##// END OF EJS Templates
merge with stable
Martin Geisler -
r12968:609edbc7 merge default
parent child Browse files
Show More
@@ -0,0 +1,154 b''
1 $ cat > nlinks.py <<EOF
2 > import os, sys
3 > for f in sorted(sys.stdin.readlines()):
4 > f = f[:-1]
5 > print os.lstat(f).st_nlink, f
6 > EOF
7
8 $ nlinksdir()
9 > {
10 > find $1 -type f | python $TESTTMP/nlinks.py
11 > }
12
13 Prepare repo r1:
14
15 $ mkdir r1
16 $ cd r1
17 $ hg init
18
19 $ echo c1 > f1
20 $ hg add f1
21 $ hg ci -m0
22
23 $ mkdir d1
24 $ cd d1
25 $ echo c2 > f2
26 $ hg add f2
27 $ hg ci -m1
28 $ cd ../..
29
30 $ nlinksdir r1/.hg/store
31 1 r1/.hg/store/00changelog.i
32 1 r1/.hg/store/00manifest.i
33 1 r1/.hg/store/data/d1/f2.i
34 1 r1/.hg/store/data/f1.i
35 1 r1/.hg/store/fncache
36 1 r1/.hg/store/undo
37
38
39 Create hardlinked clone r2:
40
41 $ hg clone -U --debug r1 r2
42 linked 7 files
43
44 Create non-hardlinked clone r3:
45
46 $ hg clone --pull r1 r3
47 requesting all changes
48 adding changesets
49 adding manifests
50 adding file changes
51 added 2 changesets with 2 changes to 2 files
52 updating to branch default
53 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
54
55
56 Repos r1 and r2 should now contain hardlinked files:
57
58 $ nlinksdir r1/.hg/store
59 2 r1/.hg/store/00changelog.i
60 2 r1/.hg/store/00manifest.i
61 2 r1/.hg/store/data/d1/f2.i
62 2 r1/.hg/store/data/f1.i
63 2 r1/.hg/store/fncache
64 1 r1/.hg/store/undo
65
66 $ nlinksdir r2/.hg/store
67 2 r2/.hg/store/00changelog.i
68 2 r2/.hg/store/00manifest.i
69 2 r2/.hg/store/data/d1/f2.i
70 2 r2/.hg/store/data/f1.i
71 2 r2/.hg/store/fncache
72
73 Repo r3 should not be hardlinked:
74
75 $ nlinksdir r3/.hg/store
76 1 r3/.hg/store/00changelog.i
77 1 r3/.hg/store/00manifest.i
78 1 r3/.hg/store/data/d1/f2.i
79 1 r3/.hg/store/data/f1.i
80 1 r3/.hg/store/fncache
81 1 r3/.hg/store/undo
82
83
84 Create a non-inlined filelog in r3:
85
86 $ cd r3/d1
87 $ python -c 'for x in range(10000): print x' >> data1
88 $ for j in 0 1 2 3 4 5 6 7 8 9; do
89 > cat data1 >> f2
90 > hg commit -m$j
91 > done
92 $ cd ../..
93
94 $ nlinksdir r3/.hg/store
95 1 r3/.hg/store/00changelog.i
96 1 r3/.hg/store/00manifest.i
97 1 r3/.hg/store/data/d1/f2.d
98 1 r3/.hg/store/data/d1/f2.i
99 1 r3/.hg/store/data/f1.i
100 1 r3/.hg/store/fncache
101 1 r3/.hg/store/undo
102
103 Push to repo r1 should break up most hardlinks in r2:
104
105 $ hg -R r2 verify
106 checking changesets
107 checking manifests
108 crosschecking files in changesets and manifests
109 checking files
110 2 files, 2 changesets, 2 total revisions
111
112 $ cd r3
113 $ hg push
114 pushing to $TESTTMP/r1
115 searching for changes
116 adding changesets
117 adding manifests
118 adding file changes
119 added 10 changesets with 10 changes to 1 files
120
121 $ cd ..
122
123 $ nlinksdir r2/.hg/store
124 1 r2/.hg/store/00changelog.i
125 1 r2/.hg/store/00manifest.i
126 1 r2/.hg/store/data/d1/f2.i
127 2 r2/.hg/store/data/f1.i
128 1 r2/.hg/store/fncache
129
130 $ hg -R r2 verify
131 checking changesets
132 checking manifests
133 crosschecking files in changesets and manifests
134 checking files
135 2 files, 2 changesets, 2 total revisions
136
137
138 $ cd r1
139 $ hg up
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
141
142 Committing a change to f1 in r1 must break up hardlink f1.i in r2:
143
144 $ echo c1c1 >> f1
145 $ hg ci -m00
146 $ cd ..
147
148 $ nlinksdir r2/.hg/store
149 1 r2/.hg/store/00changelog.i
150 1 r2/.hg/store/00manifest.i
151 1 r2/.hg/store/data/d1/f2.i
152 1 r2/.hg/store/data/f1.i
153 1 r2/.hg/store/fncache
154
@@ -1,288 +1,288 b''
1 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
1 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 '''commands to sign and verify changesets'''
6 '''commands to sign and verify changesets'''
7
7
8 import os, tempfile, binascii
8 import os, tempfile, binascii
9 from mercurial import util, commands, match
9 from mercurial import util, commands, match
10 from mercurial import node as hgnode
10 from mercurial import node as hgnode
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12
12
13 class gpg(object):
13 class gpg(object):
14 def __init__(self, path, key=None):
14 def __init__(self, path, key=None):
15 self.path = path
15 self.path = path
16 self.key = (key and " --local-user \"%s\"" % key) or ""
16 self.key = (key and " --local-user \"%s\"" % key) or ""
17
17
18 def sign(self, data):
18 def sign(self, data):
19 gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key)
19 gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key)
20 return util.filter(data, gpgcmd)
20 return util.filter(data, gpgcmd)
21
21
22 def verify(self, data, sig):
22 def verify(self, data, sig):
23 """ returns of the good and bad signatures"""
23 """ returns of the good and bad signatures"""
24 sigfile = datafile = None
24 sigfile = datafile = None
25 try:
25 try:
26 # create temporary files
26 # create temporary files
27 fd, sigfile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".sig")
27 fd, sigfile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".sig")
28 fp = os.fdopen(fd, 'wb')
28 fp = os.fdopen(fd, 'wb')
29 fp.write(sig)
29 fp.write(sig)
30 fp.close()
30 fp.close()
31 fd, datafile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".txt")
31 fd, datafile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".txt")
32 fp = os.fdopen(fd, 'wb')
32 fp = os.fdopen(fd, 'wb')
33 fp.write(data)
33 fp.write(data)
34 fp.close()
34 fp.close()
35 gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify "
35 gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify "
36 "\"%s\" \"%s\"" % (self.path, sigfile, datafile))
36 "\"%s\" \"%s\"" % (self.path, sigfile, datafile))
37 ret = util.filter("", gpgcmd)
37 ret = util.filter("", gpgcmd)
38 finally:
38 finally:
39 for f in (sigfile, datafile):
39 for f in (sigfile, datafile):
40 try:
40 try:
41 if f:
41 if f:
42 os.unlink(f)
42 os.unlink(f)
43 except:
43 except:
44 pass
44 pass
45 keys = []
45 keys = []
46 key, fingerprint = None, None
46 key, fingerprint = None, None
47 err = ""
47 err = ""
48 for l in ret.splitlines():
48 for l in ret.splitlines():
49 # see DETAILS in the gnupg documentation
49 # see DETAILS in the gnupg documentation
50 # filter the logger output
50 # filter the logger output
51 if not l.startswith("[GNUPG:]"):
51 if not l.startswith("[GNUPG:]"):
52 continue
52 continue
53 l = l[9:]
53 l = l[9:]
54 if l.startswith("ERRSIG"):
54 if l.startswith("ERRSIG"):
55 err = _("error while verifying signature")
55 err = _("error while verifying signature")
56 break
56 break
57 elif l.startswith("VALIDSIG"):
57 elif l.startswith("VALIDSIG"):
58 # fingerprint of the primary key
58 # fingerprint of the primary key
59 fingerprint = l.split()[10]
59 fingerprint = l.split()[10]
60 elif (l.startswith("GOODSIG") or
60 elif (l.startswith("GOODSIG") or
61 l.startswith("EXPSIG") or
61 l.startswith("EXPSIG") or
62 l.startswith("EXPKEYSIG") or
62 l.startswith("EXPKEYSIG") or
63 l.startswith("BADSIG")):
63 l.startswith("BADSIG")):
64 if key is not None:
64 if key is not None:
65 keys.append(key + [fingerprint])
65 keys.append(key + [fingerprint])
66 key = l.split(" ", 2)
66 key = l.split(" ", 2)
67 fingerprint = None
67 fingerprint = None
68 if err:
68 if err:
69 return err, []
69 return err, []
70 if key is not None:
70 if key is not None:
71 keys.append(key + [fingerprint])
71 keys.append(key + [fingerprint])
72 return err, keys
72 return err, keys
73
73
74 def newgpg(ui, **opts):
74 def newgpg(ui, **opts):
75 """create a new gpg instance"""
75 """create a new gpg instance"""
76 gpgpath = ui.config("gpg", "cmd", "gpg")
76 gpgpath = ui.config("gpg", "cmd", "gpg")
77 gpgkey = opts.get('key')
77 gpgkey = opts.get('key')
78 if not gpgkey:
78 if not gpgkey:
79 gpgkey = ui.config("gpg", "key", None)
79 gpgkey = ui.config("gpg", "key", None)
80 return gpg(gpgpath, gpgkey)
80 return gpg(gpgpath, gpgkey)
81
81
82 def sigwalk(repo):
82 def sigwalk(repo):
83 """
83 """
84 walk over every sigs, yields a couple
84 walk over every sigs, yields a couple
85 ((node, version, sig), (filename, linenumber))
85 ((node, version, sig), (filename, linenumber))
86 """
86 """
87 def parsefile(fileiter, context):
87 def parsefile(fileiter, context):
88 ln = 1
88 ln = 1
89 for l in fileiter:
89 for l in fileiter:
90 if not l:
90 if not l:
91 continue
91 continue
92 yield (l.split(" ", 2), (context, ln))
92 yield (l.split(" ", 2), (context, ln))
93 ln += 1
93 ln += 1
94
94
95 # read the heads
95 # read the heads
96 fl = repo.file(".hgsigs")
96 fl = repo.file(".hgsigs")
97 for r in reversed(fl.heads()):
97 for r in reversed(fl.heads()):
98 fn = ".hgsigs|%s" % hgnode.short(r)
98 fn = ".hgsigs|%s" % hgnode.short(r)
99 for item in parsefile(fl.read(r).splitlines(), fn):
99 for item in parsefile(fl.read(r).splitlines(), fn):
100 yield item
100 yield item
101 try:
101 try:
102 # read local signatures
102 # read local signatures
103 fn = "localsigs"
103 fn = "localsigs"
104 for item in parsefile(repo.opener(fn), fn):
104 for item in parsefile(repo.opener(fn), fn):
105 yield item
105 yield item
106 except IOError:
106 except IOError:
107 pass
107 pass
108
108
109 def getkeys(ui, repo, mygpg, sigdata, context):
109 def getkeys(ui, repo, mygpg, sigdata, context):
110 """get the keys who signed a data"""
110 """get the keys who signed a data"""
111 fn, ln = context
111 fn, ln = context
112 node, version, sig = sigdata
112 node, version, sig = sigdata
113 prefix = "%s:%d" % (fn, ln)
113 prefix = "%s:%d" % (fn, ln)
114 node = hgnode.bin(node)
114 node = hgnode.bin(node)
115
115
116 data = node2txt(repo, node, version)
116 data = node2txt(repo, node, version)
117 sig = binascii.a2b_base64(sig)
117 sig = binascii.a2b_base64(sig)
118 err, keys = mygpg.verify(data, sig)
118 err, keys = mygpg.verify(data, sig)
119 if err:
119 if err:
120 ui.warn("%s:%d %s\n" % (fn, ln , err))
120 ui.warn("%s:%d %s\n" % (fn, ln , err))
121 return None
121 return None
122
122
123 validkeys = []
123 validkeys = []
124 # warn for expired key and/or sigs
124 # warn for expired key and/or sigs
125 for key in keys:
125 for key in keys:
126 if key[0] == "BADSIG":
126 if key[0] == "BADSIG":
127 ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2]))
127 ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2]))
128 continue
128 continue
129 if key[0] == "EXPSIG":
129 if key[0] == "EXPSIG":
130 ui.write(_("%s Note: Signature has expired"
130 ui.write(_("%s Note: Signature has expired"
131 " (signed by: \"%s\")\n") % (prefix, key[2]))
131 " (signed by: \"%s\")\n") % (prefix, key[2]))
132 elif key[0] == "EXPKEYSIG":
132 elif key[0] == "EXPKEYSIG":
133 ui.write(_("%s Note: This key has expired"
133 ui.write(_("%s Note: This key has expired"
134 " (signed by: \"%s\")\n") % (prefix, key[2]))
134 " (signed by: \"%s\")\n") % (prefix, key[2]))
135 validkeys.append((key[1], key[2], key[3]))
135 validkeys.append((key[1], key[2], key[3]))
136 return validkeys
136 return validkeys
137
137
138 def sigs(ui, repo):
138 def sigs(ui, repo):
139 """list signed changesets"""
139 """list signed changesets"""
140 mygpg = newgpg(ui)
140 mygpg = newgpg(ui)
141 revs = {}
141 revs = {}
142
142
143 for data, context in sigwalk(repo):
143 for data, context in sigwalk(repo):
144 node, version, sig = data
144 node, version, sig = data
145 fn, ln = context
145 fn, ln = context
146 try:
146 try:
147 n = repo.lookup(node)
147 n = repo.lookup(node)
148 except KeyError:
148 except KeyError:
149 ui.warn(_("%s:%d node does not exist\n") % (fn, ln))
149 ui.warn(_("%s:%d node does not exist\n") % (fn, ln))
150 continue
150 continue
151 r = repo.changelog.rev(n)
151 r = repo.changelog.rev(n)
152 keys = getkeys(ui, repo, mygpg, data, context)
152 keys = getkeys(ui, repo, mygpg, data, context)
153 if not keys:
153 if not keys:
154 continue
154 continue
155 revs.setdefault(r, [])
155 revs.setdefault(r, [])
156 revs[r].extend(keys)
156 revs[r].extend(keys)
157 for rev in sorted(revs, reverse=True):
157 for rev in sorted(revs, reverse=True):
158 for k in revs[rev]:
158 for k in revs[rev]:
159 r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev)))
159 r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev)))
160 ui.write("%-30s %s\n" % (keystr(ui, k), r))
160 ui.write("%-30s %s\n" % (keystr(ui, k), r))
161
161
162 def check(ui, repo, rev):
162 def check(ui, repo, rev):
163 """verify all the signatures there may be for a particular revision"""
163 """verify all the signatures there may be for a particular revision"""
164 mygpg = newgpg(ui)
164 mygpg = newgpg(ui)
165 rev = repo.lookup(rev)
165 rev = repo.lookup(rev)
166 hexrev = hgnode.hex(rev)
166 hexrev = hgnode.hex(rev)
167 keys = []
167 keys = []
168
168
169 for data, context in sigwalk(repo):
169 for data, context in sigwalk(repo):
170 node, version, sig = data
170 node, version, sig = data
171 if node == hexrev:
171 if node == hexrev:
172 k = getkeys(ui, repo, mygpg, data, context)
172 k = getkeys(ui, repo, mygpg, data, context)
173 if k:
173 if k:
174 keys.extend(k)
174 keys.extend(k)
175
175
176 if not keys:
176 if not keys:
177 ui.write(_("No valid signature for %s\n") % hgnode.short(rev))
177 ui.write(_("No valid signature for %s\n") % hgnode.short(rev))
178 return
178 return
179
179
180 # print summary
180 # print summary
181 ui.write("%s is signed by:\n" % hgnode.short(rev))
181 ui.write("%s is signed by:\n" % hgnode.short(rev))
182 for key in keys:
182 for key in keys:
183 ui.write(" %s\n" % keystr(ui, key))
183 ui.write(" %s\n" % keystr(ui, key))
184
184
185 def keystr(ui, key):
185 def keystr(ui, key):
186 """associate a string to a key (username, comment)"""
186 """associate a string to a key (username, comment)"""
187 keyid, user, fingerprint = key
187 keyid, user, fingerprint = key
188 comment = ui.config("gpg", fingerprint, None)
188 comment = ui.config("gpg", fingerprint, None)
189 if comment:
189 if comment:
190 return "%s (%s)" % (user, comment)
190 return "%s (%s)" % (user, comment)
191 else:
191 else:
192 return user
192 return user
193
193
194 def sign(ui, repo, *revs, **opts):
194 def sign(ui, repo, *revs, **opts):
195 """add a signature for the current or given revision
195 """add a signature for the current or given revision
196
196
197 If no revision is given, the parent of the working directory is used,
197 If no revision is given, the parent of the working directory is used,
198 or tip if no revision is checked out.
198 or tip if no revision is checked out.
199
199
200 See :hg:`help dates` for a list of formats valid for -d/--date.
200 See :hg:`help dates` for a list of formats valid for -d/--date.
201 """
201 """
202
202
203 mygpg = newgpg(ui, **opts)
203 mygpg = newgpg(ui, **opts)
204 sigver = "0"
204 sigver = "0"
205 sigmessage = ""
205 sigmessage = ""
206
206
207 date = opts.get('date')
207 date = opts.get('date')
208 if date:
208 if date:
209 opts['date'] = util.parsedate(date)
209 opts['date'] = util.parsedate(date)
210
210
211 if revs:
211 if revs:
212 nodes = [repo.lookup(n) for n in revs]
212 nodes = [repo.lookup(n) for n in revs]
213 else:
213 else:
214 nodes = [node for node in repo.dirstate.parents()
214 nodes = [node for node in repo.dirstate.parents()
215 if node != hgnode.nullid]
215 if node != hgnode.nullid]
216 if len(nodes) > 1:
216 if len(nodes) > 1:
217 raise util.Abort(_('uncommitted merge - please provide a '
217 raise util.Abort(_('uncommitted merge - please provide a '
218 'specific revision'))
218 'specific revision'))
219 if not nodes:
219 if not nodes:
220 nodes = [repo.changelog.tip()]
220 nodes = [repo.changelog.tip()]
221
221
222 for n in nodes:
222 for n in nodes:
223 hexnode = hgnode.hex(n)
223 hexnode = hgnode.hex(n)
224 ui.write(_("Signing %d:%s\n") % (repo.changelog.rev(n),
224 ui.write(_("Signing %d:%s\n") % (repo.changelog.rev(n),
225 hgnode.short(n)))
225 hgnode.short(n)))
226 # build data
226 # build data
227 data = node2txt(repo, n, sigver)
227 data = node2txt(repo, n, sigver)
228 sig = mygpg.sign(data)
228 sig = mygpg.sign(data)
229 if not sig:
229 if not sig:
230 raise util.abort(_("error while signing"))
230 raise util.Abort(_("error while signing"))
231 sig = binascii.b2a_base64(sig)
231 sig = binascii.b2a_base64(sig)
232 sig = sig.replace("\n", "")
232 sig = sig.replace("\n", "")
233 sigmessage += "%s %s %s\n" % (hexnode, sigver, sig)
233 sigmessage += "%s %s %s\n" % (hexnode, sigver, sig)
234
234
235 # write it
235 # write it
236 if opts['local']:
236 if opts['local']:
237 repo.opener("localsigs", "ab").write(sigmessage)
237 repo.opener("localsigs", "ab").write(sigmessage)
238 return
238 return
239
239
240 msigs = match.exact(repo.root, '', ['.hgsigs'])
240 msigs = match.exact(repo.root, '', ['.hgsigs'])
241 s = repo.status(match=msigs, unknown=True, ignored=True)[:6]
241 s = repo.status(match=msigs, unknown=True, ignored=True)[:6]
242 if util.any(s) and not opts["force"]:
242 if util.any(s) and not opts["force"]:
243 raise util.Abort(_("working copy of .hgsigs is changed "
243 raise util.Abort(_("working copy of .hgsigs is changed "
244 "(please commit .hgsigs manually "
244 "(please commit .hgsigs manually "
245 "or use --force)"))
245 "or use --force)"))
246
246
247 repo.wfile(".hgsigs", "ab").write(sigmessage)
247 repo.wfile(".hgsigs", "ab").write(sigmessage)
248
248
249 if '.hgsigs' not in repo.dirstate:
249 if '.hgsigs' not in repo.dirstate:
250 repo[None].add([".hgsigs"])
250 repo[None].add([".hgsigs"])
251
251
252 if opts["no_commit"]:
252 if opts["no_commit"]:
253 return
253 return
254
254
255 message = opts['message']
255 message = opts['message']
256 if not message:
256 if not message:
257 # we don't translate commit messages
257 # we don't translate commit messages
258 message = "\n".join(["Added signature for changeset %s"
258 message = "\n".join(["Added signature for changeset %s"
259 % hgnode.short(n)
259 % hgnode.short(n)
260 for n in nodes])
260 for n in nodes])
261 try:
261 try:
262 repo.commit(message, opts['user'], opts['date'], match=msigs)
262 repo.commit(message, opts['user'], opts['date'], match=msigs)
263 except ValueError, inst:
263 except ValueError, inst:
264 raise util.Abort(str(inst))
264 raise util.Abort(str(inst))
265
265
266 def node2txt(repo, node, ver):
266 def node2txt(repo, node, ver):
267 """map a manifest into some text"""
267 """map a manifest into some text"""
268 if ver == "0":
268 if ver == "0":
269 return "%s\n" % hgnode.hex(node)
269 return "%s\n" % hgnode.hex(node)
270 else:
270 else:
271 raise util.Abort(_("unknown signature version"))
271 raise util.Abort(_("unknown signature version"))
272
272
273 cmdtable = {
273 cmdtable = {
274 "sign":
274 "sign":
275 (sign,
275 (sign,
276 [('l', 'local', None, _('make the signature local')),
276 [('l', 'local', None, _('make the signature local')),
277 ('f', 'force', None, _('sign even if the sigfile is modified')),
277 ('f', 'force', None, _('sign even if the sigfile is modified')),
278 ('', 'no-commit', None, _('do not commit the sigfile after signing')),
278 ('', 'no-commit', None, _('do not commit the sigfile after signing')),
279 ('k', 'key', '',
279 ('k', 'key', '',
280 _('the key id to sign with'), _('ID')),
280 _('the key id to sign with'), _('ID')),
281 ('m', 'message', '',
281 ('m', 'message', '',
282 _('commit message'), _('TEXT')),
282 _('commit message'), _('TEXT')),
283 ] + commands.commitopts2,
283 ] + commands.commitopts2,
284 _('hg sign [OPTION]... [REVISION]...')),
284 _('hg sign [OPTION]... [REVISION]...')),
285 "sigcheck": (check, [], _('hg sigcheck REVISION')),
285 "sigcheck": (check, [], _('hg sigcheck REVISION')),
286 "sigs": (sigs, [], _('hg sigs')),
286 "sigs": (sigs, [], _('hg sigs')),
287 }
287 }
288
288
@@ -1,4526 +1,4526 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error
12 import hg, util, revlog, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 .hgignore. As with add, these changes take effect at the next
61 .hgignore. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 ctx = cmdutil.revsingle(repo, opts.get('rev'))
129 ctx = cmdutil.revsingle(repo, opts.get('rev'))
130 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
131 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
132 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
133 fctx = ctx[abs]
133 fctx = ctx[abs]
134 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
136 continue
136 continue
137
137
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
139 pieces = []
139 pieces = []
140
140
141 for f in funcmap:
141 for f in funcmap:
142 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
143 if l:
143 if l:
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
145 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
147
147
148 if pieces:
148 if pieces:
149 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
151
151
152 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
153 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
154
154
155 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
156 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
157
157
158 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
159 extension (or override using -t/--type).
159 extension (or override using -t/--type).
160
160
161 Valid types are:
161 Valid types are:
162
162
163 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
164 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
166 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
167 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
168 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
169
169
170 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
171 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
172
172
173 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
174 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
175 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
176 removed.
176 removed.
177
177
178 Returns 0 on success.
178 Returns 0 on success.
179 '''
179 '''
180
180
181 ctx = cmdutil.revsingle(repo, opts.get('rev'))
181 ctx = cmdutil.revsingle(repo, opts.get('rev'))
182 if not ctx:
182 if not ctx:
183 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
184 node = ctx.node()
184 node = ctx.node()
185 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
186 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
187 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
188
188
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
190 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
191
191
192 if dest == '-':
192 if dest == '-':
193 if kind == 'files':
193 if kind == 'files':
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
195 dest = sys.stdout
195 dest = sys.stdout
196 if not prefix:
196 if not prefix:
197 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
198
198
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
200 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
202 matchfn, prefix, subrepos=opts.get('subrepos'))
202 matchfn, prefix, subrepos=opts.get('subrepos'))
203
203
204 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
205 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
206
206
207 The backout command merges the reverse effect of the reverted
207 The backout command merges the reverse effect of the reverted
208 changeset into the working directory.
208 changeset into the working directory.
209
209
210 With the --merge option, it first commits the reverted changes
210 With the --merge option, it first commits the reverted changes
211 as a new changeset. This new changeset is a child of the reverted
211 as a new changeset. This new changeset is a child of the reverted
212 changeset.
212 changeset.
213 The --merge option remembers the parent of the working directory
213 The --merge option remembers the parent of the working directory
214 before starting the backout, then merges the new head with that
214 before starting the backout, then merges the new head with that
215 changeset afterwards.
215 changeset afterwards.
216 This will result in an explicit merge in the history.
216 This will result in an explicit merge in the history.
217
217
218 If you backout a changeset other than the original parent of the
218 If you backout a changeset other than the original parent of the
219 working directory, the result of this merge is not committed,
219 working directory, the result of this merge is not committed,
220 as with a normal merge. Otherwise, no merge is needed and the
220 as with a normal merge. Otherwise, no merge is needed and the
221 commit is automatic.
221 commit is automatic.
222
222
223 Note that the default behavior (without --merge) has changed in
223 Note that the default behavior (without --merge) has changed in
224 version 1.7. To restore the previous default behavior, use
224 version 1.7. To restore the previous default behavior, use
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
226 the ongoing merge.
226 the ongoing merge.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = cmdutil.revsingle(repo, rev).node()
246 node = cmdutil.revsingle(repo, rev).node()
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
285 ui.setconfig('ui', 'forcemerge', '')
286
286
287 commit_opts = opts.copy()
287 commit_opts = opts.copy()
288 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
289 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
290 # we don't translate commit messages
290 # we don't translate commit messages
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
293 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
294 def nice(node):
294 def nice(node):
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
297 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
298 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
299 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
300 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
301 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
306 ui.setconfig('ui', 'forcemerge', '')
307 return 0
307 return 0
308
308
309 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
310 reset=None, good=None, bad=None, skip=None, noupdate=None):
310 reset=None, good=None, bad=None, skip=None, noupdate=None):
311 """subdivision search of changesets
311 """subdivision search of changesets
312
312
313 This command helps to find changesets which introduce problems. To
313 This command helps to find changesets which introduce problems. To
314 use, mark the earliest changeset you know exhibits the problem as
314 use, mark the earliest changeset you know exhibits the problem as
315 bad, then mark the latest changeset which is free from the problem
315 bad, then mark the latest changeset which is free from the problem
316 as good. Bisect will update your working directory to a revision
316 as good. Bisect will update your working directory to a revision
317 for testing (unless the -U/--noupdate option is specified). Once
317 for testing (unless the -U/--noupdate option is specified). Once
318 you have performed tests, mark the working directory as good or
318 you have performed tests, mark the working directory as good or
319 bad, and bisect will either update to another candidate changeset
319 bad, and bisect will either update to another candidate changeset
320 or announce that it has found the bad revision.
320 or announce that it has found the bad revision.
321
321
322 As a shortcut, you can also use the revision argument to mark a
322 As a shortcut, you can also use the revision argument to mark a
323 revision as good or bad without checking it out first.
323 revision as good or bad without checking it out first.
324
324
325 If you supply a command, it will be used for automatic bisection.
325 If you supply a command, it will be used for automatic bisection.
326 Its exit status will be used to mark revisions as good or bad:
326 Its exit status will be used to mark revisions as good or bad:
327 status 0 means good, 125 means to skip the revision, 127
327 status 0 means good, 125 means to skip the revision, 127
328 (command not found) will abort the bisection, and any other
328 (command not found) will abort the bisection, and any other
329 non-zero exit status means the revision is bad.
329 non-zero exit status means the revision is bad.
330
330
331 Returns 0 on success.
331 Returns 0 on success.
332 """
332 """
333 def print_result(nodes, good):
333 def print_result(nodes, good):
334 displayer = cmdutil.show_changeset(ui, repo, {})
334 displayer = cmdutil.show_changeset(ui, repo, {})
335 if len(nodes) == 1:
335 if len(nodes) == 1:
336 # narrowed it down to a single revision
336 # narrowed it down to a single revision
337 if good:
337 if good:
338 ui.write(_("The first good revision is:\n"))
338 ui.write(_("The first good revision is:\n"))
339 else:
339 else:
340 ui.write(_("The first bad revision is:\n"))
340 ui.write(_("The first bad revision is:\n"))
341 displayer.show(repo[nodes[0]])
341 displayer.show(repo[nodes[0]])
342 parents = repo[nodes[0]].parents()
342 parents = repo[nodes[0]].parents()
343 if len(parents) > 1:
343 if len(parents) > 1:
344 side = good and state['bad'] or state['good']
344 side = good and state['bad'] or state['good']
345 num = len(set(i.node() for i in parents) & set(side))
345 num = len(set(i.node() for i in parents) & set(side))
346 if num == 1:
346 if num == 1:
347 common = parents[0].ancestor(parents[1])
347 common = parents[0].ancestor(parents[1])
348 ui.write(_('Not all ancestors of this changeset have been'
348 ui.write(_('Not all ancestors of this changeset have been'
349 ' checked.\nTo check the other ancestors, start'
349 ' checked.\nTo check the other ancestors, start'
350 ' from the common ancestor, %s.\n' % common))
350 ' from the common ancestor, %s.\n' % common))
351 else:
351 else:
352 # multiple possible revisions
352 # multiple possible revisions
353 if good:
353 if good:
354 ui.write(_("Due to skipped revisions, the first "
354 ui.write(_("Due to skipped revisions, the first "
355 "good revision could be any of:\n"))
355 "good revision could be any of:\n"))
356 else:
356 else:
357 ui.write(_("Due to skipped revisions, the first "
357 ui.write(_("Due to skipped revisions, the first "
358 "bad revision could be any of:\n"))
358 "bad revision could be any of:\n"))
359 for n in nodes:
359 for n in nodes:
360 displayer.show(repo[n])
360 displayer.show(repo[n])
361 displayer.close()
361 displayer.close()
362
362
363 def check_state(state, interactive=True):
363 def check_state(state, interactive=True):
364 if not state['good'] or not state['bad']:
364 if not state['good'] or not state['bad']:
365 if (good or bad or skip or reset) and interactive:
365 if (good or bad or skip or reset) and interactive:
366 return
366 return
367 if not state['good']:
367 if not state['good']:
368 raise util.Abort(_('cannot bisect (no known good revisions)'))
368 raise util.Abort(_('cannot bisect (no known good revisions)'))
369 else:
369 else:
370 raise util.Abort(_('cannot bisect (no known bad revisions)'))
370 raise util.Abort(_('cannot bisect (no known bad revisions)'))
371 return True
371 return True
372
372
373 # backward compatibility
373 # backward compatibility
374 if rev in "good bad reset init".split():
374 if rev in "good bad reset init".split():
375 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
375 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
376 cmd, rev, extra = rev, extra, None
376 cmd, rev, extra = rev, extra, None
377 if cmd == "good":
377 if cmd == "good":
378 good = True
378 good = True
379 elif cmd == "bad":
379 elif cmd == "bad":
380 bad = True
380 bad = True
381 else:
381 else:
382 reset = True
382 reset = True
383 elif extra or good + bad + skip + reset + bool(command) > 1:
383 elif extra or good + bad + skip + reset + bool(command) > 1:
384 raise util.Abort(_('incompatible arguments'))
384 raise util.Abort(_('incompatible arguments'))
385
385
386 if reset:
386 if reset:
387 p = repo.join("bisect.state")
387 p = repo.join("bisect.state")
388 if os.path.exists(p):
388 if os.path.exists(p):
389 os.unlink(p)
389 os.unlink(p)
390 return
390 return
391
391
392 state = hbisect.load_state(repo)
392 state = hbisect.load_state(repo)
393
393
394 if command:
394 if command:
395 changesets = 1
395 changesets = 1
396 try:
396 try:
397 while changesets:
397 while changesets:
398 # update state
398 # update state
399 status = util.system(command)
399 status = util.system(command)
400 if status == 125:
400 if status == 125:
401 transition = "skip"
401 transition = "skip"
402 elif status == 0:
402 elif status == 0:
403 transition = "good"
403 transition = "good"
404 # status < 0 means process was killed
404 # status < 0 means process was killed
405 elif status == 127:
405 elif status == 127:
406 raise util.Abort(_("failed to execute %s") % command)
406 raise util.Abort(_("failed to execute %s") % command)
407 elif status < 0:
407 elif status < 0:
408 raise util.Abort(_("%s killed") % command)
408 raise util.Abort(_("%s killed") % command)
409 else:
409 else:
410 transition = "bad"
410 transition = "bad"
411 ctx = cmdutil.revsingle(repo, rev)
411 ctx = cmdutil.revsingle(repo, rev)
412 rev = None # clear for future iterations
412 rev = None # clear for future iterations
413 state[transition].append(ctx.node())
413 state[transition].append(ctx.node())
414 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
414 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
415 check_state(state, interactive=False)
415 check_state(state, interactive=False)
416 # bisect
416 # bisect
417 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
417 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
418 # update to next check
418 # update to next check
419 cmdutil.bail_if_changed(repo)
419 cmdutil.bail_if_changed(repo)
420 hg.clean(repo, nodes[0], show_stats=False)
420 hg.clean(repo, nodes[0], show_stats=False)
421 finally:
421 finally:
422 hbisect.save_state(repo, state)
422 hbisect.save_state(repo, state)
423 print_result(nodes, good)
423 print_result(nodes, good)
424 return
424 return
425
425
426 # update state
426 # update state
427
427
428 if rev:
428 if rev:
429 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
429 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
430 else:
430 else:
431 nodes = [repo.lookup('.')]
431 nodes = [repo.lookup('.')]
432
432
433 if good or bad or skip:
433 if good or bad or skip:
434 if good:
434 if good:
435 state['good'] += nodes
435 state['good'] += nodes
436 elif bad:
436 elif bad:
437 state['bad'] += nodes
437 state['bad'] += nodes
438 elif skip:
438 elif skip:
439 state['skip'] += nodes
439 state['skip'] += nodes
440 hbisect.save_state(repo, state)
440 hbisect.save_state(repo, state)
441
441
442 if not check_state(state):
442 if not check_state(state):
443 return
443 return
444
444
445 # actually bisect
445 # actually bisect
446 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
446 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
447 if changesets == 0:
447 if changesets == 0:
448 print_result(nodes, good)
448 print_result(nodes, good)
449 else:
449 else:
450 assert len(nodes) == 1 # only a single node can be tested next
450 assert len(nodes) == 1 # only a single node can be tested next
451 node = nodes[0]
451 node = nodes[0]
452 # compute the approximate number of remaining tests
452 # compute the approximate number of remaining tests
453 tests, size = 0, 2
453 tests, size = 0, 2
454 while size <= changesets:
454 while size <= changesets:
455 tests, size = tests + 1, size * 2
455 tests, size = tests + 1, size * 2
456 rev = repo.changelog.rev(node)
456 rev = repo.changelog.rev(node)
457 ui.write(_("Testing changeset %d:%s "
457 ui.write(_("Testing changeset %d:%s "
458 "(%d changesets remaining, ~%d tests)\n")
458 "(%d changesets remaining, ~%d tests)\n")
459 % (rev, short(node), changesets, tests))
459 % (rev, short(node), changesets, tests))
460 if not noupdate:
460 if not noupdate:
461 cmdutil.bail_if_changed(repo)
461 cmdutil.bail_if_changed(repo)
462 return hg.clean(repo, node)
462 return hg.clean(repo, node)
463
463
464 def branch(ui, repo, label=None, **opts):
464 def branch(ui, repo, label=None, **opts):
465 """set or show the current branch name
465 """set or show the current branch name
466
466
467 With no argument, show the current branch name. With one argument,
467 With no argument, show the current branch name. With one argument,
468 set the working directory branch name (the branch will not exist
468 set the working directory branch name (the branch will not exist
469 in the repository until the next commit). Standard practice
469 in the repository until the next commit). Standard practice
470 recommends that primary development take place on the 'default'
470 recommends that primary development take place on the 'default'
471 branch.
471 branch.
472
472
473 Unless -f/--force is specified, branch will not let you set a
473 Unless -f/--force is specified, branch will not let you set a
474 branch name that already exists, even if it's inactive.
474 branch name that already exists, even if it's inactive.
475
475
476 Use -C/--clean to reset the working directory branch to that of
476 Use -C/--clean to reset the working directory branch to that of
477 the parent of the working directory, negating a previous branch
477 the parent of the working directory, negating a previous branch
478 change.
478 change.
479
479
480 Use the command :hg:`update` to switch to an existing branch. Use
480 Use the command :hg:`update` to switch to an existing branch. Use
481 :hg:`commit --close-branch` to mark this branch as closed.
481 :hg:`commit --close-branch` to mark this branch as closed.
482
482
483 Returns 0 on success.
483 Returns 0 on success.
484 """
484 """
485
485
486 if opts.get('clean'):
486 if opts.get('clean'):
487 label = repo[None].parents()[0].branch()
487 label = repo[None].parents()[0].branch()
488 repo.dirstate.setbranch(label)
488 repo.dirstate.setbranch(label)
489 ui.status(_('reset working directory to branch %s\n') % label)
489 ui.status(_('reset working directory to branch %s\n') % label)
490 elif label:
490 elif label:
491 utflabel = encoding.fromlocal(label)
491 utflabel = encoding.fromlocal(label)
492 if not opts.get('force') and utflabel in repo.branchtags():
492 if not opts.get('force') and utflabel in repo.branchtags():
493 if label not in [p.branch() for p in repo.parents()]:
493 if label not in [p.branch() for p in repo.parents()]:
494 raise util.Abort(_('a branch of the same name already exists'
494 raise util.Abort(_('a branch of the same name already exists'
495 " (use 'hg update' to switch to it)"))
495 " (use 'hg update' to switch to it)"))
496 repo.dirstate.setbranch(utflabel)
496 repo.dirstate.setbranch(utflabel)
497 ui.status(_('marked working directory as branch %s\n') % label)
497 ui.status(_('marked working directory as branch %s\n') % label)
498 else:
498 else:
499 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
499 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
500
500
501 def branches(ui, repo, active=False, closed=False):
501 def branches(ui, repo, active=False, closed=False):
502 """list repository named branches
502 """list repository named branches
503
503
504 List the repository's named branches, indicating which ones are
504 List the repository's named branches, indicating which ones are
505 inactive. If -c/--closed is specified, also list branches which have
505 inactive. If -c/--closed is specified, also list branches which have
506 been marked closed (see :hg:`commit --close-branch`).
506 been marked closed (see :hg:`commit --close-branch`).
507
507
508 If -a/--active is specified, only show active branches. A branch
508 If -a/--active is specified, only show active branches. A branch
509 is considered active if it contains repository heads.
509 is considered active if it contains repository heads.
510
510
511 Use the command :hg:`update` to switch to an existing branch.
511 Use the command :hg:`update` to switch to an existing branch.
512
512
513 Returns 0.
513 Returns 0.
514 """
514 """
515
515
516 hexfunc = ui.debugflag and hex or short
516 hexfunc = ui.debugflag and hex or short
517 activebranches = [repo[n].branch() for n in repo.heads()]
517 activebranches = [repo[n].branch() for n in repo.heads()]
518 def testactive(tag, node):
518 def testactive(tag, node):
519 realhead = tag in activebranches
519 realhead = tag in activebranches
520 open = node in repo.branchheads(tag, closed=False)
520 open = node in repo.branchheads(tag, closed=False)
521 return realhead and open
521 return realhead and open
522 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
522 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
523 for tag, node in repo.branchtags().items()],
523 for tag, node in repo.branchtags().items()],
524 reverse=True)
524 reverse=True)
525
525
526 for isactive, node, tag in branches:
526 for isactive, node, tag in branches:
527 if (not active) or isactive:
527 if (not active) or isactive:
528 encodedtag = encoding.tolocal(tag)
528 encodedtag = encoding.tolocal(tag)
529 if ui.quiet:
529 if ui.quiet:
530 ui.write("%s\n" % encodedtag)
530 ui.write("%s\n" % encodedtag)
531 else:
531 else:
532 hn = repo.lookup(node)
532 hn = repo.lookup(node)
533 if isactive:
533 if isactive:
534 label = 'branches.active'
534 label = 'branches.active'
535 notice = ''
535 notice = ''
536 elif hn not in repo.branchheads(tag, closed=False):
536 elif hn not in repo.branchheads(tag, closed=False):
537 if not closed:
537 if not closed:
538 continue
538 continue
539 label = 'branches.closed'
539 label = 'branches.closed'
540 notice = _(' (closed)')
540 notice = _(' (closed)')
541 else:
541 else:
542 label = 'branches.inactive'
542 label = 'branches.inactive'
543 notice = _(' (inactive)')
543 notice = _(' (inactive)')
544 if tag == repo.dirstate.branch():
544 if tag == repo.dirstate.branch():
545 label = 'branches.current'
545 label = 'branches.current'
546 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
546 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
547 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
547 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
548 encodedtag = ui.label(encodedtag, label)
548 encodedtag = ui.label(encodedtag, label)
549 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
549 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
550
550
551 def bundle(ui, repo, fname, dest=None, **opts):
551 def bundle(ui, repo, fname, dest=None, **opts):
552 """create a changegroup file
552 """create a changegroup file
553
553
554 Generate a compressed changegroup file collecting changesets not
554 Generate a compressed changegroup file collecting changesets not
555 known to be in another repository.
555 known to be in another repository.
556
556
557 If you omit the destination repository, then hg assumes the
557 If you omit the destination repository, then hg assumes the
558 destination will have all the nodes you specify with --base
558 destination will have all the nodes you specify with --base
559 parameters. To create a bundle containing all changesets, use
559 parameters. To create a bundle containing all changesets, use
560 -a/--all (or --base null).
560 -a/--all (or --base null).
561
561
562 You can change compression method with the -t/--type option.
562 You can change compression method with the -t/--type option.
563 The available compression methods are: none, bzip2, and
563 The available compression methods are: none, bzip2, and
564 gzip (by default, bundles are compressed using bzip2).
564 gzip (by default, bundles are compressed using bzip2).
565
565
566 The bundle file can then be transferred using conventional means
566 The bundle file can then be transferred using conventional means
567 and applied to another repository with the unbundle or pull
567 and applied to another repository with the unbundle or pull
568 command. This is useful when direct push and pull are not
568 command. This is useful when direct push and pull are not
569 available or when exporting an entire repository is undesirable.
569 available or when exporting an entire repository is undesirable.
570
570
571 Applying bundles preserves all changeset contents including
571 Applying bundles preserves all changeset contents including
572 permissions, copy/rename information, and revision history.
572 permissions, copy/rename information, and revision history.
573
573
574 Returns 0 on success, 1 if no changes found.
574 Returns 0 on success, 1 if no changes found.
575 """
575 """
576 revs = None
576 revs = None
577 if 'rev' in opts:
577 if 'rev' in opts:
578 revs = cmdutil.revrange(repo, opts['rev'])
578 revs = cmdutil.revrange(repo, opts['rev'])
579
579
580 if opts.get('all'):
580 if opts.get('all'):
581 base = ['null']
581 base = ['null']
582 else:
582 else:
583 base = cmdutil.revrange(repo, opts.get('base'))
583 base = cmdutil.revrange(repo, opts.get('base'))
584 if base:
584 if base:
585 if dest:
585 if dest:
586 raise util.Abort(_("--base is incompatible with specifying "
586 raise util.Abort(_("--base is incompatible with specifying "
587 "a destination"))
587 "a destination"))
588 base = [repo.lookup(rev) for rev in base]
588 base = [repo.lookup(rev) for rev in base]
589 # create the right base
589 # create the right base
590 # XXX: nodesbetween / changegroup* should be "fixed" instead
590 # XXX: nodesbetween / changegroup* should be "fixed" instead
591 o = []
591 o = []
592 has = set((nullid,))
592 has = set((nullid,))
593 for n in base:
593 for n in base:
594 has.update(repo.changelog.reachable(n))
594 has.update(repo.changelog.reachable(n))
595 if revs:
595 if revs:
596 revs = [repo.lookup(rev) for rev in revs]
596 revs = [repo.lookup(rev) for rev in revs]
597 visit = revs[:]
597 visit = revs[:]
598 has.difference_update(visit)
598 has.difference_update(visit)
599 else:
599 else:
600 visit = repo.changelog.heads()
600 visit = repo.changelog.heads()
601 seen = {}
601 seen = {}
602 while visit:
602 while visit:
603 n = visit.pop(0)
603 n = visit.pop(0)
604 parents = [p for p in repo.changelog.parents(n) if p not in has]
604 parents = [p for p in repo.changelog.parents(n) if p not in has]
605 if len(parents) == 0:
605 if len(parents) == 0:
606 if n not in has:
606 if n not in has:
607 o.append(n)
607 o.append(n)
608 else:
608 else:
609 for p in parents:
609 for p in parents:
610 if p not in seen:
610 if p not in seen:
611 seen[p] = 1
611 seen[p] = 1
612 visit.append(p)
612 visit.append(p)
613 else:
613 else:
614 dest = ui.expandpath(dest or 'default-push', dest or 'default')
614 dest = ui.expandpath(dest or 'default-push', dest or 'default')
615 dest, branches = hg.parseurl(dest, opts.get('branch'))
615 dest, branches = hg.parseurl(dest, opts.get('branch'))
616 other = hg.repository(hg.remoteui(repo, opts), dest)
616 other = hg.repository(hg.remoteui(repo, opts), dest)
617 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
617 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
618 if revs:
618 if revs:
619 revs = [repo.lookup(rev) for rev in revs]
619 revs = [repo.lookup(rev) for rev in revs]
620 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
620 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
621
621
622 if not o:
622 if not o:
623 ui.status(_("no changes found\n"))
623 ui.status(_("no changes found\n"))
624 return 1
624 return 1
625
625
626 if revs:
626 if revs:
627 cg = repo.changegroupsubset(o, revs, 'bundle')
627 cg = repo.changegroupsubset(o, revs, 'bundle')
628 else:
628 else:
629 cg = repo.changegroup(o, 'bundle')
629 cg = repo.changegroup(o, 'bundle')
630
630
631 bundletype = opts.get('type', 'bzip2').lower()
631 bundletype = opts.get('type', 'bzip2').lower()
632 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
632 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
633 bundletype = btypes.get(bundletype)
633 bundletype = btypes.get(bundletype)
634 if bundletype not in changegroup.bundletypes:
634 if bundletype not in changegroup.bundletypes:
635 raise util.Abort(_('unknown bundle type specified with --type'))
635 raise util.Abort(_('unknown bundle type specified with --type'))
636
636
637 changegroup.writebundle(cg, fname, bundletype)
637 changegroup.writebundle(cg, fname, bundletype)
638
638
639 def cat(ui, repo, file1, *pats, **opts):
639 def cat(ui, repo, file1, *pats, **opts):
640 """output the current or given revision of files
640 """output the current or given revision of files
641
641
642 Print the specified files as they were at the given revision. If
642 Print the specified files as they were at the given revision. If
643 no revision is given, the parent of the working directory is used,
643 no revision is given, the parent of the working directory is used,
644 or tip if no revision is checked out.
644 or tip if no revision is checked out.
645
645
646 Output may be to a file, in which case the name of the file is
646 Output may be to a file, in which case the name of the file is
647 given using a format string. The formatting rules are the same as
647 given using a format string. The formatting rules are the same as
648 for the export command, with the following additions:
648 for the export command, with the following additions:
649
649
650 :``%s``: basename of file being printed
650 :``%s``: basename of file being printed
651 :``%d``: dirname of file being printed, or '.' if in repository root
651 :``%d``: dirname of file being printed, or '.' if in repository root
652 :``%p``: root-relative path name of file being printed
652 :``%p``: root-relative path name of file being printed
653
653
654 Returns 0 on success.
654 Returns 0 on success.
655 """
655 """
656 ctx = cmdutil.revsingle(repo, opts.get('rev'))
656 ctx = cmdutil.revsingle(repo, opts.get('rev'))
657 err = 1
657 err = 1
658 m = cmdutil.match(repo, (file1,) + pats, opts)
658 m = cmdutil.match(repo, (file1,) + pats, opts)
659 for abs in ctx.walk(m):
659 for abs in ctx.walk(m):
660 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
660 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
661 data = ctx[abs].data()
661 data = ctx[abs].data()
662 if opts.get('decode'):
662 if opts.get('decode'):
663 data = repo.wwritedata(abs, data)
663 data = repo.wwritedata(abs, data)
664 fp.write(data)
664 fp.write(data)
665 err = 0
665 err = 0
666 return err
666 return err
667
667
668 def clone(ui, source, dest=None, **opts):
668 def clone(ui, source, dest=None, **opts):
669 """make a copy of an existing repository
669 """make a copy of an existing repository
670
670
671 Create a copy of an existing repository in a new directory.
671 Create a copy of an existing repository in a new directory.
672
672
673 If no destination directory name is specified, it defaults to the
673 If no destination directory name is specified, it defaults to the
674 basename of the source.
674 basename of the source.
675
675
676 The location of the source is added to the new repository's
676 The location of the source is added to the new repository's
677 .hg/hgrc file, as the default to be used for future pulls.
677 .hg/hgrc file, as the default to be used for future pulls.
678
678
679 See :hg:`help urls` for valid source format details.
679 See :hg:`help urls` for valid source format details.
680
680
681 It is possible to specify an ``ssh://`` URL as the destination, but no
681 It is possible to specify an ``ssh://`` URL as the destination, but no
682 .hg/hgrc and working directory will be created on the remote side.
682 .hg/hgrc and working directory will be created on the remote side.
683 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
683 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
684
684
685 A set of changesets (tags, or branch names) to pull may be specified
685 A set of changesets (tags, or branch names) to pull may be specified
686 by listing each changeset (tag, or branch name) with -r/--rev.
686 by listing each changeset (tag, or branch name) with -r/--rev.
687 If -r/--rev is used, the cloned repository will contain only a subset
687 If -r/--rev is used, the cloned repository will contain only a subset
688 of the changesets of the source repository. Only the set of changesets
688 of the changesets of the source repository. Only the set of changesets
689 defined by all -r/--rev options (including all their ancestors)
689 defined by all -r/--rev options (including all their ancestors)
690 will be pulled into the destination repository.
690 will be pulled into the destination repository.
691 No subsequent changesets (including subsequent tags) will be present
691 No subsequent changesets (including subsequent tags) will be present
692 in the destination.
692 in the destination.
693
693
694 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
694 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
695 local source repositories.
695 local source repositories.
696
696
697 For efficiency, hardlinks are used for cloning whenever the source
697 For efficiency, hardlinks are used for cloning whenever the source
698 and destination are on the same filesystem (note this applies only
698 and destination are on the same filesystem (note this applies only
699 to the repository data, not to the working directory). Some
699 to the repository data, not to the working directory). Some
700 filesystems, such as AFS, implement hardlinking incorrectly, but
700 filesystems, such as AFS, implement hardlinking incorrectly, but
701 do not report errors. In these cases, use the --pull option to
701 do not report errors. In these cases, use the --pull option to
702 avoid hardlinking.
702 avoid hardlinking.
703
703
704 In some cases, you can clone repositories and the working directory
704 In some cases, you can clone repositories and the working directory
705 using full hardlinks with ::
705 using full hardlinks with ::
706
706
707 $ cp -al REPO REPOCLONE
707 $ cp -al REPO REPOCLONE
708
708
709 This is the fastest way to clone, but it is not always safe. The
709 This is the fastest way to clone, but it is not always safe. The
710 operation is not atomic (making sure REPO is not modified during
710 operation is not atomic (making sure REPO is not modified during
711 the operation is up to you) and you have to make sure your editor
711 the operation is up to you) and you have to make sure your editor
712 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
712 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
713 this is not compatible with certain extensions that place their
713 this is not compatible with certain extensions that place their
714 metadata under the .hg directory, such as mq.
714 metadata under the .hg directory, such as mq.
715
715
716 Mercurial will update the working directory to the first applicable
716 Mercurial will update the working directory to the first applicable
717 revision from this list:
717 revision from this list:
718
718
719 a) null if -U or the source repository has no changesets
719 a) null if -U or the source repository has no changesets
720 b) if -u . and the source repository is local, the first parent of
720 b) if -u . and the source repository is local, the first parent of
721 the source repository's working directory
721 the source repository's working directory
722 c) the changeset specified with -u (if a branch name, this means the
722 c) the changeset specified with -u (if a branch name, this means the
723 latest head of that branch)
723 latest head of that branch)
724 d) the changeset specified with -r
724 d) the changeset specified with -r
725 e) the tipmost head specified with -b
725 e) the tipmost head specified with -b
726 f) the tipmost head specified with the url#branch source syntax
726 f) the tipmost head specified with the url#branch source syntax
727 g) the tipmost head of the default branch
727 g) the tipmost head of the default branch
728 h) tip
728 h) tip
729
729
730 Returns 0 on success.
730 Returns 0 on success.
731 """
731 """
732 if opts.get('noupdate') and opts.get('updaterev'):
732 if opts.get('noupdate') and opts.get('updaterev'):
733 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
733 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
734
734
735 r = hg.clone(hg.remoteui(ui, opts), source, dest,
735 r = hg.clone(hg.remoteui(ui, opts), source, dest,
736 pull=opts.get('pull'),
736 pull=opts.get('pull'),
737 stream=opts.get('uncompressed'),
737 stream=opts.get('uncompressed'),
738 rev=opts.get('rev'),
738 rev=opts.get('rev'),
739 update=opts.get('updaterev') or not opts.get('noupdate'),
739 update=opts.get('updaterev') or not opts.get('noupdate'),
740 branch=opts.get('branch'))
740 branch=opts.get('branch'))
741
741
742 return r is None
742 return r is None
743
743
744 def commit(ui, repo, *pats, **opts):
744 def commit(ui, repo, *pats, **opts):
745 """commit the specified files or all outstanding changes
745 """commit the specified files or all outstanding changes
746
746
747 Commit changes to the given files into the repository. Unlike a
747 Commit changes to the given files into the repository. Unlike a
748 centralized RCS, this operation is a local operation. See
748 centralized RCS, this operation is a local operation. See
749 :hg:`push` for a way to actively distribute your changes.
749 :hg:`push` for a way to actively distribute your changes.
750
750
751 If a list of files is omitted, all changes reported by :hg:`status`
751 If a list of files is omitted, all changes reported by :hg:`status`
752 will be committed.
752 will be committed.
753
753
754 If you are committing the result of a merge, do not provide any
754 If you are committing the result of a merge, do not provide any
755 filenames or -I/-X filters.
755 filenames or -I/-X filters.
756
756
757 If no commit message is specified, Mercurial starts your
757 If no commit message is specified, Mercurial starts your
758 configured editor where you can enter a message. In case your
758 configured editor where you can enter a message. In case your
759 commit fails, you will find a backup of your message in
759 commit fails, you will find a backup of your message in
760 ``.hg/last-message.txt``.
760 ``.hg/last-message.txt``.
761
761
762 See :hg:`help dates` for a list of formats valid for -d/--date.
762 See :hg:`help dates` for a list of formats valid for -d/--date.
763
763
764 Returns 0 on success, 1 if nothing changed.
764 Returns 0 on success, 1 if nothing changed.
765 """
765 """
766 extra = {}
766 extra = {}
767 if opts.get('close_branch'):
767 if opts.get('close_branch'):
768 if repo['.'].node() not in repo.branchheads():
768 if repo['.'].node() not in repo.branchheads():
769 # The topo heads set is included in the branch heads set of the
769 # The topo heads set is included in the branch heads set of the
770 # current branch, so it's sufficient to test branchheads
770 # current branch, so it's sufficient to test branchheads
771 raise util.Abort(_('can only close branch heads'))
771 raise util.Abort(_('can only close branch heads'))
772 extra['close'] = 1
772 extra['close'] = 1
773 e = cmdutil.commiteditor
773 e = cmdutil.commiteditor
774 if opts.get('force_editor'):
774 if opts.get('force_editor'):
775 e = cmdutil.commitforceeditor
775 e = cmdutil.commitforceeditor
776
776
777 def commitfunc(ui, repo, message, match, opts):
777 def commitfunc(ui, repo, message, match, opts):
778 return repo.commit(message, opts.get('user'), opts.get('date'), match,
778 return repo.commit(message, opts.get('user'), opts.get('date'), match,
779 editor=e, extra=extra)
779 editor=e, extra=extra)
780
780
781 branch = repo[None].branch()
781 branch = repo[None].branch()
782 bheads = repo.branchheads(branch)
782 bheads = repo.branchheads(branch)
783
783
784 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
784 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
785 if not node:
785 if not node:
786 ui.status(_("nothing changed\n"))
786 ui.status(_("nothing changed\n"))
787 return 1
787 return 1
788
788
789 ctx = repo[node]
789 ctx = repo[node]
790 parents = ctx.parents()
790 parents = ctx.parents()
791
791
792 if bheads and not [x for x in parents
792 if bheads and not [x for x in parents
793 if x.node() in bheads and x.branch() == branch]:
793 if x.node() in bheads and x.branch() == branch]:
794 ui.status(_('created new head\n'))
794 ui.status(_('created new head\n'))
795 # The message is not printed for initial roots. For the other
795 # The message is not printed for initial roots. For the other
796 # changesets, it is printed in the following situations:
796 # changesets, it is printed in the following situations:
797 #
797 #
798 # Par column: for the 2 parents with ...
798 # Par column: for the 2 parents with ...
799 # N: null or no parent
799 # N: null or no parent
800 # B: parent is on another named branch
800 # B: parent is on another named branch
801 # C: parent is a regular non head changeset
801 # C: parent is a regular non head changeset
802 # H: parent was a branch head of the current branch
802 # H: parent was a branch head of the current branch
803 # Msg column: whether we print "created new head" message
803 # Msg column: whether we print "created new head" message
804 # In the following, it is assumed that there already exists some
804 # In the following, it is assumed that there already exists some
805 # initial branch heads of the current branch, otherwise nothing is
805 # initial branch heads of the current branch, otherwise nothing is
806 # printed anyway.
806 # printed anyway.
807 #
807 #
808 # Par Msg Comment
808 # Par Msg Comment
809 # NN y additional topo root
809 # NN y additional topo root
810 #
810 #
811 # BN y additional branch root
811 # BN y additional branch root
812 # CN y additional topo head
812 # CN y additional topo head
813 # HN n usual case
813 # HN n usual case
814 #
814 #
815 # BB y weird additional branch root
815 # BB y weird additional branch root
816 # CB y branch merge
816 # CB y branch merge
817 # HB n merge with named branch
817 # HB n merge with named branch
818 #
818 #
819 # CC y additional head from merge
819 # CC y additional head from merge
820 # CH n merge with a head
820 # CH n merge with a head
821 #
821 #
822 # HH n head merge: head count decreases
822 # HH n head merge: head count decreases
823
823
824 if not opts.get('close_branch'):
824 if not opts.get('close_branch'):
825 for r in parents:
825 for r in parents:
826 if r.extra().get('close') and r.branch() == branch:
826 if r.extra().get('close') and r.branch() == branch:
827 ui.status(_('reopening closed branch head %d\n') % r)
827 ui.status(_('reopening closed branch head %d\n') % r)
828
828
829 if ui.debugflag:
829 if ui.debugflag:
830 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
830 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
831 elif ui.verbose:
831 elif ui.verbose:
832 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
832 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
833
833
834 def copy(ui, repo, *pats, **opts):
834 def copy(ui, repo, *pats, **opts):
835 """mark files as copied for the next commit
835 """mark files as copied for the next commit
836
836
837 Mark dest as having copies of source files. If dest is a
837 Mark dest as having copies of source files. If dest is a
838 directory, copies are put in that directory. If dest is a file,
838 directory, copies are put in that directory. If dest is a file,
839 the source must be a single file.
839 the source must be a single file.
840
840
841 By default, this command copies the contents of files as they
841 By default, this command copies the contents of files as they
842 exist in the working directory. If invoked with -A/--after, the
842 exist in the working directory. If invoked with -A/--after, the
843 operation is recorded, but no copying is performed.
843 operation is recorded, but no copying is performed.
844
844
845 This command takes effect with the next commit. To undo a copy
845 This command takes effect with the next commit. To undo a copy
846 before that, see :hg:`revert`.
846 before that, see :hg:`revert`.
847
847
848 Returns 0 on success, 1 if errors are encountered.
848 Returns 0 on success, 1 if errors are encountered.
849 """
849 """
850 wlock = repo.wlock(False)
850 wlock = repo.wlock(False)
851 try:
851 try:
852 return cmdutil.copy(ui, repo, pats, opts)
852 return cmdutil.copy(ui, repo, pats, opts)
853 finally:
853 finally:
854 wlock.release()
854 wlock.release()
855
855
856 def debugancestor(ui, repo, *args):
856 def debugancestor(ui, repo, *args):
857 """find the ancestor revision of two revisions in a given index"""
857 """find the ancestor revision of two revisions in a given index"""
858 if len(args) == 3:
858 if len(args) == 3:
859 index, rev1, rev2 = args
859 index, rev1, rev2 = args
860 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
860 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
861 lookup = r.lookup
861 lookup = r.lookup
862 elif len(args) == 2:
862 elif len(args) == 2:
863 if not repo:
863 if not repo:
864 raise util.Abort(_("there is no Mercurial repository here "
864 raise util.Abort(_("there is no Mercurial repository here "
865 "(.hg not found)"))
865 "(.hg not found)"))
866 rev1, rev2 = args
866 rev1, rev2 = args
867 r = repo.changelog
867 r = repo.changelog
868 lookup = repo.lookup
868 lookup = repo.lookup
869 else:
869 else:
870 raise util.Abort(_('either two or three arguments required'))
870 raise util.Abort(_('either two or three arguments required'))
871 a = r.ancestor(lookup(rev1), lookup(rev2))
871 a = r.ancestor(lookup(rev1), lookup(rev2))
872 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
872 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
873
873
874 def debugbuilddag(ui, repo, text,
874 def debugbuilddag(ui, repo, text,
875 mergeable_file=False,
875 mergeable_file=False,
876 appended_file=False,
876 appended_file=False,
877 overwritten_file=False,
877 overwritten_file=False,
878 new_file=False):
878 new_file=False):
879 """builds a repo with a given dag from scratch in the current empty repo
879 """builds a repo with a given dag from scratch in the current empty repo
880
880
881 Elements:
881 Elements:
882
882
883 - "+n" is a linear run of n nodes based on the current default parent
883 - "+n" is a linear run of n nodes based on the current default parent
884 - "." is a single node based on the current default parent
884 - "." is a single node based on the current default parent
885 - "$" resets the default parent to null (implied at the start);
885 - "$" resets the default parent to null (implied at the start);
886 otherwise the default parent is always the last node created
886 otherwise the default parent is always the last node created
887 - "<p" sets the default parent to the backref p
887 - "<p" sets the default parent to the backref p
888 - "*p" is a fork at parent p, which is a backref
888 - "*p" is a fork at parent p, which is a backref
889 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
889 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
890 - "/p2" is a merge of the preceding node and p2
890 - "/p2" is a merge of the preceding node and p2
891 - ":tag" defines a local tag for the preceding node
891 - ":tag" defines a local tag for the preceding node
892 - "@branch" sets the named branch for subsequent nodes
892 - "@branch" sets the named branch for subsequent nodes
893 - "!command" runs the command using your shell
893 - "!command" runs the command using your shell
894 - "!!my command\\n" is like "!", but to the end of the line
894 - "!!my command\\n" is like "!", but to the end of the line
895 - "#...\\n" is a comment up to the end of the line
895 - "#...\\n" is a comment up to the end of the line
896
896
897 Whitespace between the above elements is ignored.
897 Whitespace between the above elements is ignored.
898
898
899 A backref is either
899 A backref is either
900
900
901 - a number n, which references the node curr-n, where curr is the current
901 - a number n, which references the node curr-n, where curr is the current
902 node, or
902 node, or
903 - the name of a local tag you placed earlier using ":tag", or
903 - the name of a local tag you placed earlier using ":tag", or
904 - empty to denote the default parent.
904 - empty to denote the default parent.
905
905
906 All string valued-elements are either strictly alphanumeric, or must
906 All string valued-elements are either strictly alphanumeric, or must
907 be enclosed in double quotes ("..."), with "\\" as escape character.
907 be enclosed in double quotes ("..."), with "\\" as escape character.
908
908
909 Note that the --overwritten-file and --appended-file options imply the
909 Note that the --overwritten-file and --appended-file options imply the
910 use of "HGMERGE=internal:local" during DAG buildup.
910 use of "HGMERGE=internal:local" during DAG buildup.
911 """
911 """
912
912
913 if not (mergeable_file or appended_file or overwritten_file or new_file):
913 if not (mergeable_file or appended_file or overwritten_file or new_file):
914 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
914 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
915
915
916 if len(repo.changelog) > 0:
916 if len(repo.changelog) > 0:
917 raise util.Abort(_('repository is not empty'))
917 raise util.Abort(_('repository is not empty'))
918
918
919 if overwritten_file or appended_file:
919 if overwritten_file or appended_file:
920 # we don't want to fail in merges during buildup
920 # we don't want to fail in merges during buildup
921 os.environ['HGMERGE'] = 'internal:local'
921 os.environ['HGMERGE'] = 'internal:local'
922
922
923 def writefile(fname, text, fmode="wb"):
923 def writefile(fname, text, fmode="wb"):
924 f = open(fname, fmode)
924 f = open(fname, fmode)
925 try:
925 try:
926 f.write(text)
926 f.write(text)
927 finally:
927 finally:
928 f.close()
928 f.close()
929
929
930 if mergeable_file:
930 if mergeable_file:
931 linesperrev = 2
931 linesperrev = 2
932 # determine number of revs in DAG
932 # determine number of revs in DAG
933 n = 0
933 n = 0
934 for type, data in dagparser.parsedag(text):
934 for type, data in dagparser.parsedag(text):
935 if type == 'n':
935 if type == 'n':
936 n += 1
936 n += 1
937 # make a file with k lines per rev
937 # make a file with k lines per rev
938 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
938 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
939 + "\n")
939 + "\n")
940
940
941 at = -1
941 at = -1
942 atbranch = 'default'
942 atbranch = 'default'
943 for type, data in dagparser.parsedag(text):
943 for type, data in dagparser.parsedag(text):
944 if type == 'n':
944 if type == 'n':
945 ui.status('node %s\n' % str(data))
945 ui.status('node %s\n' % str(data))
946 id, ps = data
946 id, ps = data
947 p1 = ps[0]
947 p1 = ps[0]
948 if p1 != at:
948 if p1 != at:
949 update(ui, repo, node=str(p1), clean=True)
949 update(ui, repo, node=str(p1), clean=True)
950 at = p1
950 at = p1
951 if repo.dirstate.branch() != atbranch:
951 if repo.dirstate.branch() != atbranch:
952 branch(ui, repo, atbranch, force=True)
952 branch(ui, repo, atbranch, force=True)
953 if len(ps) > 1:
953 if len(ps) > 1:
954 p2 = ps[1]
954 p2 = ps[1]
955 merge(ui, repo, node=p2)
955 merge(ui, repo, node=p2)
956
956
957 if mergeable_file:
957 if mergeable_file:
958 f = open("mf", "rb+")
958 f = open("mf", "rb+")
959 try:
959 try:
960 lines = f.read().split("\n")
960 lines = f.read().split("\n")
961 lines[id * linesperrev] += " r%i" % id
961 lines[id * linesperrev] += " r%i" % id
962 f.seek(0)
962 f.seek(0)
963 f.write("\n".join(lines))
963 f.write("\n".join(lines))
964 finally:
964 finally:
965 f.close()
965 f.close()
966
966
967 if appended_file:
967 if appended_file:
968 writefile("af", "r%i\n" % id, "ab")
968 writefile("af", "r%i\n" % id, "ab")
969
969
970 if overwritten_file:
970 if overwritten_file:
971 writefile("of", "r%i\n" % id)
971 writefile("of", "r%i\n" % id)
972
972
973 if new_file:
973 if new_file:
974 writefile("nf%i" % id, "r%i\n" % id)
974 writefile("nf%i" % id, "r%i\n" % id)
975
975
976 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
976 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
977 at = id
977 at = id
978 elif type == 'l':
978 elif type == 'l':
979 id, name = data
979 id, name = data
980 ui.status('tag %s\n' % name)
980 ui.status('tag %s\n' % name)
981 tag(ui, repo, name, local=True)
981 tag(ui, repo, name, local=True)
982 elif type == 'a':
982 elif type == 'a':
983 ui.status('branch %s\n' % data)
983 ui.status('branch %s\n' % data)
984 atbranch = data
984 atbranch = data
985 elif type in 'cC':
985 elif type in 'cC':
986 r = util.system(data, cwd=repo.root)
986 r = util.system(data, cwd=repo.root)
987 if r:
987 if r:
988 desc, r = util.explain_exit(r)
988 desc, r = util.explain_exit(r)
989 raise util.Abort(_('%s command %s') % (data, desc))
989 raise util.Abort(_('%s command %s') % (data, desc))
990
990
991 def debugcommands(ui, cmd='', *args):
991 def debugcommands(ui, cmd='', *args):
992 """list all available commands and options"""
992 """list all available commands and options"""
993 for cmd, vals in sorted(table.iteritems()):
993 for cmd, vals in sorted(table.iteritems()):
994 cmd = cmd.split('|')[0].strip('^')
994 cmd = cmd.split('|')[0].strip('^')
995 opts = ', '.join([i[1] for i in vals[1]])
995 opts = ', '.join([i[1] for i in vals[1]])
996 ui.write('%s: %s\n' % (cmd, opts))
996 ui.write('%s: %s\n' % (cmd, opts))
997
997
998 def debugcomplete(ui, cmd='', **opts):
998 def debugcomplete(ui, cmd='', **opts):
999 """returns the completion list associated with the given command"""
999 """returns the completion list associated with the given command"""
1000
1000
1001 if opts.get('options'):
1001 if opts.get('options'):
1002 options = []
1002 options = []
1003 otables = [globalopts]
1003 otables = [globalopts]
1004 if cmd:
1004 if cmd:
1005 aliases, entry = cmdutil.findcmd(cmd, table, False)
1005 aliases, entry = cmdutil.findcmd(cmd, table, False)
1006 otables.append(entry[1])
1006 otables.append(entry[1])
1007 for t in otables:
1007 for t in otables:
1008 for o in t:
1008 for o in t:
1009 if "(DEPRECATED)" in o[3]:
1009 if "(DEPRECATED)" in o[3]:
1010 continue
1010 continue
1011 if o[0]:
1011 if o[0]:
1012 options.append('-%s' % o[0])
1012 options.append('-%s' % o[0])
1013 options.append('--%s' % o[1])
1013 options.append('--%s' % o[1])
1014 ui.write("%s\n" % "\n".join(options))
1014 ui.write("%s\n" % "\n".join(options))
1015 return
1015 return
1016
1016
1017 cmdlist = cmdutil.findpossible(cmd, table)
1017 cmdlist = cmdutil.findpossible(cmd, table)
1018 if ui.verbose:
1018 if ui.verbose:
1019 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1019 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1020 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1020 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1021
1021
1022 def debugfsinfo(ui, path = "."):
1022 def debugfsinfo(ui, path = "."):
1023 """show information detected about current filesystem"""
1023 """show information detected about current filesystem"""
1024 open('.debugfsinfo', 'w').write('')
1024 open('.debugfsinfo', 'w').write('')
1025 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1025 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1026 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1026 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1027 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1027 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1028 and 'yes' or 'no'))
1028 and 'yes' or 'no'))
1029 os.unlink('.debugfsinfo')
1029 os.unlink('.debugfsinfo')
1030
1030
1031 def debugrebuildstate(ui, repo, rev="tip"):
1031 def debugrebuildstate(ui, repo, rev="tip"):
1032 """rebuild the dirstate as it would look like for the given revision"""
1032 """rebuild the dirstate as it would look like for the given revision"""
1033 ctx = cmdutil.revsingle(repo, rev)
1033 ctx = cmdutil.revsingle(repo, rev)
1034 wlock = repo.wlock()
1034 wlock = repo.wlock()
1035 try:
1035 try:
1036 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1036 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1037 finally:
1037 finally:
1038 wlock.release()
1038 wlock.release()
1039
1039
1040 def debugcheckstate(ui, repo):
1040 def debugcheckstate(ui, repo):
1041 """validate the correctness of the current dirstate"""
1041 """validate the correctness of the current dirstate"""
1042 parent1, parent2 = repo.dirstate.parents()
1042 parent1, parent2 = repo.dirstate.parents()
1043 m1 = repo[parent1].manifest()
1043 m1 = repo[parent1].manifest()
1044 m2 = repo[parent2].manifest()
1044 m2 = repo[parent2].manifest()
1045 errors = 0
1045 errors = 0
1046 for f in repo.dirstate:
1046 for f in repo.dirstate:
1047 state = repo.dirstate[f]
1047 state = repo.dirstate[f]
1048 if state in "nr" and f not in m1:
1048 if state in "nr" and f not in m1:
1049 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1049 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1050 errors += 1
1050 errors += 1
1051 if state in "a" and f in m1:
1051 if state in "a" and f in m1:
1052 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1052 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1053 errors += 1
1053 errors += 1
1054 if state in "m" and f not in m1 and f not in m2:
1054 if state in "m" and f not in m1 and f not in m2:
1055 ui.warn(_("%s in state %s, but not in either manifest\n") %
1055 ui.warn(_("%s in state %s, but not in either manifest\n") %
1056 (f, state))
1056 (f, state))
1057 errors += 1
1057 errors += 1
1058 for f in m1:
1058 for f in m1:
1059 state = repo.dirstate[f]
1059 state = repo.dirstate[f]
1060 if state not in "nrm":
1060 if state not in "nrm":
1061 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1061 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1062 errors += 1
1062 errors += 1
1063 if errors:
1063 if errors:
1064 error = _(".hg/dirstate inconsistent with current parent's manifest")
1064 error = _(".hg/dirstate inconsistent with current parent's manifest")
1065 raise util.Abort(error)
1065 raise util.Abort(error)
1066
1066
1067 def showconfig(ui, repo, *values, **opts):
1067 def showconfig(ui, repo, *values, **opts):
1068 """show combined config settings from all hgrc files
1068 """show combined config settings from all hgrc files
1069
1069
1070 With no arguments, print names and values of all config items.
1070 With no arguments, print names and values of all config items.
1071
1071
1072 With one argument of the form section.name, print just the value
1072 With one argument of the form section.name, print just the value
1073 of that config item.
1073 of that config item.
1074
1074
1075 With multiple arguments, print names and values of all config
1075 With multiple arguments, print names and values of all config
1076 items with matching section names.
1076 items with matching section names.
1077
1077
1078 With --debug, the source (filename and line number) is printed
1078 With --debug, the source (filename and line number) is printed
1079 for each config item.
1079 for each config item.
1080
1080
1081 Returns 0 on success.
1081 Returns 0 on success.
1082 """
1082 """
1083
1083
1084 for f in util.rcpath():
1084 for f in util.rcpath():
1085 ui.debug(_('read config from: %s\n') % f)
1085 ui.debug(_('read config from: %s\n') % f)
1086 untrusted = bool(opts.get('untrusted'))
1086 untrusted = bool(opts.get('untrusted'))
1087 if values:
1087 if values:
1088 sections = [v for v in values if '.' not in v]
1088 sections = [v for v in values if '.' not in v]
1089 items = [v for v in values if '.' in v]
1089 items = [v for v in values if '.' in v]
1090 if len(items) > 1 or items and sections:
1090 if len(items) > 1 or items and sections:
1091 raise util.Abort(_('only one config item permitted'))
1091 raise util.Abort(_('only one config item permitted'))
1092 for section, name, value in ui.walkconfig(untrusted=untrusted):
1092 for section, name, value in ui.walkconfig(untrusted=untrusted):
1093 sectname = section + '.' + name
1093 sectname = section + '.' + name
1094 if values:
1094 if values:
1095 for v in values:
1095 for v in values:
1096 if v == section:
1096 if v == section:
1097 ui.debug('%s: ' %
1097 ui.debug('%s: ' %
1098 ui.configsource(section, name, untrusted))
1098 ui.configsource(section, name, untrusted))
1099 ui.write('%s=%s\n' % (sectname, value))
1099 ui.write('%s=%s\n' % (sectname, value))
1100 elif v == sectname:
1100 elif v == sectname:
1101 ui.debug('%s: ' %
1101 ui.debug('%s: ' %
1102 ui.configsource(section, name, untrusted))
1102 ui.configsource(section, name, untrusted))
1103 ui.write(value, '\n')
1103 ui.write(value, '\n')
1104 else:
1104 else:
1105 ui.debug('%s: ' %
1105 ui.debug('%s: ' %
1106 ui.configsource(section, name, untrusted))
1106 ui.configsource(section, name, untrusted))
1107 ui.write('%s=%s\n' % (sectname, value))
1107 ui.write('%s=%s\n' % (sectname, value))
1108
1108
1109 def debugpushkey(ui, repopath, namespace, *keyinfo):
1109 def debugpushkey(ui, repopath, namespace, *keyinfo):
1110 '''access the pushkey key/value protocol
1110 '''access the pushkey key/value protocol
1111
1111
1112 With two args, list the keys in the given namespace.
1112 With two args, list the keys in the given namespace.
1113
1113
1114 With five args, set a key to new if it currently is set to old.
1114 With five args, set a key to new if it currently is set to old.
1115 Reports success or failure.
1115 Reports success or failure.
1116 '''
1116 '''
1117
1117
1118 target = hg.repository(ui, repopath)
1118 target = hg.repository(ui, repopath)
1119 if keyinfo:
1119 if keyinfo:
1120 key, old, new = keyinfo
1120 key, old, new = keyinfo
1121 r = target.pushkey(namespace, key, old, new)
1121 r = target.pushkey(namespace, key, old, new)
1122 ui.status(str(r) + '\n')
1122 ui.status(str(r) + '\n')
1123 return not r
1123 return not r
1124 else:
1124 else:
1125 for k, v in target.listkeys(namespace).iteritems():
1125 for k, v in target.listkeys(namespace).iteritems():
1126 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1126 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1127 v.encode('string-escape')))
1127 v.encode('string-escape')))
1128
1128
1129 def debugrevspec(ui, repo, expr):
1129 def debugrevspec(ui, repo, expr):
1130 '''parse and apply a revision specification'''
1130 '''parse and apply a revision specification'''
1131 if ui.verbose:
1131 if ui.verbose:
1132 tree = revset.parse(expr)
1132 tree = revset.parse(expr)
1133 ui.note(tree, "\n")
1133 ui.note(tree, "\n")
1134 func = revset.match(expr)
1134 func = revset.match(expr)
1135 for c in func(repo, range(len(repo))):
1135 for c in func(repo, range(len(repo))):
1136 ui.write("%s\n" % c)
1136 ui.write("%s\n" % c)
1137
1137
1138 def debugsetparents(ui, repo, rev1, rev2=None):
1138 def debugsetparents(ui, repo, rev1, rev2=None):
1139 """manually set the parents of the current working directory
1139 """manually set the parents of the current working directory
1140
1140
1141 This is useful for writing repository conversion tools, but should
1141 This is useful for writing repository conversion tools, but should
1142 be used with care.
1142 be used with care.
1143
1143
1144 Returns 0 on success.
1144 Returns 0 on success.
1145 """
1145 """
1146
1146
1147 r1 = cmdutil.revsingle(repo, rev1).node()
1147 r1 = cmdutil.revsingle(repo, rev1).node()
1148 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1148 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1149
1149
1150 wlock = repo.wlock()
1150 wlock = repo.wlock()
1151 try:
1151 try:
1152 repo.dirstate.setparents(r1, r2)
1152 repo.dirstate.setparents(r1, r2)
1153 finally:
1153 finally:
1154 wlock.release()
1154 wlock.release()
1155
1155
1156 def debugstate(ui, repo, nodates=None):
1156 def debugstate(ui, repo, nodates=None):
1157 """show the contents of the current dirstate"""
1157 """show the contents of the current dirstate"""
1158 timestr = ""
1158 timestr = ""
1159 showdate = not nodates
1159 showdate = not nodates
1160 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1160 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1161 if showdate:
1161 if showdate:
1162 if ent[3] == -1:
1162 if ent[3] == -1:
1163 # Pad or slice to locale representation
1163 # Pad or slice to locale representation
1164 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1164 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1165 time.localtime(0)))
1165 time.localtime(0)))
1166 timestr = 'unset'
1166 timestr = 'unset'
1167 timestr = (timestr[:locale_len] +
1167 timestr = (timestr[:locale_len] +
1168 ' ' * (locale_len - len(timestr)))
1168 ' ' * (locale_len - len(timestr)))
1169 else:
1169 else:
1170 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1170 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1171 time.localtime(ent[3]))
1171 time.localtime(ent[3]))
1172 if ent[1] & 020000:
1172 if ent[1] & 020000:
1173 mode = 'lnk'
1173 mode = 'lnk'
1174 else:
1174 else:
1175 mode = '%3o' % (ent[1] & 0777)
1175 mode = '%3o' % (ent[1] & 0777)
1176 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1176 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1177 for f in repo.dirstate.copies():
1177 for f in repo.dirstate.copies():
1178 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1178 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1179
1179
1180 def debugsub(ui, repo, rev=None):
1180 def debugsub(ui, repo, rev=None):
1181 ctx = cmdutil.revsingle(repo, rev, None)
1181 ctx = cmdutil.revsingle(repo, rev, None)
1182 for k, v in sorted(ctx.substate.items()):
1182 for k, v in sorted(ctx.substate.items()):
1183 ui.write('path %s\n' % k)
1183 ui.write('path %s\n' % k)
1184 ui.write(' source %s\n' % v[0])
1184 ui.write(' source %s\n' % v[0])
1185 ui.write(' revision %s\n' % v[1])
1185 ui.write(' revision %s\n' % v[1])
1186
1186
1187 def debugdag(ui, repo, file_=None, *revs, **opts):
1187 def debugdag(ui, repo, file_=None, *revs, **opts):
1188 """format the changelog or an index DAG as a concise textual description
1188 """format the changelog or an index DAG as a concise textual description
1189
1189
1190 If you pass a revlog index, the revlog's DAG is emitted. If you list
1190 If you pass a revlog index, the revlog's DAG is emitted. If you list
1191 revision numbers, they get labelled in the output as rN.
1191 revision numbers, they get labelled in the output as rN.
1192
1192
1193 Otherwise, the changelog DAG of the current repo is emitted.
1193 Otherwise, the changelog DAG of the current repo is emitted.
1194 """
1194 """
1195 spaces = opts.get('spaces')
1195 spaces = opts.get('spaces')
1196 dots = opts.get('dots')
1196 dots = opts.get('dots')
1197 if file_:
1197 if file_:
1198 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1198 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1199 revs = set((int(r) for r in revs))
1199 revs = set((int(r) for r in revs))
1200 def events():
1200 def events():
1201 for r in rlog:
1201 for r in rlog:
1202 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1202 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1203 if r in revs:
1203 if r in revs:
1204 yield 'l', (r, "r%i" % r)
1204 yield 'l', (r, "r%i" % r)
1205 elif repo:
1205 elif repo:
1206 cl = repo.changelog
1206 cl = repo.changelog
1207 tags = opts.get('tags')
1207 tags = opts.get('tags')
1208 branches = opts.get('branches')
1208 branches = opts.get('branches')
1209 if tags:
1209 if tags:
1210 labels = {}
1210 labels = {}
1211 for l, n in repo.tags().items():
1211 for l, n in repo.tags().items():
1212 labels.setdefault(cl.rev(n), []).append(l)
1212 labels.setdefault(cl.rev(n), []).append(l)
1213 def events():
1213 def events():
1214 b = "default"
1214 b = "default"
1215 for r in cl:
1215 for r in cl:
1216 if branches:
1216 if branches:
1217 newb = cl.read(cl.node(r))[5]['branch']
1217 newb = cl.read(cl.node(r))[5]['branch']
1218 if newb != b:
1218 if newb != b:
1219 yield 'a', newb
1219 yield 'a', newb
1220 b = newb
1220 b = newb
1221 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1221 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1222 if tags:
1222 if tags:
1223 ls = labels.get(r)
1223 ls = labels.get(r)
1224 if ls:
1224 if ls:
1225 for l in ls:
1225 for l in ls:
1226 yield 'l', (r, l)
1226 yield 'l', (r, l)
1227 else:
1227 else:
1228 raise util.Abort(_('need repo for changelog dag'))
1228 raise util.Abort(_('need repo for changelog dag'))
1229
1229
1230 for line in dagparser.dagtextlines(events(),
1230 for line in dagparser.dagtextlines(events(),
1231 addspaces=spaces,
1231 addspaces=spaces,
1232 wraplabels=True,
1232 wraplabels=True,
1233 wrapannotations=True,
1233 wrapannotations=True,
1234 wrapnonlinear=dots,
1234 wrapnonlinear=dots,
1235 usedots=dots,
1235 usedots=dots,
1236 maxlinewidth=70):
1236 maxlinewidth=70):
1237 ui.write(line)
1237 ui.write(line)
1238 ui.write("\n")
1238 ui.write("\n")
1239
1239
1240 def debugdata(ui, repo, file_, rev):
1240 def debugdata(ui, repo, file_, rev):
1241 """dump the contents of a data file revision"""
1241 """dump the contents of a data file revision"""
1242 r = None
1242 r = None
1243 if repo:
1243 if repo:
1244 filelog = repo.file(file_)
1244 filelog = repo.file(file_)
1245 if len(filelog):
1245 if len(filelog):
1246 r = filelog
1246 r = filelog
1247 if not r:
1247 if not r:
1248 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1248 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1249 try:
1249 try:
1250 ui.write(r.revision(r.lookup(rev)))
1250 ui.write(r.revision(r.lookup(rev)))
1251 except KeyError:
1251 except KeyError:
1252 raise util.Abort(_('invalid revision identifier %s') % rev)
1252 raise util.Abort(_('invalid revision identifier %s') % rev)
1253
1253
1254 def debugdate(ui, date, range=None, **opts):
1254 def debugdate(ui, date, range=None, **opts):
1255 """parse and display a date"""
1255 """parse and display a date"""
1256 if opts["extended"]:
1256 if opts["extended"]:
1257 d = util.parsedate(date, util.extendeddateformats)
1257 d = util.parsedate(date, util.extendeddateformats)
1258 else:
1258 else:
1259 d = util.parsedate(date)
1259 d = util.parsedate(date)
1260 ui.write("internal: %s %s\n" % d)
1260 ui.write("internal: %s %s\n" % d)
1261 ui.write("standard: %s\n" % util.datestr(d))
1261 ui.write("standard: %s\n" % util.datestr(d))
1262 if range:
1262 if range:
1263 m = util.matchdate(range)
1263 m = util.matchdate(range)
1264 ui.write("match: %s\n" % m(d[0]))
1264 ui.write("match: %s\n" % m(d[0]))
1265
1265
1266 def debugindex(ui, repo, file_, **opts):
1266 def debugindex(ui, repo, file_, **opts):
1267 """dump the contents of an index file"""
1267 """dump the contents of an index file"""
1268 r = None
1268 r = None
1269 if repo:
1269 if repo:
1270 filelog = repo.file(file_)
1270 filelog = repo.file(file_)
1271 if len(filelog):
1271 if len(filelog):
1272 r = filelog
1272 r = filelog
1273
1273
1274 format = opts.get('format', 0)
1274 format = opts.get('format', 0)
1275 if format not in (0, 1):
1275 if format not in (0, 1):
1276 raise util.abort("unknown format %d" % format)
1276 raise util.Abort("unknown format %d" % format)
1277
1277
1278 if not r:
1278 if not r:
1279 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1279 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1280
1280
1281 if format == 0:
1281 if format == 0:
1282 ui.write(" rev offset length base linkrev"
1282 ui.write(" rev offset length base linkrev"
1283 " nodeid p1 p2\n")
1283 " nodeid p1 p2\n")
1284 elif format == 1:
1284 elif format == 1:
1285 ui.write(" rev flag offset length"
1285 ui.write(" rev flag offset length"
1286 " size base link p1 p2 nodeid\n")
1286 " size base link p1 p2 nodeid\n")
1287
1287
1288 for i in r:
1288 for i in r:
1289 node = r.node(i)
1289 node = r.node(i)
1290 if format == 0:
1290 if format == 0:
1291 try:
1291 try:
1292 pp = r.parents(node)
1292 pp = r.parents(node)
1293 except:
1293 except:
1294 pp = [nullid, nullid]
1294 pp = [nullid, nullid]
1295 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1295 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1296 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1296 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1297 short(node), short(pp[0]), short(pp[1])))
1297 short(node), short(pp[0]), short(pp[1])))
1298 elif format == 1:
1298 elif format == 1:
1299 pr = r.parentrevs(i)
1299 pr = r.parentrevs(i)
1300 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1300 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1301 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1301 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1302 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1302 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1303
1303
1304 def debugindexdot(ui, repo, file_):
1304 def debugindexdot(ui, repo, file_):
1305 """dump an index DAG as a graphviz dot file"""
1305 """dump an index DAG as a graphviz dot file"""
1306 r = None
1306 r = None
1307 if repo:
1307 if repo:
1308 filelog = repo.file(file_)
1308 filelog = repo.file(file_)
1309 if len(filelog):
1309 if len(filelog):
1310 r = filelog
1310 r = filelog
1311 if not r:
1311 if not r:
1312 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1312 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1313 ui.write("digraph G {\n")
1313 ui.write("digraph G {\n")
1314 for i in r:
1314 for i in r:
1315 node = r.node(i)
1315 node = r.node(i)
1316 pp = r.parents(node)
1316 pp = r.parents(node)
1317 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1317 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1318 if pp[1] != nullid:
1318 if pp[1] != nullid:
1319 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1319 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1320 ui.write("}\n")
1320 ui.write("}\n")
1321
1321
1322 def debuginstall(ui):
1322 def debuginstall(ui):
1323 '''test Mercurial installation
1323 '''test Mercurial installation
1324
1324
1325 Returns 0 on success.
1325 Returns 0 on success.
1326 '''
1326 '''
1327
1327
1328 def writetemp(contents):
1328 def writetemp(contents):
1329 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1329 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1330 f = os.fdopen(fd, "wb")
1330 f = os.fdopen(fd, "wb")
1331 f.write(contents)
1331 f.write(contents)
1332 f.close()
1332 f.close()
1333 return name
1333 return name
1334
1334
1335 problems = 0
1335 problems = 0
1336
1336
1337 # encoding
1337 # encoding
1338 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1338 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1339 try:
1339 try:
1340 encoding.fromlocal("test")
1340 encoding.fromlocal("test")
1341 except util.Abort, inst:
1341 except util.Abort, inst:
1342 ui.write(" %s\n" % inst)
1342 ui.write(" %s\n" % inst)
1343 ui.write(_(" (check that your locale is properly set)\n"))
1343 ui.write(_(" (check that your locale is properly set)\n"))
1344 problems += 1
1344 problems += 1
1345
1345
1346 # compiled modules
1346 # compiled modules
1347 ui.status(_("Checking installed modules (%s)...\n")
1347 ui.status(_("Checking installed modules (%s)...\n")
1348 % os.path.dirname(__file__))
1348 % os.path.dirname(__file__))
1349 try:
1349 try:
1350 import bdiff, mpatch, base85, osutil
1350 import bdiff, mpatch, base85, osutil
1351 except Exception, inst:
1351 except Exception, inst:
1352 ui.write(" %s\n" % inst)
1352 ui.write(" %s\n" % inst)
1353 ui.write(_(" One or more extensions could not be found"))
1353 ui.write(_(" One or more extensions could not be found"))
1354 ui.write(_(" (check that you compiled the extensions)\n"))
1354 ui.write(_(" (check that you compiled the extensions)\n"))
1355 problems += 1
1355 problems += 1
1356
1356
1357 # templates
1357 # templates
1358 ui.status(_("Checking templates...\n"))
1358 ui.status(_("Checking templates...\n"))
1359 try:
1359 try:
1360 import templater
1360 import templater
1361 templater.templater(templater.templatepath("map-cmdline.default"))
1361 templater.templater(templater.templatepath("map-cmdline.default"))
1362 except Exception, inst:
1362 except Exception, inst:
1363 ui.write(" %s\n" % inst)
1363 ui.write(" %s\n" % inst)
1364 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1364 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1365 problems += 1
1365 problems += 1
1366
1366
1367 # patch
1367 # patch
1368 ui.status(_("Checking patch...\n"))
1368 ui.status(_("Checking patch...\n"))
1369 patchproblems = 0
1369 patchproblems = 0
1370 a = "1\n2\n3\n4\n"
1370 a = "1\n2\n3\n4\n"
1371 b = "1\n2\n3\ninsert\n4\n"
1371 b = "1\n2\n3\ninsert\n4\n"
1372 fa = writetemp(a)
1372 fa = writetemp(a)
1373 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1373 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1374 os.path.basename(fa))
1374 os.path.basename(fa))
1375 fd = writetemp(d)
1375 fd = writetemp(d)
1376
1376
1377 files = {}
1377 files = {}
1378 try:
1378 try:
1379 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1379 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1380 except util.Abort, e:
1380 except util.Abort, e:
1381 ui.write(_(" patch call failed:\n"))
1381 ui.write(_(" patch call failed:\n"))
1382 ui.write(" " + str(e) + "\n")
1382 ui.write(" " + str(e) + "\n")
1383 patchproblems += 1
1383 patchproblems += 1
1384 else:
1384 else:
1385 if list(files) != [os.path.basename(fa)]:
1385 if list(files) != [os.path.basename(fa)]:
1386 ui.write(_(" unexpected patch output!\n"))
1386 ui.write(_(" unexpected patch output!\n"))
1387 patchproblems += 1
1387 patchproblems += 1
1388 a = open(fa).read()
1388 a = open(fa).read()
1389 if a != b:
1389 if a != b:
1390 ui.write(_(" patch test failed!\n"))
1390 ui.write(_(" patch test failed!\n"))
1391 patchproblems += 1
1391 patchproblems += 1
1392
1392
1393 if patchproblems:
1393 if patchproblems:
1394 if ui.config('ui', 'patch'):
1394 if ui.config('ui', 'patch'):
1395 ui.write(_(" (Current patch tool may be incompatible with patch,"
1395 ui.write(_(" (Current patch tool may be incompatible with patch,"
1396 " or misconfigured. Please check your configuration"
1396 " or misconfigured. Please check your configuration"
1397 " file)\n"))
1397 " file)\n"))
1398 else:
1398 else:
1399 ui.write(_(" Internal patcher failure, please report this error"
1399 ui.write(_(" Internal patcher failure, please report this error"
1400 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1400 " to http://mercurial.selenic.com/wiki/BugTracker\n"))
1401 problems += patchproblems
1401 problems += patchproblems
1402
1402
1403 os.unlink(fa)
1403 os.unlink(fa)
1404 os.unlink(fd)
1404 os.unlink(fd)
1405
1405
1406 # editor
1406 # editor
1407 ui.status(_("Checking commit editor...\n"))
1407 ui.status(_("Checking commit editor...\n"))
1408 editor = ui.geteditor()
1408 editor = ui.geteditor()
1409 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1409 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1410 if not cmdpath:
1410 if not cmdpath:
1411 if editor == 'vi':
1411 if editor == 'vi':
1412 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1412 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1413 ui.write(_(" (specify a commit editor in your configuration"
1413 ui.write(_(" (specify a commit editor in your configuration"
1414 " file)\n"))
1414 " file)\n"))
1415 else:
1415 else:
1416 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1416 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1417 ui.write(_(" (specify a commit editor in your configuration"
1417 ui.write(_(" (specify a commit editor in your configuration"
1418 " file)\n"))
1418 " file)\n"))
1419 problems += 1
1419 problems += 1
1420
1420
1421 # check username
1421 # check username
1422 ui.status(_("Checking username...\n"))
1422 ui.status(_("Checking username...\n"))
1423 try:
1423 try:
1424 ui.username()
1424 ui.username()
1425 except util.Abort, e:
1425 except util.Abort, e:
1426 ui.write(" %s\n" % e)
1426 ui.write(" %s\n" % e)
1427 ui.write(_(" (specify a username in your configuration file)\n"))
1427 ui.write(_(" (specify a username in your configuration file)\n"))
1428 problems += 1
1428 problems += 1
1429
1429
1430 if not problems:
1430 if not problems:
1431 ui.status(_("No problems detected\n"))
1431 ui.status(_("No problems detected\n"))
1432 else:
1432 else:
1433 ui.write(_("%s problems detected,"
1433 ui.write(_("%s problems detected,"
1434 " please check your install!\n") % problems)
1434 " please check your install!\n") % problems)
1435
1435
1436 return problems
1436 return problems
1437
1437
1438 def debugrename(ui, repo, file1, *pats, **opts):
1438 def debugrename(ui, repo, file1, *pats, **opts):
1439 """dump rename information"""
1439 """dump rename information"""
1440
1440
1441 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1441 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1442 m = cmdutil.match(repo, (file1,) + pats, opts)
1442 m = cmdutil.match(repo, (file1,) + pats, opts)
1443 for abs in ctx.walk(m):
1443 for abs in ctx.walk(m):
1444 fctx = ctx[abs]
1444 fctx = ctx[abs]
1445 o = fctx.filelog().renamed(fctx.filenode())
1445 o = fctx.filelog().renamed(fctx.filenode())
1446 rel = m.rel(abs)
1446 rel = m.rel(abs)
1447 if o:
1447 if o:
1448 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1448 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1449 else:
1449 else:
1450 ui.write(_("%s not renamed\n") % rel)
1450 ui.write(_("%s not renamed\n") % rel)
1451
1451
1452 def debugwalk(ui, repo, *pats, **opts):
1452 def debugwalk(ui, repo, *pats, **opts):
1453 """show how files match on given patterns"""
1453 """show how files match on given patterns"""
1454 m = cmdutil.match(repo, pats, opts)
1454 m = cmdutil.match(repo, pats, opts)
1455 items = list(repo.walk(m))
1455 items = list(repo.walk(m))
1456 if not items:
1456 if not items:
1457 return
1457 return
1458 fmt = 'f %%-%ds %%-%ds %%s' % (
1458 fmt = 'f %%-%ds %%-%ds %%s' % (
1459 max([len(abs) for abs in items]),
1459 max([len(abs) for abs in items]),
1460 max([len(m.rel(abs)) for abs in items]))
1460 max([len(m.rel(abs)) for abs in items]))
1461 for abs in items:
1461 for abs in items:
1462 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1462 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1463 ui.write("%s\n" % line.rstrip())
1463 ui.write("%s\n" % line.rstrip())
1464
1464
1465 def diff(ui, repo, *pats, **opts):
1465 def diff(ui, repo, *pats, **opts):
1466 """diff repository (or selected files)
1466 """diff repository (or selected files)
1467
1467
1468 Show differences between revisions for the specified files.
1468 Show differences between revisions for the specified files.
1469
1469
1470 Differences between files are shown using the unified diff format.
1470 Differences between files are shown using the unified diff format.
1471
1471
1472 .. note::
1472 .. note::
1473 diff may generate unexpected results for merges, as it will
1473 diff may generate unexpected results for merges, as it will
1474 default to comparing against the working directory's first
1474 default to comparing against the working directory's first
1475 parent changeset if no revisions are specified.
1475 parent changeset if no revisions are specified.
1476
1476
1477 When two revision arguments are given, then changes are shown
1477 When two revision arguments are given, then changes are shown
1478 between those revisions. If only one revision is specified then
1478 between those revisions. If only one revision is specified then
1479 that revision is compared to the working directory, and, when no
1479 that revision is compared to the working directory, and, when no
1480 revisions are specified, the working directory files are compared
1480 revisions are specified, the working directory files are compared
1481 to its parent.
1481 to its parent.
1482
1482
1483 Alternatively you can specify -c/--change with a revision to see
1483 Alternatively you can specify -c/--change with a revision to see
1484 the changes in that changeset relative to its first parent.
1484 the changes in that changeset relative to its first parent.
1485
1485
1486 Without the -a/--text option, diff will avoid generating diffs of
1486 Without the -a/--text option, diff will avoid generating diffs of
1487 files it detects as binary. With -a, diff will generate a diff
1487 files it detects as binary. With -a, diff will generate a diff
1488 anyway, probably with undesirable results.
1488 anyway, probably with undesirable results.
1489
1489
1490 Use the -g/--git option to generate diffs in the git extended diff
1490 Use the -g/--git option to generate diffs in the git extended diff
1491 format. For more information, read :hg:`help diffs`.
1491 format. For more information, read :hg:`help diffs`.
1492
1492
1493 Returns 0 on success.
1493 Returns 0 on success.
1494 """
1494 """
1495
1495
1496 revs = opts.get('rev')
1496 revs = opts.get('rev')
1497 change = opts.get('change')
1497 change = opts.get('change')
1498 stat = opts.get('stat')
1498 stat = opts.get('stat')
1499 reverse = opts.get('reverse')
1499 reverse = opts.get('reverse')
1500
1500
1501 if revs and change:
1501 if revs and change:
1502 msg = _('cannot specify --rev and --change at the same time')
1502 msg = _('cannot specify --rev and --change at the same time')
1503 raise util.Abort(msg)
1503 raise util.Abort(msg)
1504 elif change:
1504 elif change:
1505 node2 = repo.lookup(change)
1505 node2 = repo.lookup(change)
1506 node1 = repo[node2].parents()[0].node()
1506 node1 = repo[node2].parents()[0].node()
1507 else:
1507 else:
1508 node1, node2 = cmdutil.revpair(repo, revs)
1508 node1, node2 = cmdutil.revpair(repo, revs)
1509
1509
1510 if reverse:
1510 if reverse:
1511 node1, node2 = node2, node1
1511 node1, node2 = node2, node1
1512
1512
1513 diffopts = patch.diffopts(ui, opts)
1513 diffopts = patch.diffopts(ui, opts)
1514 m = cmdutil.match(repo, pats, opts)
1514 m = cmdutil.match(repo, pats, opts)
1515 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1515 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1516 listsubrepos=opts.get('subrepos'))
1516 listsubrepos=opts.get('subrepos'))
1517
1517
1518 def export(ui, repo, *changesets, **opts):
1518 def export(ui, repo, *changesets, **opts):
1519 """dump the header and diffs for one or more changesets
1519 """dump the header and diffs for one or more changesets
1520
1520
1521 Print the changeset header and diffs for one or more revisions.
1521 Print the changeset header and diffs for one or more revisions.
1522
1522
1523 The information shown in the changeset header is: author, date,
1523 The information shown in the changeset header is: author, date,
1524 branch name (if non-default), changeset hash, parent(s) and commit
1524 branch name (if non-default), changeset hash, parent(s) and commit
1525 comment.
1525 comment.
1526
1526
1527 .. note::
1527 .. note::
1528 export may generate unexpected diff output for merge
1528 export may generate unexpected diff output for merge
1529 changesets, as it will compare the merge changeset against its
1529 changesets, as it will compare the merge changeset against its
1530 first parent only.
1530 first parent only.
1531
1531
1532 Output may be to a file, in which case the name of the file is
1532 Output may be to a file, in which case the name of the file is
1533 given using a format string. The formatting rules are as follows:
1533 given using a format string. The formatting rules are as follows:
1534
1534
1535 :``%%``: literal "%" character
1535 :``%%``: literal "%" character
1536 :``%H``: changeset hash (40 hexadecimal digits)
1536 :``%H``: changeset hash (40 hexadecimal digits)
1537 :``%N``: number of patches being generated
1537 :``%N``: number of patches being generated
1538 :``%R``: changeset revision number
1538 :``%R``: changeset revision number
1539 :``%b``: basename of the exporting repository
1539 :``%b``: basename of the exporting repository
1540 :``%h``: short-form changeset hash (12 hexadecimal digits)
1540 :``%h``: short-form changeset hash (12 hexadecimal digits)
1541 :``%n``: zero-padded sequence number, starting at 1
1541 :``%n``: zero-padded sequence number, starting at 1
1542 :``%r``: zero-padded changeset revision number
1542 :``%r``: zero-padded changeset revision number
1543
1543
1544 Without the -a/--text option, export will avoid generating diffs
1544 Without the -a/--text option, export will avoid generating diffs
1545 of files it detects as binary. With -a, export will generate a
1545 of files it detects as binary. With -a, export will generate a
1546 diff anyway, probably with undesirable results.
1546 diff anyway, probably with undesirable results.
1547
1547
1548 Use the -g/--git option to generate diffs in the git extended diff
1548 Use the -g/--git option to generate diffs in the git extended diff
1549 format. See :hg:`help diffs` for more information.
1549 format. See :hg:`help diffs` for more information.
1550
1550
1551 With the --switch-parent option, the diff will be against the
1551 With the --switch-parent option, the diff will be against the
1552 second parent. It can be useful to review a merge.
1552 second parent. It can be useful to review a merge.
1553
1553
1554 Returns 0 on success.
1554 Returns 0 on success.
1555 """
1555 """
1556 changesets += tuple(opts.get('rev', []))
1556 changesets += tuple(opts.get('rev', []))
1557 if not changesets:
1557 if not changesets:
1558 raise util.Abort(_("export requires at least one changeset"))
1558 raise util.Abort(_("export requires at least one changeset"))
1559 revs = cmdutil.revrange(repo, changesets)
1559 revs = cmdutil.revrange(repo, changesets)
1560 if len(revs) > 1:
1560 if len(revs) > 1:
1561 ui.note(_('exporting patches:\n'))
1561 ui.note(_('exporting patches:\n'))
1562 else:
1562 else:
1563 ui.note(_('exporting patch:\n'))
1563 ui.note(_('exporting patch:\n'))
1564 cmdutil.export(repo, revs, template=opts.get('output'),
1564 cmdutil.export(repo, revs, template=opts.get('output'),
1565 switch_parent=opts.get('switch_parent'),
1565 switch_parent=opts.get('switch_parent'),
1566 opts=patch.diffopts(ui, opts))
1566 opts=patch.diffopts(ui, opts))
1567
1567
1568 def forget(ui, repo, *pats, **opts):
1568 def forget(ui, repo, *pats, **opts):
1569 """forget the specified files on the next commit
1569 """forget the specified files on the next commit
1570
1570
1571 Mark the specified files so they will no longer be tracked
1571 Mark the specified files so they will no longer be tracked
1572 after the next commit.
1572 after the next commit.
1573
1573
1574 This only removes files from the current branch, not from the
1574 This only removes files from the current branch, not from the
1575 entire project history, and it does not delete them from the
1575 entire project history, and it does not delete them from the
1576 working directory.
1576 working directory.
1577
1577
1578 To undo a forget before the next commit, see :hg:`add`.
1578 To undo a forget before the next commit, see :hg:`add`.
1579
1579
1580 Returns 0 on success.
1580 Returns 0 on success.
1581 """
1581 """
1582
1582
1583 if not pats:
1583 if not pats:
1584 raise util.Abort(_('no files specified'))
1584 raise util.Abort(_('no files specified'))
1585
1585
1586 m = cmdutil.match(repo, pats, opts)
1586 m = cmdutil.match(repo, pats, opts)
1587 s = repo.status(match=m, clean=True)
1587 s = repo.status(match=m, clean=True)
1588 forget = sorted(s[0] + s[1] + s[3] + s[6])
1588 forget = sorted(s[0] + s[1] + s[3] + s[6])
1589 errs = 0
1589 errs = 0
1590
1590
1591 for f in m.files():
1591 for f in m.files():
1592 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1592 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1593 ui.warn(_('not removing %s: file is already untracked\n')
1593 ui.warn(_('not removing %s: file is already untracked\n')
1594 % m.rel(f))
1594 % m.rel(f))
1595 errs = 1
1595 errs = 1
1596
1596
1597 for f in forget:
1597 for f in forget:
1598 if ui.verbose or not m.exact(f):
1598 if ui.verbose or not m.exact(f):
1599 ui.status(_('removing %s\n') % m.rel(f))
1599 ui.status(_('removing %s\n') % m.rel(f))
1600
1600
1601 repo[None].remove(forget, unlink=False)
1601 repo[None].remove(forget, unlink=False)
1602 return errs
1602 return errs
1603
1603
1604 def grep(ui, repo, pattern, *pats, **opts):
1604 def grep(ui, repo, pattern, *pats, **opts):
1605 """search for a pattern in specified files and revisions
1605 """search for a pattern in specified files and revisions
1606
1606
1607 Search revisions of files for a regular expression.
1607 Search revisions of files for a regular expression.
1608
1608
1609 This command behaves differently than Unix grep. It only accepts
1609 This command behaves differently than Unix grep. It only accepts
1610 Python/Perl regexps. It searches repository history, not the
1610 Python/Perl regexps. It searches repository history, not the
1611 working directory. It always prints the revision number in which a
1611 working directory. It always prints the revision number in which a
1612 match appears.
1612 match appears.
1613
1613
1614 By default, grep only prints output for the first revision of a
1614 By default, grep only prints output for the first revision of a
1615 file in which it finds a match. To get it to print every revision
1615 file in which it finds a match. To get it to print every revision
1616 that contains a change in match status ("-" for a match that
1616 that contains a change in match status ("-" for a match that
1617 becomes a non-match, or "+" for a non-match that becomes a match),
1617 becomes a non-match, or "+" for a non-match that becomes a match),
1618 use the --all flag.
1618 use the --all flag.
1619
1619
1620 Returns 0 if a match is found, 1 otherwise.
1620 Returns 0 if a match is found, 1 otherwise.
1621 """
1621 """
1622 reflags = 0
1622 reflags = 0
1623 if opts.get('ignore_case'):
1623 if opts.get('ignore_case'):
1624 reflags |= re.I
1624 reflags |= re.I
1625 try:
1625 try:
1626 regexp = re.compile(pattern, reflags)
1626 regexp = re.compile(pattern, reflags)
1627 except re.error, inst:
1627 except re.error, inst:
1628 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1628 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1629 return 1
1629 return 1
1630 sep, eol = ':', '\n'
1630 sep, eol = ':', '\n'
1631 if opts.get('print0'):
1631 if opts.get('print0'):
1632 sep = eol = '\0'
1632 sep = eol = '\0'
1633
1633
1634 getfile = util.lrucachefunc(repo.file)
1634 getfile = util.lrucachefunc(repo.file)
1635
1635
1636 def matchlines(body):
1636 def matchlines(body):
1637 begin = 0
1637 begin = 0
1638 linenum = 0
1638 linenum = 0
1639 while True:
1639 while True:
1640 match = regexp.search(body, begin)
1640 match = regexp.search(body, begin)
1641 if not match:
1641 if not match:
1642 break
1642 break
1643 mstart, mend = match.span()
1643 mstart, mend = match.span()
1644 linenum += body.count('\n', begin, mstart) + 1
1644 linenum += body.count('\n', begin, mstart) + 1
1645 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1645 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1646 begin = body.find('\n', mend) + 1 or len(body)
1646 begin = body.find('\n', mend) + 1 or len(body)
1647 lend = begin - 1
1647 lend = begin - 1
1648 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1648 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1649
1649
1650 class linestate(object):
1650 class linestate(object):
1651 def __init__(self, line, linenum, colstart, colend):
1651 def __init__(self, line, linenum, colstart, colend):
1652 self.line = line
1652 self.line = line
1653 self.linenum = linenum
1653 self.linenum = linenum
1654 self.colstart = colstart
1654 self.colstart = colstart
1655 self.colend = colend
1655 self.colend = colend
1656
1656
1657 def __hash__(self):
1657 def __hash__(self):
1658 return hash((self.linenum, self.line))
1658 return hash((self.linenum, self.line))
1659
1659
1660 def __eq__(self, other):
1660 def __eq__(self, other):
1661 return self.line == other.line
1661 return self.line == other.line
1662
1662
1663 matches = {}
1663 matches = {}
1664 copies = {}
1664 copies = {}
1665 def grepbody(fn, rev, body):
1665 def grepbody(fn, rev, body):
1666 matches[rev].setdefault(fn, [])
1666 matches[rev].setdefault(fn, [])
1667 m = matches[rev][fn]
1667 m = matches[rev][fn]
1668 for lnum, cstart, cend, line in matchlines(body):
1668 for lnum, cstart, cend, line in matchlines(body):
1669 s = linestate(line, lnum, cstart, cend)
1669 s = linestate(line, lnum, cstart, cend)
1670 m.append(s)
1670 m.append(s)
1671
1671
1672 def difflinestates(a, b):
1672 def difflinestates(a, b):
1673 sm = difflib.SequenceMatcher(None, a, b)
1673 sm = difflib.SequenceMatcher(None, a, b)
1674 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1674 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1675 if tag == 'insert':
1675 if tag == 'insert':
1676 for i in xrange(blo, bhi):
1676 for i in xrange(blo, bhi):
1677 yield ('+', b[i])
1677 yield ('+', b[i])
1678 elif tag == 'delete':
1678 elif tag == 'delete':
1679 for i in xrange(alo, ahi):
1679 for i in xrange(alo, ahi):
1680 yield ('-', a[i])
1680 yield ('-', a[i])
1681 elif tag == 'replace':
1681 elif tag == 'replace':
1682 for i in xrange(alo, ahi):
1682 for i in xrange(alo, ahi):
1683 yield ('-', a[i])
1683 yield ('-', a[i])
1684 for i in xrange(blo, bhi):
1684 for i in xrange(blo, bhi):
1685 yield ('+', b[i])
1685 yield ('+', b[i])
1686
1686
1687 def display(fn, ctx, pstates, states):
1687 def display(fn, ctx, pstates, states):
1688 rev = ctx.rev()
1688 rev = ctx.rev()
1689 datefunc = ui.quiet and util.shortdate or util.datestr
1689 datefunc = ui.quiet and util.shortdate or util.datestr
1690 found = False
1690 found = False
1691 filerevmatches = {}
1691 filerevmatches = {}
1692 if opts.get('all'):
1692 if opts.get('all'):
1693 iter = difflinestates(pstates, states)
1693 iter = difflinestates(pstates, states)
1694 else:
1694 else:
1695 iter = [('', l) for l in states]
1695 iter = [('', l) for l in states]
1696 for change, l in iter:
1696 for change, l in iter:
1697 cols = [fn, str(rev)]
1697 cols = [fn, str(rev)]
1698 before, match, after = None, None, None
1698 before, match, after = None, None, None
1699 if opts.get('line_number'):
1699 if opts.get('line_number'):
1700 cols.append(str(l.linenum))
1700 cols.append(str(l.linenum))
1701 if opts.get('all'):
1701 if opts.get('all'):
1702 cols.append(change)
1702 cols.append(change)
1703 if opts.get('user'):
1703 if opts.get('user'):
1704 cols.append(ui.shortuser(ctx.user()))
1704 cols.append(ui.shortuser(ctx.user()))
1705 if opts.get('date'):
1705 if opts.get('date'):
1706 cols.append(datefunc(ctx.date()))
1706 cols.append(datefunc(ctx.date()))
1707 if opts.get('files_with_matches'):
1707 if opts.get('files_with_matches'):
1708 c = (fn, rev)
1708 c = (fn, rev)
1709 if c in filerevmatches:
1709 if c in filerevmatches:
1710 continue
1710 continue
1711 filerevmatches[c] = 1
1711 filerevmatches[c] = 1
1712 else:
1712 else:
1713 before = l.line[:l.colstart]
1713 before = l.line[:l.colstart]
1714 match = l.line[l.colstart:l.colend]
1714 match = l.line[l.colstart:l.colend]
1715 after = l.line[l.colend:]
1715 after = l.line[l.colend:]
1716 ui.write(sep.join(cols))
1716 ui.write(sep.join(cols))
1717 if before is not None:
1717 if before is not None:
1718 ui.write(sep + before)
1718 ui.write(sep + before)
1719 ui.write(match, label='grep.match')
1719 ui.write(match, label='grep.match')
1720 ui.write(after)
1720 ui.write(after)
1721 ui.write(eol)
1721 ui.write(eol)
1722 found = True
1722 found = True
1723 return found
1723 return found
1724
1724
1725 skip = {}
1725 skip = {}
1726 revfiles = {}
1726 revfiles = {}
1727 matchfn = cmdutil.match(repo, pats, opts)
1727 matchfn = cmdutil.match(repo, pats, opts)
1728 found = False
1728 found = False
1729 follow = opts.get('follow')
1729 follow = opts.get('follow')
1730
1730
1731 def prep(ctx, fns):
1731 def prep(ctx, fns):
1732 rev = ctx.rev()
1732 rev = ctx.rev()
1733 pctx = ctx.parents()[0]
1733 pctx = ctx.parents()[0]
1734 parent = pctx.rev()
1734 parent = pctx.rev()
1735 matches.setdefault(rev, {})
1735 matches.setdefault(rev, {})
1736 matches.setdefault(parent, {})
1736 matches.setdefault(parent, {})
1737 files = revfiles.setdefault(rev, [])
1737 files = revfiles.setdefault(rev, [])
1738 for fn in fns:
1738 for fn in fns:
1739 flog = getfile(fn)
1739 flog = getfile(fn)
1740 try:
1740 try:
1741 fnode = ctx.filenode(fn)
1741 fnode = ctx.filenode(fn)
1742 except error.LookupError:
1742 except error.LookupError:
1743 continue
1743 continue
1744
1744
1745 copied = flog.renamed(fnode)
1745 copied = flog.renamed(fnode)
1746 copy = follow and copied and copied[0]
1746 copy = follow and copied and copied[0]
1747 if copy:
1747 if copy:
1748 copies.setdefault(rev, {})[fn] = copy
1748 copies.setdefault(rev, {})[fn] = copy
1749 if fn in skip:
1749 if fn in skip:
1750 if copy:
1750 if copy:
1751 skip[copy] = True
1751 skip[copy] = True
1752 continue
1752 continue
1753 files.append(fn)
1753 files.append(fn)
1754
1754
1755 if fn not in matches[rev]:
1755 if fn not in matches[rev]:
1756 grepbody(fn, rev, flog.read(fnode))
1756 grepbody(fn, rev, flog.read(fnode))
1757
1757
1758 pfn = copy or fn
1758 pfn = copy or fn
1759 if pfn not in matches[parent]:
1759 if pfn not in matches[parent]:
1760 try:
1760 try:
1761 fnode = pctx.filenode(pfn)
1761 fnode = pctx.filenode(pfn)
1762 grepbody(pfn, parent, flog.read(fnode))
1762 grepbody(pfn, parent, flog.read(fnode))
1763 except error.LookupError:
1763 except error.LookupError:
1764 pass
1764 pass
1765
1765
1766 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1766 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1767 rev = ctx.rev()
1767 rev = ctx.rev()
1768 parent = ctx.parents()[0].rev()
1768 parent = ctx.parents()[0].rev()
1769 for fn in sorted(revfiles.get(rev, [])):
1769 for fn in sorted(revfiles.get(rev, [])):
1770 states = matches[rev][fn]
1770 states = matches[rev][fn]
1771 copy = copies.get(rev, {}).get(fn)
1771 copy = copies.get(rev, {}).get(fn)
1772 if fn in skip:
1772 if fn in skip:
1773 if copy:
1773 if copy:
1774 skip[copy] = True
1774 skip[copy] = True
1775 continue
1775 continue
1776 pstates = matches.get(parent, {}).get(copy or fn, [])
1776 pstates = matches.get(parent, {}).get(copy or fn, [])
1777 if pstates or states:
1777 if pstates or states:
1778 r = display(fn, ctx, pstates, states)
1778 r = display(fn, ctx, pstates, states)
1779 found = found or r
1779 found = found or r
1780 if r and not opts.get('all'):
1780 if r and not opts.get('all'):
1781 skip[fn] = True
1781 skip[fn] = True
1782 if copy:
1782 if copy:
1783 skip[copy] = True
1783 skip[copy] = True
1784 del matches[rev]
1784 del matches[rev]
1785 del revfiles[rev]
1785 del revfiles[rev]
1786
1786
1787 return not found
1787 return not found
1788
1788
1789 def heads(ui, repo, *branchrevs, **opts):
1789 def heads(ui, repo, *branchrevs, **opts):
1790 """show current repository heads or show branch heads
1790 """show current repository heads or show branch heads
1791
1791
1792 With no arguments, show all repository branch heads.
1792 With no arguments, show all repository branch heads.
1793
1793
1794 Repository "heads" are changesets with no child changesets. They are
1794 Repository "heads" are changesets with no child changesets. They are
1795 where development generally takes place and are the usual targets
1795 where development generally takes place and are the usual targets
1796 for update and merge operations. Branch heads are changesets that have
1796 for update and merge operations. Branch heads are changesets that have
1797 no child changeset on the same branch.
1797 no child changeset on the same branch.
1798
1798
1799 If one or more REVs are given, only branch heads on the branches
1799 If one or more REVs are given, only branch heads on the branches
1800 associated with the specified changesets are shown.
1800 associated with the specified changesets are shown.
1801
1801
1802 If -c/--closed is specified, also show branch heads marked closed
1802 If -c/--closed is specified, also show branch heads marked closed
1803 (see :hg:`commit --close-branch`).
1803 (see :hg:`commit --close-branch`).
1804
1804
1805 If STARTREV is specified, only those heads that are descendants of
1805 If STARTREV is specified, only those heads that are descendants of
1806 STARTREV will be displayed.
1806 STARTREV will be displayed.
1807
1807
1808 If -t/--topo is specified, named branch mechanics will be ignored and only
1808 If -t/--topo is specified, named branch mechanics will be ignored and only
1809 changesets without children will be shown.
1809 changesets without children will be shown.
1810
1810
1811 Returns 0 if matching heads are found, 1 if not.
1811 Returns 0 if matching heads are found, 1 if not.
1812 """
1812 """
1813
1813
1814 start = None
1814 start = None
1815 if 'rev' in opts:
1815 if 'rev' in opts:
1816 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1816 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1817
1817
1818 if opts.get('topo'):
1818 if opts.get('topo'):
1819 heads = [repo[h] for h in repo.heads(start)]
1819 heads = [repo[h] for h in repo.heads(start)]
1820 else:
1820 else:
1821 heads = []
1821 heads = []
1822 for b, ls in repo.branchmap().iteritems():
1822 for b, ls in repo.branchmap().iteritems():
1823 if start is None:
1823 if start is None:
1824 heads += [repo[h] for h in ls]
1824 heads += [repo[h] for h in ls]
1825 continue
1825 continue
1826 startrev = repo.changelog.rev(start)
1826 startrev = repo.changelog.rev(start)
1827 descendants = set(repo.changelog.descendants(startrev))
1827 descendants = set(repo.changelog.descendants(startrev))
1828 descendants.add(startrev)
1828 descendants.add(startrev)
1829 rev = repo.changelog.rev
1829 rev = repo.changelog.rev
1830 heads += [repo[h] for h in ls if rev(h) in descendants]
1830 heads += [repo[h] for h in ls if rev(h) in descendants]
1831
1831
1832 if branchrevs:
1832 if branchrevs:
1833 decode, encode = encoding.fromlocal, encoding.tolocal
1833 decode, encode = encoding.fromlocal, encoding.tolocal
1834 branches = set(repo[decode(br)].branch() for br in branchrevs)
1834 branches = set(repo[decode(br)].branch() for br in branchrevs)
1835 heads = [h for h in heads if h.branch() in branches]
1835 heads = [h for h in heads if h.branch() in branches]
1836
1836
1837 if not opts.get('closed'):
1837 if not opts.get('closed'):
1838 heads = [h for h in heads if not h.extra().get('close')]
1838 heads = [h for h in heads if not h.extra().get('close')]
1839
1839
1840 if opts.get('active') and branchrevs:
1840 if opts.get('active') and branchrevs:
1841 dagheads = repo.heads(start)
1841 dagheads = repo.heads(start)
1842 heads = [h for h in heads if h.node() in dagheads]
1842 heads = [h for h in heads if h.node() in dagheads]
1843
1843
1844 if branchrevs:
1844 if branchrevs:
1845 haveheads = set(h.branch() for h in heads)
1845 haveheads = set(h.branch() for h in heads)
1846 if branches - haveheads:
1846 if branches - haveheads:
1847 headless = ', '.join(encode(b) for b in branches - haveheads)
1847 headless = ', '.join(encode(b) for b in branches - haveheads)
1848 msg = _('no open branch heads found on branches %s')
1848 msg = _('no open branch heads found on branches %s')
1849 if opts.get('rev'):
1849 if opts.get('rev'):
1850 msg += _(' (started at %s)' % opts['rev'])
1850 msg += _(' (started at %s)' % opts['rev'])
1851 ui.warn((msg + '\n') % headless)
1851 ui.warn((msg + '\n') % headless)
1852
1852
1853 if not heads:
1853 if not heads:
1854 return 1
1854 return 1
1855
1855
1856 heads = sorted(heads, key=lambda x: -x.rev())
1856 heads = sorted(heads, key=lambda x: -x.rev())
1857 displayer = cmdutil.show_changeset(ui, repo, opts)
1857 displayer = cmdutil.show_changeset(ui, repo, opts)
1858 for ctx in heads:
1858 for ctx in heads:
1859 displayer.show(ctx)
1859 displayer.show(ctx)
1860 displayer.close()
1860 displayer.close()
1861
1861
1862 def help_(ui, name=None, with_version=False, unknowncmd=False):
1862 def help_(ui, name=None, with_version=False, unknowncmd=False):
1863 """show help for a given topic or a help overview
1863 """show help for a given topic or a help overview
1864
1864
1865 With no arguments, print a list of commands with short help messages.
1865 With no arguments, print a list of commands with short help messages.
1866
1866
1867 Given a topic, extension, or command name, print help for that
1867 Given a topic, extension, or command name, print help for that
1868 topic.
1868 topic.
1869
1869
1870 Returns 0 if successful.
1870 Returns 0 if successful.
1871 """
1871 """
1872 option_lists = []
1872 option_lists = []
1873 textwidth = ui.termwidth() - 2
1873 textwidth = ui.termwidth() - 2
1874
1874
1875 def addglobalopts(aliases):
1875 def addglobalopts(aliases):
1876 if ui.verbose:
1876 if ui.verbose:
1877 option_lists.append((_("global options:"), globalopts))
1877 option_lists.append((_("global options:"), globalopts))
1878 if name == 'shortlist':
1878 if name == 'shortlist':
1879 option_lists.append((_('use "hg help" for the full list '
1879 option_lists.append((_('use "hg help" for the full list '
1880 'of commands'), ()))
1880 'of commands'), ()))
1881 else:
1881 else:
1882 if name == 'shortlist':
1882 if name == 'shortlist':
1883 msg = _('use "hg help" for the full list of commands '
1883 msg = _('use "hg help" for the full list of commands '
1884 'or "hg -v" for details')
1884 'or "hg -v" for details')
1885 elif aliases:
1885 elif aliases:
1886 msg = _('use "hg -v help%s" to show aliases and '
1886 msg = _('use "hg -v help%s" to show aliases and '
1887 'global options') % (name and " " + name or "")
1887 'global options') % (name and " " + name or "")
1888 else:
1888 else:
1889 msg = _('use "hg -v help %s" to show global options') % name
1889 msg = _('use "hg -v help %s" to show global options') % name
1890 option_lists.append((msg, ()))
1890 option_lists.append((msg, ()))
1891
1891
1892 def helpcmd(name):
1892 def helpcmd(name):
1893 if with_version:
1893 if with_version:
1894 version_(ui)
1894 version_(ui)
1895 ui.write('\n')
1895 ui.write('\n')
1896
1896
1897 try:
1897 try:
1898 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1898 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1899 except error.AmbiguousCommand, inst:
1899 except error.AmbiguousCommand, inst:
1900 # py3k fix: except vars can't be used outside the scope of the
1900 # py3k fix: except vars can't be used outside the scope of the
1901 # except block, nor can be used inside a lambda. python issue4617
1901 # except block, nor can be used inside a lambda. python issue4617
1902 prefix = inst.args[0]
1902 prefix = inst.args[0]
1903 select = lambda c: c.lstrip('^').startswith(prefix)
1903 select = lambda c: c.lstrip('^').startswith(prefix)
1904 helplist(_('list of commands:\n\n'), select)
1904 helplist(_('list of commands:\n\n'), select)
1905 return
1905 return
1906
1906
1907 # check if it's an invalid alias and display its error if it is
1907 # check if it's an invalid alias and display its error if it is
1908 if getattr(entry[0], 'badalias', False):
1908 if getattr(entry[0], 'badalias', False):
1909 if not unknowncmd:
1909 if not unknowncmd:
1910 entry[0](ui)
1910 entry[0](ui)
1911 return
1911 return
1912
1912
1913 # synopsis
1913 # synopsis
1914 if len(entry) > 2:
1914 if len(entry) > 2:
1915 if entry[2].startswith('hg'):
1915 if entry[2].startswith('hg'):
1916 ui.write("%s\n" % entry[2])
1916 ui.write("%s\n" % entry[2])
1917 else:
1917 else:
1918 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1918 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1919 else:
1919 else:
1920 ui.write('hg %s\n' % aliases[0])
1920 ui.write('hg %s\n' % aliases[0])
1921
1921
1922 # aliases
1922 # aliases
1923 if not ui.quiet and len(aliases) > 1:
1923 if not ui.quiet and len(aliases) > 1:
1924 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1924 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1925
1925
1926 # description
1926 # description
1927 doc = gettext(entry[0].__doc__)
1927 doc = gettext(entry[0].__doc__)
1928 if not doc:
1928 if not doc:
1929 doc = _("(no help text available)")
1929 doc = _("(no help text available)")
1930 if hasattr(entry[0], 'definition'): # aliased command
1930 if hasattr(entry[0], 'definition'): # aliased command
1931 if entry[0].definition.startswith('!'): # shell alias
1931 if entry[0].definition.startswith('!'): # shell alias
1932 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1932 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1933 else:
1933 else:
1934 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1934 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1935 if ui.quiet:
1935 if ui.quiet:
1936 doc = doc.splitlines()[0]
1936 doc = doc.splitlines()[0]
1937 keep = ui.verbose and ['verbose'] or []
1937 keep = ui.verbose and ['verbose'] or []
1938 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1938 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1939 ui.write("\n%s\n" % formatted)
1939 ui.write("\n%s\n" % formatted)
1940 if pruned:
1940 if pruned:
1941 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1941 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1942
1942
1943 if not ui.quiet:
1943 if not ui.quiet:
1944 # options
1944 # options
1945 if entry[1]:
1945 if entry[1]:
1946 option_lists.append((_("options:\n"), entry[1]))
1946 option_lists.append((_("options:\n"), entry[1]))
1947
1947
1948 addglobalopts(False)
1948 addglobalopts(False)
1949
1949
1950 def helplist(header, select=None):
1950 def helplist(header, select=None):
1951 h = {}
1951 h = {}
1952 cmds = {}
1952 cmds = {}
1953 for c, e in table.iteritems():
1953 for c, e in table.iteritems():
1954 f = c.split("|", 1)[0]
1954 f = c.split("|", 1)[0]
1955 if select and not select(f):
1955 if select and not select(f):
1956 continue
1956 continue
1957 if (not select and name != 'shortlist' and
1957 if (not select and name != 'shortlist' and
1958 e[0].__module__ != __name__):
1958 e[0].__module__ != __name__):
1959 continue
1959 continue
1960 if name == "shortlist" and not f.startswith("^"):
1960 if name == "shortlist" and not f.startswith("^"):
1961 continue
1961 continue
1962 f = f.lstrip("^")
1962 f = f.lstrip("^")
1963 if not ui.debugflag and f.startswith("debug"):
1963 if not ui.debugflag and f.startswith("debug"):
1964 continue
1964 continue
1965 doc = e[0].__doc__
1965 doc = e[0].__doc__
1966 if doc and 'DEPRECATED' in doc and not ui.verbose:
1966 if doc and 'DEPRECATED' in doc and not ui.verbose:
1967 continue
1967 continue
1968 doc = gettext(doc)
1968 doc = gettext(doc)
1969 if not doc:
1969 if not doc:
1970 doc = _("(no help text available)")
1970 doc = _("(no help text available)")
1971 h[f] = doc.splitlines()[0].rstrip()
1971 h[f] = doc.splitlines()[0].rstrip()
1972 cmds[f] = c.lstrip("^")
1972 cmds[f] = c.lstrip("^")
1973
1973
1974 if not h:
1974 if not h:
1975 ui.status(_('no commands defined\n'))
1975 ui.status(_('no commands defined\n'))
1976 return
1976 return
1977
1977
1978 ui.status(header)
1978 ui.status(header)
1979 fns = sorted(h)
1979 fns = sorted(h)
1980 m = max(map(len, fns))
1980 m = max(map(len, fns))
1981 for f in fns:
1981 for f in fns:
1982 if ui.verbose:
1982 if ui.verbose:
1983 commands = cmds[f].replace("|",", ")
1983 commands = cmds[f].replace("|",", ")
1984 ui.write(" %s:\n %s\n"%(commands, h[f]))
1984 ui.write(" %s:\n %s\n"%(commands, h[f]))
1985 else:
1985 else:
1986 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1986 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1987 initindent=' %-*s ' % (m, f),
1987 initindent=' %-*s ' % (m, f),
1988 hangindent=' ' * (m + 4))))
1988 hangindent=' ' * (m + 4))))
1989
1989
1990 if not ui.quiet:
1990 if not ui.quiet:
1991 addglobalopts(True)
1991 addglobalopts(True)
1992
1992
1993 def helptopic(name):
1993 def helptopic(name):
1994 for names, header, doc in help.helptable:
1994 for names, header, doc in help.helptable:
1995 if name in names:
1995 if name in names:
1996 break
1996 break
1997 else:
1997 else:
1998 raise error.UnknownCommand(name)
1998 raise error.UnknownCommand(name)
1999
1999
2000 # description
2000 # description
2001 if not doc:
2001 if not doc:
2002 doc = _("(no help text available)")
2002 doc = _("(no help text available)")
2003 if hasattr(doc, '__call__'):
2003 if hasattr(doc, '__call__'):
2004 doc = doc()
2004 doc = doc()
2005
2005
2006 ui.write("%s\n\n" % header)
2006 ui.write("%s\n\n" % header)
2007 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2007 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2008
2008
2009 def helpext(name):
2009 def helpext(name):
2010 try:
2010 try:
2011 mod = extensions.find(name)
2011 mod = extensions.find(name)
2012 doc = gettext(mod.__doc__) or _('no help text available')
2012 doc = gettext(mod.__doc__) or _('no help text available')
2013 except KeyError:
2013 except KeyError:
2014 mod = None
2014 mod = None
2015 doc = extensions.disabledext(name)
2015 doc = extensions.disabledext(name)
2016 if not doc:
2016 if not doc:
2017 raise error.UnknownCommand(name)
2017 raise error.UnknownCommand(name)
2018
2018
2019 if '\n' not in doc:
2019 if '\n' not in doc:
2020 head, tail = doc, ""
2020 head, tail = doc, ""
2021 else:
2021 else:
2022 head, tail = doc.split('\n', 1)
2022 head, tail = doc.split('\n', 1)
2023 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2023 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2024 if tail:
2024 if tail:
2025 ui.write(minirst.format(tail, textwidth))
2025 ui.write(minirst.format(tail, textwidth))
2026 ui.status('\n\n')
2026 ui.status('\n\n')
2027
2027
2028 if mod:
2028 if mod:
2029 try:
2029 try:
2030 ct = mod.cmdtable
2030 ct = mod.cmdtable
2031 except AttributeError:
2031 except AttributeError:
2032 ct = {}
2032 ct = {}
2033 modcmds = set([c.split('|', 1)[0] for c in ct])
2033 modcmds = set([c.split('|', 1)[0] for c in ct])
2034 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2034 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2035 else:
2035 else:
2036 ui.write(_('use "hg help extensions" for information on enabling '
2036 ui.write(_('use "hg help extensions" for information on enabling '
2037 'extensions\n'))
2037 'extensions\n'))
2038
2038
2039 def helpextcmd(name):
2039 def helpextcmd(name):
2040 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2040 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2041 doc = gettext(mod.__doc__).splitlines()[0]
2041 doc = gettext(mod.__doc__).splitlines()[0]
2042
2042
2043 msg = help.listexts(_("'%s' is provided by the following "
2043 msg = help.listexts(_("'%s' is provided by the following "
2044 "extension:") % cmd, {ext: doc}, len(ext),
2044 "extension:") % cmd, {ext: doc}, len(ext),
2045 indent=4)
2045 indent=4)
2046 ui.write(minirst.format(msg, textwidth))
2046 ui.write(minirst.format(msg, textwidth))
2047 ui.write('\n\n')
2047 ui.write('\n\n')
2048 ui.write(_('use "hg help extensions" for information on enabling '
2048 ui.write(_('use "hg help extensions" for information on enabling '
2049 'extensions\n'))
2049 'extensions\n'))
2050
2050
2051 help.addtopichook('revsets', revset.makedoc)
2051 help.addtopichook('revsets', revset.makedoc)
2052
2052
2053 if name and name != 'shortlist':
2053 if name and name != 'shortlist':
2054 i = None
2054 i = None
2055 if unknowncmd:
2055 if unknowncmd:
2056 queries = (helpextcmd,)
2056 queries = (helpextcmd,)
2057 else:
2057 else:
2058 queries = (helptopic, helpcmd, helpext, helpextcmd)
2058 queries = (helptopic, helpcmd, helpext, helpextcmd)
2059 for f in queries:
2059 for f in queries:
2060 try:
2060 try:
2061 f(name)
2061 f(name)
2062 i = None
2062 i = None
2063 break
2063 break
2064 except error.UnknownCommand, inst:
2064 except error.UnknownCommand, inst:
2065 i = inst
2065 i = inst
2066 if i:
2066 if i:
2067 raise i
2067 raise i
2068
2068
2069 else:
2069 else:
2070 # program name
2070 # program name
2071 if ui.verbose or with_version:
2071 if ui.verbose or with_version:
2072 version_(ui)
2072 version_(ui)
2073 else:
2073 else:
2074 ui.status(_("Mercurial Distributed SCM\n"))
2074 ui.status(_("Mercurial Distributed SCM\n"))
2075 ui.status('\n')
2075 ui.status('\n')
2076
2076
2077 # list of commands
2077 # list of commands
2078 if name == "shortlist":
2078 if name == "shortlist":
2079 header = _('basic commands:\n\n')
2079 header = _('basic commands:\n\n')
2080 else:
2080 else:
2081 header = _('list of commands:\n\n')
2081 header = _('list of commands:\n\n')
2082
2082
2083 helplist(header)
2083 helplist(header)
2084 if name != 'shortlist':
2084 if name != 'shortlist':
2085 exts, maxlength = extensions.enabled()
2085 exts, maxlength = extensions.enabled()
2086 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2086 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2087 if text:
2087 if text:
2088 ui.write("\n%s\n" % minirst.format(text, textwidth))
2088 ui.write("\n%s\n" % minirst.format(text, textwidth))
2089
2089
2090 # list all option lists
2090 # list all option lists
2091 opt_output = []
2091 opt_output = []
2092 multioccur = False
2092 multioccur = False
2093 for title, options in option_lists:
2093 for title, options in option_lists:
2094 opt_output.append(("\n%s" % title, None))
2094 opt_output.append(("\n%s" % title, None))
2095 for option in options:
2095 for option in options:
2096 if len(option) == 5:
2096 if len(option) == 5:
2097 shortopt, longopt, default, desc, optlabel = option
2097 shortopt, longopt, default, desc, optlabel = option
2098 else:
2098 else:
2099 shortopt, longopt, default, desc = option
2099 shortopt, longopt, default, desc = option
2100 optlabel = _("VALUE") # default label
2100 optlabel = _("VALUE") # default label
2101
2101
2102 if _("DEPRECATED") in desc and not ui.verbose:
2102 if _("DEPRECATED") in desc and not ui.verbose:
2103 continue
2103 continue
2104 if isinstance(default, list):
2104 if isinstance(default, list):
2105 numqualifier = " %s [+]" % optlabel
2105 numqualifier = " %s [+]" % optlabel
2106 multioccur = True
2106 multioccur = True
2107 elif (default is not None) and not isinstance(default, bool):
2107 elif (default is not None) and not isinstance(default, bool):
2108 numqualifier = " %s" % optlabel
2108 numqualifier = " %s" % optlabel
2109 else:
2109 else:
2110 numqualifier = ""
2110 numqualifier = ""
2111 opt_output.append(("%2s%s" %
2111 opt_output.append(("%2s%s" %
2112 (shortopt and "-%s" % shortopt,
2112 (shortopt and "-%s" % shortopt,
2113 longopt and " --%s%s" %
2113 longopt and " --%s%s" %
2114 (longopt, numqualifier)),
2114 (longopt, numqualifier)),
2115 "%s%s" % (desc,
2115 "%s%s" % (desc,
2116 default
2116 default
2117 and _(" (default: %s)") % default
2117 and _(" (default: %s)") % default
2118 or "")))
2118 or "")))
2119 if multioccur:
2119 if multioccur:
2120 msg = _("\n[+] marked option can be specified multiple times")
2120 msg = _("\n[+] marked option can be specified multiple times")
2121 if ui.verbose and name != 'shortlist':
2121 if ui.verbose and name != 'shortlist':
2122 opt_output.append((msg, None))
2122 opt_output.append((msg, None))
2123 else:
2123 else:
2124 opt_output.insert(-1, (msg, None))
2124 opt_output.insert(-1, (msg, None))
2125
2125
2126 if not name:
2126 if not name:
2127 ui.write(_("\nadditional help topics:\n\n"))
2127 ui.write(_("\nadditional help topics:\n\n"))
2128 topics = []
2128 topics = []
2129 for names, header, doc in help.helptable:
2129 for names, header, doc in help.helptable:
2130 topics.append((sorted(names, key=len, reverse=True)[0], header))
2130 topics.append((sorted(names, key=len, reverse=True)[0], header))
2131 topics_len = max([len(s[0]) for s in topics])
2131 topics_len = max([len(s[0]) for s in topics])
2132 for t, desc in topics:
2132 for t, desc in topics:
2133 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2133 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2134
2134
2135 if opt_output:
2135 if opt_output:
2136 colwidth = encoding.colwidth
2136 colwidth = encoding.colwidth
2137 # normalize: (opt or message, desc or None, width of opt)
2137 # normalize: (opt or message, desc or None, width of opt)
2138 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2138 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2139 for opt, desc in opt_output]
2139 for opt, desc in opt_output]
2140 hanging = max([e[2] for e in entries])
2140 hanging = max([e[2] for e in entries])
2141 for opt, desc, width in entries:
2141 for opt, desc, width in entries:
2142 if desc:
2142 if desc:
2143 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2143 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2144 hangindent = ' ' * (hanging + 3)
2144 hangindent = ' ' * (hanging + 3)
2145 ui.write('%s\n' % (util.wrap(desc, textwidth,
2145 ui.write('%s\n' % (util.wrap(desc, textwidth,
2146 initindent=initindent,
2146 initindent=initindent,
2147 hangindent=hangindent)))
2147 hangindent=hangindent)))
2148 else:
2148 else:
2149 ui.write("%s\n" % opt)
2149 ui.write("%s\n" % opt)
2150
2150
2151 def identify(ui, repo, source=None,
2151 def identify(ui, repo, source=None,
2152 rev=None, num=None, id=None, branch=None, tags=None):
2152 rev=None, num=None, id=None, branch=None, tags=None):
2153 """identify the working copy or specified revision
2153 """identify the working copy or specified revision
2154
2154
2155 With no revision, print a summary of the current state of the
2155 With no revision, print a summary of the current state of the
2156 repository.
2156 repository.
2157
2157
2158 Specifying a path to a repository root or Mercurial bundle will
2158 Specifying a path to a repository root or Mercurial bundle will
2159 cause lookup to operate on that repository/bundle.
2159 cause lookup to operate on that repository/bundle.
2160
2160
2161 This summary identifies the repository state using one or two
2161 This summary identifies the repository state using one or two
2162 parent hash identifiers, followed by a "+" if there are
2162 parent hash identifiers, followed by a "+" if there are
2163 uncommitted changes in the working directory, a list of tags for
2163 uncommitted changes in the working directory, a list of tags for
2164 this revision and a branch name for non-default branches.
2164 this revision and a branch name for non-default branches.
2165
2165
2166 Returns 0 if successful.
2166 Returns 0 if successful.
2167 """
2167 """
2168
2168
2169 if not repo and not source:
2169 if not repo and not source:
2170 raise util.Abort(_("there is no Mercurial repository here "
2170 raise util.Abort(_("there is no Mercurial repository here "
2171 "(.hg not found)"))
2171 "(.hg not found)"))
2172
2172
2173 hexfunc = ui.debugflag and hex or short
2173 hexfunc = ui.debugflag and hex or short
2174 default = not (num or id or branch or tags)
2174 default = not (num or id or branch or tags)
2175 output = []
2175 output = []
2176
2176
2177 revs = []
2177 revs = []
2178 if source:
2178 if source:
2179 source, branches = hg.parseurl(ui.expandpath(source))
2179 source, branches = hg.parseurl(ui.expandpath(source))
2180 repo = hg.repository(ui, source)
2180 repo = hg.repository(ui, source)
2181 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2181 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2182
2182
2183 if not repo.local():
2183 if not repo.local():
2184 if not rev and revs:
2184 if not rev and revs:
2185 rev = revs[0]
2185 rev = revs[0]
2186 if not rev:
2186 if not rev:
2187 rev = "tip"
2187 rev = "tip"
2188 if num or branch or tags:
2188 if num or branch or tags:
2189 raise util.Abort(
2189 raise util.Abort(
2190 "can't query remote revision number, branch, or tags")
2190 "can't query remote revision number, branch, or tags")
2191 output = [hexfunc(repo.lookup(rev))]
2191 output = [hexfunc(repo.lookup(rev))]
2192 elif not rev:
2192 elif not rev:
2193 ctx = repo[None]
2193 ctx = repo[None]
2194 parents = ctx.parents()
2194 parents = ctx.parents()
2195 changed = False
2195 changed = False
2196 if default or id or num:
2196 if default or id or num:
2197 changed = util.any(repo.status())
2197 changed = util.any(repo.status())
2198 if default or id:
2198 if default or id:
2199 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2199 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2200 (changed) and "+" or "")]
2200 (changed) and "+" or "")]
2201 if num:
2201 if num:
2202 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2202 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2203 (changed) and "+" or ""))
2203 (changed) and "+" or ""))
2204 else:
2204 else:
2205 ctx = cmdutil.revsingle(repo, rev)
2205 ctx = cmdutil.revsingle(repo, rev)
2206 if default or id:
2206 if default or id:
2207 output = [hexfunc(ctx.node())]
2207 output = [hexfunc(ctx.node())]
2208 if num:
2208 if num:
2209 output.append(str(ctx.rev()))
2209 output.append(str(ctx.rev()))
2210
2210
2211 if repo.local() and default and not ui.quiet:
2211 if repo.local() and default and not ui.quiet:
2212 b = encoding.tolocal(ctx.branch())
2212 b = encoding.tolocal(ctx.branch())
2213 if b != 'default':
2213 if b != 'default':
2214 output.append("(%s)" % b)
2214 output.append("(%s)" % b)
2215
2215
2216 # multiple tags for a single parent separated by '/'
2216 # multiple tags for a single parent separated by '/'
2217 t = "/".join(ctx.tags())
2217 t = "/".join(ctx.tags())
2218 if t:
2218 if t:
2219 output.append(t)
2219 output.append(t)
2220
2220
2221 if branch:
2221 if branch:
2222 output.append(encoding.tolocal(ctx.branch()))
2222 output.append(encoding.tolocal(ctx.branch()))
2223
2223
2224 if tags:
2224 if tags:
2225 output.extend(ctx.tags())
2225 output.extend(ctx.tags())
2226
2226
2227 ui.write("%s\n" % ' '.join(output))
2227 ui.write("%s\n" % ' '.join(output))
2228
2228
2229 def import_(ui, repo, patch1, *patches, **opts):
2229 def import_(ui, repo, patch1, *patches, **opts):
2230 """import an ordered set of patches
2230 """import an ordered set of patches
2231
2231
2232 Import a list of patches and commit them individually (unless
2232 Import a list of patches and commit them individually (unless
2233 --no-commit is specified).
2233 --no-commit is specified).
2234
2234
2235 If there are outstanding changes in the working directory, import
2235 If there are outstanding changes in the working directory, import
2236 will abort unless given the -f/--force flag.
2236 will abort unless given the -f/--force flag.
2237
2237
2238 You can import a patch straight from a mail message. Even patches
2238 You can import a patch straight from a mail message. Even patches
2239 as attachments work (to use the body part, it must have type
2239 as attachments work (to use the body part, it must have type
2240 text/plain or text/x-patch). From and Subject headers of email
2240 text/plain or text/x-patch). From and Subject headers of email
2241 message are used as default committer and commit message. All
2241 message are used as default committer and commit message. All
2242 text/plain body parts before first diff are added to commit
2242 text/plain body parts before first diff are added to commit
2243 message.
2243 message.
2244
2244
2245 If the imported patch was generated by :hg:`export`, user and
2245 If the imported patch was generated by :hg:`export`, user and
2246 description from patch override values from message headers and
2246 description from patch override values from message headers and
2247 body. Values given on command line with -m/--message and -u/--user
2247 body. Values given on command line with -m/--message and -u/--user
2248 override these.
2248 override these.
2249
2249
2250 If --exact is specified, import will set the working directory to
2250 If --exact is specified, import will set the working directory to
2251 the parent of each patch before applying it, and will abort if the
2251 the parent of each patch before applying it, and will abort if the
2252 resulting changeset has a different ID than the one recorded in
2252 resulting changeset has a different ID than the one recorded in
2253 the patch. This may happen due to character set problems or other
2253 the patch. This may happen due to character set problems or other
2254 deficiencies in the text patch format.
2254 deficiencies in the text patch format.
2255
2255
2256 With -s/--similarity, hg will attempt to discover renames and
2256 With -s/--similarity, hg will attempt to discover renames and
2257 copies in the patch in the same way as 'addremove'.
2257 copies in the patch in the same way as 'addremove'.
2258
2258
2259 To read a patch from standard input, use "-" as the patch name. If
2259 To read a patch from standard input, use "-" as the patch name. If
2260 a URL is specified, the patch will be downloaded from it.
2260 a URL is specified, the patch will be downloaded from it.
2261 See :hg:`help dates` for a list of formats valid for -d/--date.
2261 See :hg:`help dates` for a list of formats valid for -d/--date.
2262
2262
2263 Returns 0 on success.
2263 Returns 0 on success.
2264 """
2264 """
2265 patches = (patch1,) + patches
2265 patches = (patch1,) + patches
2266
2266
2267 date = opts.get('date')
2267 date = opts.get('date')
2268 if date:
2268 if date:
2269 opts['date'] = util.parsedate(date)
2269 opts['date'] = util.parsedate(date)
2270
2270
2271 try:
2271 try:
2272 sim = float(opts.get('similarity') or 0)
2272 sim = float(opts.get('similarity') or 0)
2273 except ValueError:
2273 except ValueError:
2274 raise util.Abort(_('similarity must be a number'))
2274 raise util.Abort(_('similarity must be a number'))
2275 if sim < 0 or sim > 100:
2275 if sim < 0 or sim > 100:
2276 raise util.Abort(_('similarity must be between 0 and 100'))
2276 raise util.Abort(_('similarity must be between 0 and 100'))
2277
2277
2278 if opts.get('exact') or not opts.get('force'):
2278 if opts.get('exact') or not opts.get('force'):
2279 cmdutil.bail_if_changed(repo)
2279 cmdutil.bail_if_changed(repo)
2280
2280
2281 d = opts["base"]
2281 d = opts["base"]
2282 strip = opts["strip"]
2282 strip = opts["strip"]
2283 wlock = lock = None
2283 wlock = lock = None
2284 msgs = []
2284 msgs = []
2285
2285
2286 def tryone(ui, hunk):
2286 def tryone(ui, hunk):
2287 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2287 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2288 patch.extract(ui, hunk)
2288 patch.extract(ui, hunk)
2289
2289
2290 if not tmpname:
2290 if not tmpname:
2291 return None
2291 return None
2292 commitid = _('to working directory')
2292 commitid = _('to working directory')
2293
2293
2294 try:
2294 try:
2295 cmdline_message = cmdutil.logmessage(opts)
2295 cmdline_message = cmdutil.logmessage(opts)
2296 if cmdline_message:
2296 if cmdline_message:
2297 # pickup the cmdline msg
2297 # pickup the cmdline msg
2298 message = cmdline_message
2298 message = cmdline_message
2299 elif message:
2299 elif message:
2300 # pickup the patch msg
2300 # pickup the patch msg
2301 message = message.strip()
2301 message = message.strip()
2302 else:
2302 else:
2303 # launch the editor
2303 # launch the editor
2304 message = None
2304 message = None
2305 ui.debug('message:\n%s\n' % message)
2305 ui.debug('message:\n%s\n' % message)
2306
2306
2307 wp = repo.parents()
2307 wp = repo.parents()
2308 if opts.get('exact'):
2308 if opts.get('exact'):
2309 if not nodeid or not p1:
2309 if not nodeid or not p1:
2310 raise util.Abort(_('not a Mercurial patch'))
2310 raise util.Abort(_('not a Mercurial patch'))
2311 p1 = repo.lookup(p1)
2311 p1 = repo.lookup(p1)
2312 p2 = repo.lookup(p2 or hex(nullid))
2312 p2 = repo.lookup(p2 or hex(nullid))
2313
2313
2314 if p1 != wp[0].node():
2314 if p1 != wp[0].node():
2315 hg.clean(repo, p1)
2315 hg.clean(repo, p1)
2316 repo.dirstate.setparents(p1, p2)
2316 repo.dirstate.setparents(p1, p2)
2317 elif p2:
2317 elif p2:
2318 try:
2318 try:
2319 p1 = repo.lookup(p1)
2319 p1 = repo.lookup(p1)
2320 p2 = repo.lookup(p2)
2320 p2 = repo.lookup(p2)
2321 if p1 == wp[0].node():
2321 if p1 == wp[0].node():
2322 repo.dirstate.setparents(p1, p2)
2322 repo.dirstate.setparents(p1, p2)
2323 except error.RepoError:
2323 except error.RepoError:
2324 pass
2324 pass
2325 if opts.get('exact') or opts.get('import_branch'):
2325 if opts.get('exact') or opts.get('import_branch'):
2326 repo.dirstate.setbranch(branch or 'default')
2326 repo.dirstate.setbranch(branch or 'default')
2327
2327
2328 files = {}
2328 files = {}
2329 try:
2329 try:
2330 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2330 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2331 files=files, eolmode=None)
2331 files=files, eolmode=None)
2332 finally:
2332 finally:
2333 files = cmdutil.updatedir(ui, repo, files,
2333 files = cmdutil.updatedir(ui, repo, files,
2334 similarity=sim / 100.0)
2334 similarity=sim / 100.0)
2335 if opts.get('no_commit'):
2335 if opts.get('no_commit'):
2336 if message:
2336 if message:
2337 msgs.append(message)
2337 msgs.append(message)
2338 else:
2338 else:
2339 if opts.get('exact'):
2339 if opts.get('exact'):
2340 m = None
2340 m = None
2341 else:
2341 else:
2342 m = cmdutil.matchfiles(repo, files or [])
2342 m = cmdutil.matchfiles(repo, files or [])
2343 n = repo.commit(message, opts.get('user') or user,
2343 n = repo.commit(message, opts.get('user') or user,
2344 opts.get('date') or date, match=m,
2344 opts.get('date') or date, match=m,
2345 editor=cmdutil.commiteditor)
2345 editor=cmdutil.commiteditor)
2346 if opts.get('exact'):
2346 if opts.get('exact'):
2347 if hex(n) != nodeid:
2347 if hex(n) != nodeid:
2348 repo.rollback()
2348 repo.rollback()
2349 raise util.Abort(_('patch is damaged'
2349 raise util.Abort(_('patch is damaged'
2350 ' or loses information'))
2350 ' or loses information'))
2351 # Force a dirstate write so that the next transaction
2351 # Force a dirstate write so that the next transaction
2352 # backups an up-do-date file.
2352 # backups an up-do-date file.
2353 repo.dirstate.write()
2353 repo.dirstate.write()
2354 if n:
2354 if n:
2355 commitid = short(n)
2355 commitid = short(n)
2356
2356
2357 return commitid
2357 return commitid
2358 finally:
2358 finally:
2359 os.unlink(tmpname)
2359 os.unlink(tmpname)
2360
2360
2361 try:
2361 try:
2362 wlock = repo.wlock()
2362 wlock = repo.wlock()
2363 lock = repo.lock()
2363 lock = repo.lock()
2364 lastcommit = None
2364 lastcommit = None
2365 for p in patches:
2365 for p in patches:
2366 pf = os.path.join(d, p)
2366 pf = os.path.join(d, p)
2367
2367
2368 if pf == '-':
2368 if pf == '-':
2369 ui.status(_("applying patch from stdin\n"))
2369 ui.status(_("applying patch from stdin\n"))
2370 pf = sys.stdin
2370 pf = sys.stdin
2371 else:
2371 else:
2372 ui.status(_("applying %s\n") % p)
2372 ui.status(_("applying %s\n") % p)
2373 pf = url.open(ui, pf)
2373 pf = url.open(ui, pf)
2374
2374
2375 haspatch = False
2375 haspatch = False
2376 for hunk in patch.split(pf):
2376 for hunk in patch.split(pf):
2377 commitid = tryone(ui, hunk)
2377 commitid = tryone(ui, hunk)
2378 if commitid:
2378 if commitid:
2379 haspatch = True
2379 haspatch = True
2380 if lastcommit:
2380 if lastcommit:
2381 ui.status(_('applied %s\n') % lastcommit)
2381 ui.status(_('applied %s\n') % lastcommit)
2382 lastcommit = commitid
2382 lastcommit = commitid
2383
2383
2384 if not haspatch:
2384 if not haspatch:
2385 raise util.Abort(_('no diffs found'))
2385 raise util.Abort(_('no diffs found'))
2386
2386
2387 if msgs:
2387 if msgs:
2388 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2388 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2389 finally:
2389 finally:
2390 release(lock, wlock)
2390 release(lock, wlock)
2391
2391
2392 def incoming(ui, repo, source="default", **opts):
2392 def incoming(ui, repo, source="default", **opts):
2393 """show new changesets found in source
2393 """show new changesets found in source
2394
2394
2395 Show new changesets found in the specified path/URL or the default
2395 Show new changesets found in the specified path/URL or the default
2396 pull location. These are the changesets that would have been pulled
2396 pull location. These are the changesets that would have been pulled
2397 if a pull at the time you issued this command.
2397 if a pull at the time you issued this command.
2398
2398
2399 For remote repository, using --bundle avoids downloading the
2399 For remote repository, using --bundle avoids downloading the
2400 changesets twice if the incoming is followed by a pull.
2400 changesets twice if the incoming is followed by a pull.
2401
2401
2402 See pull for valid source format details.
2402 See pull for valid source format details.
2403
2403
2404 Returns 0 if there are incoming changes, 1 otherwise.
2404 Returns 0 if there are incoming changes, 1 otherwise.
2405 """
2405 """
2406 if opts.get('bundle') and opts.get('subrepos'):
2406 if opts.get('bundle') and opts.get('subrepos'):
2407 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2407 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2408
2408
2409 ret = hg.incoming(ui, repo, source, opts)
2409 ret = hg.incoming(ui, repo, source, opts)
2410 return ret
2410 return ret
2411
2411
2412 def init(ui, dest=".", **opts):
2412 def init(ui, dest=".", **opts):
2413 """create a new repository in the given directory
2413 """create a new repository in the given directory
2414
2414
2415 Initialize a new repository in the given directory. If the given
2415 Initialize a new repository in the given directory. If the given
2416 directory does not exist, it will be created.
2416 directory does not exist, it will be created.
2417
2417
2418 If no directory is given, the current directory is used.
2418 If no directory is given, the current directory is used.
2419
2419
2420 It is possible to specify an ``ssh://`` URL as the destination.
2420 It is possible to specify an ``ssh://`` URL as the destination.
2421 See :hg:`help urls` for more information.
2421 See :hg:`help urls` for more information.
2422
2422
2423 Returns 0 on success.
2423 Returns 0 on success.
2424 """
2424 """
2425 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2425 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2426
2426
2427 def locate(ui, repo, *pats, **opts):
2427 def locate(ui, repo, *pats, **opts):
2428 """locate files matching specific patterns
2428 """locate files matching specific patterns
2429
2429
2430 Print files under Mercurial control in the working directory whose
2430 Print files under Mercurial control in the working directory whose
2431 names match the given patterns.
2431 names match the given patterns.
2432
2432
2433 By default, this command searches all directories in the working
2433 By default, this command searches all directories in the working
2434 directory. To search just the current directory and its
2434 directory. To search just the current directory and its
2435 subdirectories, use "--include .".
2435 subdirectories, use "--include .".
2436
2436
2437 If no patterns are given to match, this command prints the names
2437 If no patterns are given to match, this command prints the names
2438 of all files under Mercurial control in the working directory.
2438 of all files under Mercurial control in the working directory.
2439
2439
2440 If you want to feed the output of this command into the "xargs"
2440 If you want to feed the output of this command into the "xargs"
2441 command, use the -0 option to both this command and "xargs". This
2441 command, use the -0 option to both this command and "xargs". This
2442 will avoid the problem of "xargs" treating single filenames that
2442 will avoid the problem of "xargs" treating single filenames that
2443 contain whitespace as multiple filenames.
2443 contain whitespace as multiple filenames.
2444
2444
2445 Returns 0 if a match is found, 1 otherwise.
2445 Returns 0 if a match is found, 1 otherwise.
2446 """
2446 """
2447 end = opts.get('print0') and '\0' or '\n'
2447 end = opts.get('print0') and '\0' or '\n'
2448 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2448 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2449
2449
2450 ret = 1
2450 ret = 1
2451 m = cmdutil.match(repo, pats, opts, default='relglob')
2451 m = cmdutil.match(repo, pats, opts, default='relglob')
2452 m.bad = lambda x, y: False
2452 m.bad = lambda x, y: False
2453 for abs in repo[rev].walk(m):
2453 for abs in repo[rev].walk(m):
2454 if not rev and abs not in repo.dirstate:
2454 if not rev and abs not in repo.dirstate:
2455 continue
2455 continue
2456 if opts.get('fullpath'):
2456 if opts.get('fullpath'):
2457 ui.write(repo.wjoin(abs), end)
2457 ui.write(repo.wjoin(abs), end)
2458 else:
2458 else:
2459 ui.write(((pats and m.rel(abs)) or abs), end)
2459 ui.write(((pats and m.rel(abs)) or abs), end)
2460 ret = 0
2460 ret = 0
2461
2461
2462 return ret
2462 return ret
2463
2463
2464 def log(ui, repo, *pats, **opts):
2464 def log(ui, repo, *pats, **opts):
2465 """show revision history of entire repository or files
2465 """show revision history of entire repository or files
2466
2466
2467 Print the revision history of the specified files or the entire
2467 Print the revision history of the specified files or the entire
2468 project.
2468 project.
2469
2469
2470 File history is shown without following rename or copy history of
2470 File history is shown without following rename or copy history of
2471 files. Use -f/--follow with a filename to follow history across
2471 files. Use -f/--follow with a filename to follow history across
2472 renames and copies. --follow without a filename will only show
2472 renames and copies. --follow without a filename will only show
2473 ancestors or descendants of the starting revision. --follow-first
2473 ancestors or descendants of the starting revision. --follow-first
2474 only follows the first parent of merge revisions.
2474 only follows the first parent of merge revisions.
2475
2475
2476 If no revision range is specified, the default is ``tip:0`` unless
2476 If no revision range is specified, the default is ``tip:0`` unless
2477 --follow is set, in which case the working directory parent is
2477 --follow is set, in which case the working directory parent is
2478 used as the starting revision. You can specify a revision set for
2478 used as the starting revision. You can specify a revision set for
2479 log, see :hg:`help revsets` for more information.
2479 log, see :hg:`help revsets` for more information.
2480
2480
2481 See :hg:`help dates` for a list of formats valid for -d/--date.
2481 See :hg:`help dates` for a list of formats valid for -d/--date.
2482
2482
2483 By default this command prints revision number and changeset id,
2483 By default this command prints revision number and changeset id,
2484 tags, non-trivial parents, user, date and time, and a summary for
2484 tags, non-trivial parents, user, date and time, and a summary for
2485 each commit. When the -v/--verbose switch is used, the list of
2485 each commit. When the -v/--verbose switch is used, the list of
2486 changed files and full commit message are shown.
2486 changed files and full commit message are shown.
2487
2487
2488 .. note::
2488 .. note::
2489 log -p/--patch may generate unexpected diff output for merge
2489 log -p/--patch may generate unexpected diff output for merge
2490 changesets, as it will only compare the merge changeset against
2490 changesets, as it will only compare the merge changeset against
2491 its first parent. Also, only files different from BOTH parents
2491 its first parent. Also, only files different from BOTH parents
2492 will appear in files:.
2492 will appear in files:.
2493
2493
2494 Returns 0 on success.
2494 Returns 0 on success.
2495 """
2495 """
2496
2496
2497 matchfn = cmdutil.match(repo, pats, opts)
2497 matchfn = cmdutil.match(repo, pats, opts)
2498 limit = cmdutil.loglimit(opts)
2498 limit = cmdutil.loglimit(opts)
2499 count = 0
2499 count = 0
2500
2500
2501 endrev = None
2501 endrev = None
2502 if opts.get('copies') and opts.get('rev'):
2502 if opts.get('copies') and opts.get('rev'):
2503 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2503 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2504
2504
2505 df = False
2505 df = False
2506 if opts["date"]:
2506 if opts["date"]:
2507 df = util.matchdate(opts["date"])
2507 df = util.matchdate(opts["date"])
2508
2508
2509 branches = opts.get('branch', []) + opts.get('only_branch', [])
2509 branches = opts.get('branch', []) + opts.get('only_branch', [])
2510 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2510 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2511
2511
2512 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2512 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2513 def prep(ctx, fns):
2513 def prep(ctx, fns):
2514 rev = ctx.rev()
2514 rev = ctx.rev()
2515 parents = [p for p in repo.changelog.parentrevs(rev)
2515 parents = [p for p in repo.changelog.parentrevs(rev)
2516 if p != nullrev]
2516 if p != nullrev]
2517 if opts.get('no_merges') and len(parents) == 2:
2517 if opts.get('no_merges') and len(parents) == 2:
2518 return
2518 return
2519 if opts.get('only_merges') and len(parents) != 2:
2519 if opts.get('only_merges') and len(parents) != 2:
2520 return
2520 return
2521 if opts.get('branch') and ctx.branch() not in opts['branch']:
2521 if opts.get('branch') and ctx.branch() not in opts['branch']:
2522 return
2522 return
2523 if df and not df(ctx.date()[0]):
2523 if df and not df(ctx.date()[0]):
2524 return
2524 return
2525 if opts['user'] and not [k for k in opts['user']
2525 if opts['user'] and not [k for k in opts['user']
2526 if k.lower() in ctx.user().lower()]:
2526 if k.lower() in ctx.user().lower()]:
2527 return
2527 return
2528 if opts.get('keyword'):
2528 if opts.get('keyword'):
2529 for k in [kw.lower() for kw in opts['keyword']]:
2529 for k in [kw.lower() for kw in opts['keyword']]:
2530 if (k in ctx.user().lower() or
2530 if (k in ctx.user().lower() or
2531 k in ctx.description().lower() or
2531 k in ctx.description().lower() or
2532 k in " ".join(ctx.files()).lower()):
2532 k in " ".join(ctx.files()).lower()):
2533 break
2533 break
2534 else:
2534 else:
2535 return
2535 return
2536
2536
2537 copies = None
2537 copies = None
2538 if opts.get('copies') and rev:
2538 if opts.get('copies') and rev:
2539 copies = []
2539 copies = []
2540 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2540 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2541 for fn in ctx.files():
2541 for fn in ctx.files():
2542 rename = getrenamed(fn, rev)
2542 rename = getrenamed(fn, rev)
2543 if rename:
2543 if rename:
2544 copies.append((fn, rename[0]))
2544 copies.append((fn, rename[0]))
2545
2545
2546 revmatchfn = None
2546 revmatchfn = None
2547 if opts.get('patch') or opts.get('stat'):
2547 if opts.get('patch') or opts.get('stat'):
2548 if opts.get('follow') or opts.get('follow_first'):
2548 if opts.get('follow') or opts.get('follow_first'):
2549 # note: this might be wrong when following through merges
2549 # note: this might be wrong when following through merges
2550 revmatchfn = cmdutil.match(repo, fns, default='path')
2550 revmatchfn = cmdutil.match(repo, fns, default='path')
2551 else:
2551 else:
2552 revmatchfn = matchfn
2552 revmatchfn = matchfn
2553
2553
2554 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2554 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2555
2555
2556 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2556 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2557 if count == limit:
2557 if count == limit:
2558 break
2558 break
2559 if displayer.flush(ctx.rev()):
2559 if displayer.flush(ctx.rev()):
2560 count += 1
2560 count += 1
2561 displayer.close()
2561 displayer.close()
2562
2562
2563 def manifest(ui, repo, node=None, rev=None):
2563 def manifest(ui, repo, node=None, rev=None):
2564 """output the current or given revision of the project manifest
2564 """output the current or given revision of the project manifest
2565
2565
2566 Print a list of version controlled files for the given revision.
2566 Print a list of version controlled files for the given revision.
2567 If no revision is given, the first parent of the working directory
2567 If no revision is given, the first parent of the working directory
2568 is used, or the null revision if no revision is checked out.
2568 is used, or the null revision if no revision is checked out.
2569
2569
2570 With -v, print file permissions, symlink and executable bits.
2570 With -v, print file permissions, symlink and executable bits.
2571 With --debug, print file revision hashes.
2571 With --debug, print file revision hashes.
2572
2572
2573 Returns 0 on success.
2573 Returns 0 on success.
2574 """
2574 """
2575
2575
2576 if rev and node:
2576 if rev and node:
2577 raise util.Abort(_("please specify just one revision"))
2577 raise util.Abort(_("please specify just one revision"))
2578
2578
2579 if not node:
2579 if not node:
2580 node = rev
2580 node = rev
2581
2581
2582 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2582 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2583 ctx = cmdutil.revsingle(repo, node)
2583 ctx = cmdutil.revsingle(repo, node)
2584 for f in ctx:
2584 for f in ctx:
2585 if ui.debugflag:
2585 if ui.debugflag:
2586 ui.write("%40s " % hex(ctx.manifest()[f]))
2586 ui.write("%40s " % hex(ctx.manifest()[f]))
2587 if ui.verbose:
2587 if ui.verbose:
2588 ui.write(decor[ctx.flags(f)])
2588 ui.write(decor[ctx.flags(f)])
2589 ui.write("%s\n" % f)
2589 ui.write("%s\n" % f)
2590
2590
2591 def merge(ui, repo, node=None, **opts):
2591 def merge(ui, repo, node=None, **opts):
2592 """merge working directory with another revision
2592 """merge working directory with another revision
2593
2593
2594 The current working directory is updated with all changes made in
2594 The current working directory is updated with all changes made in
2595 the requested revision since the last common predecessor revision.
2595 the requested revision since the last common predecessor revision.
2596
2596
2597 Files that changed between either parent are marked as changed for
2597 Files that changed between either parent are marked as changed for
2598 the next commit and a commit must be performed before any further
2598 the next commit and a commit must be performed before any further
2599 updates to the repository are allowed. The next commit will have
2599 updates to the repository are allowed. The next commit will have
2600 two parents.
2600 two parents.
2601
2601
2602 ``--tool`` can be used to specify the merge tool used for file
2602 ``--tool`` can be used to specify the merge tool used for file
2603 merges. It overrides the HGMERGE environment variable and your
2603 merges. It overrides the HGMERGE environment variable and your
2604 configuration files.
2604 configuration files.
2605
2605
2606 If no revision is specified, the working directory's parent is a
2606 If no revision is specified, the working directory's parent is a
2607 head revision, and the current branch contains exactly one other
2607 head revision, and the current branch contains exactly one other
2608 head, the other head is merged with by default. Otherwise, an
2608 head, the other head is merged with by default. Otherwise, an
2609 explicit revision with which to merge with must be provided.
2609 explicit revision with which to merge with must be provided.
2610
2610
2611 :hg:`resolve` must be used to resolve unresolved files.
2611 :hg:`resolve` must be used to resolve unresolved files.
2612
2612
2613 To undo an uncommitted merge, use :hg:`update --clean .` which
2613 To undo an uncommitted merge, use :hg:`update --clean .` which
2614 will check out a clean copy of the original merge parent, losing
2614 will check out a clean copy of the original merge parent, losing
2615 all changes.
2615 all changes.
2616
2616
2617 Returns 0 on success, 1 if there are unresolved files.
2617 Returns 0 on success, 1 if there are unresolved files.
2618 """
2618 """
2619
2619
2620 if opts.get('rev') and node:
2620 if opts.get('rev') and node:
2621 raise util.Abort(_("please specify just one revision"))
2621 raise util.Abort(_("please specify just one revision"))
2622 if not node:
2622 if not node:
2623 node = opts.get('rev')
2623 node = opts.get('rev')
2624
2624
2625 if not node:
2625 if not node:
2626 branch = repo.changectx(None).branch()
2626 branch = repo.changectx(None).branch()
2627 bheads = repo.branchheads(branch)
2627 bheads = repo.branchheads(branch)
2628 if len(bheads) > 2:
2628 if len(bheads) > 2:
2629 raise util.Abort(_(
2629 raise util.Abort(_(
2630 'branch \'%s\' has %d heads - '
2630 'branch \'%s\' has %d heads - '
2631 'please merge with an explicit rev\n'
2631 'please merge with an explicit rev\n'
2632 '(run \'hg heads .\' to see heads)')
2632 '(run \'hg heads .\' to see heads)')
2633 % (branch, len(bheads)))
2633 % (branch, len(bheads)))
2634
2634
2635 parent = repo.dirstate.parents()[0]
2635 parent = repo.dirstate.parents()[0]
2636 if len(bheads) == 1:
2636 if len(bheads) == 1:
2637 if len(repo.heads()) > 1:
2637 if len(repo.heads()) > 1:
2638 raise util.Abort(_(
2638 raise util.Abort(_(
2639 'branch \'%s\' has one head - '
2639 'branch \'%s\' has one head - '
2640 'please merge with an explicit rev\n'
2640 'please merge with an explicit rev\n'
2641 '(run \'hg heads\' to see all heads)')
2641 '(run \'hg heads\' to see all heads)')
2642 % branch)
2642 % branch)
2643 msg = _('there is nothing to merge')
2643 msg = _('there is nothing to merge')
2644 if parent != repo.lookup(repo[None].branch()):
2644 if parent != repo.lookup(repo[None].branch()):
2645 msg = _('%s - use "hg update" instead') % msg
2645 msg = _('%s - use "hg update" instead') % msg
2646 raise util.Abort(msg)
2646 raise util.Abort(msg)
2647
2647
2648 if parent not in bheads:
2648 if parent not in bheads:
2649 raise util.Abort(_('working dir not at a head rev - '
2649 raise util.Abort(_('working dir not at a head rev - '
2650 'use "hg update" or merge with an explicit rev'))
2650 'use "hg update" or merge with an explicit rev'))
2651 node = parent == bheads[0] and bheads[-1] or bheads[0]
2651 node = parent == bheads[0] and bheads[-1] or bheads[0]
2652 else:
2652 else:
2653 node = cmdutil.revsingle(repo, node).node()
2653 node = cmdutil.revsingle(repo, node).node()
2654
2654
2655 if opts.get('preview'):
2655 if opts.get('preview'):
2656 # find nodes that are ancestors of p2 but not of p1
2656 # find nodes that are ancestors of p2 but not of p1
2657 p1 = repo.lookup('.')
2657 p1 = repo.lookup('.')
2658 p2 = repo.lookup(node)
2658 p2 = repo.lookup(node)
2659 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2659 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2660
2660
2661 displayer = cmdutil.show_changeset(ui, repo, opts)
2661 displayer = cmdutil.show_changeset(ui, repo, opts)
2662 for node in nodes:
2662 for node in nodes:
2663 displayer.show(repo[node])
2663 displayer.show(repo[node])
2664 displayer.close()
2664 displayer.close()
2665 return 0
2665 return 0
2666
2666
2667 try:
2667 try:
2668 # ui.forcemerge is an internal variable, do not document
2668 # ui.forcemerge is an internal variable, do not document
2669 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2669 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2670 return hg.merge(repo, node, force=opts.get('force'))
2670 return hg.merge(repo, node, force=opts.get('force'))
2671 finally:
2671 finally:
2672 ui.setconfig('ui', 'forcemerge', '')
2672 ui.setconfig('ui', 'forcemerge', '')
2673
2673
2674 def outgoing(ui, repo, dest=None, **opts):
2674 def outgoing(ui, repo, dest=None, **opts):
2675 """show changesets not found in the destination
2675 """show changesets not found in the destination
2676
2676
2677 Show changesets not found in the specified destination repository
2677 Show changesets not found in the specified destination repository
2678 or the default push location. These are the changesets that would
2678 or the default push location. These are the changesets that would
2679 be pushed if a push was requested.
2679 be pushed if a push was requested.
2680
2680
2681 See pull for details of valid destination formats.
2681 See pull for details of valid destination formats.
2682
2682
2683 Returns 0 if there are outgoing changes, 1 otherwise.
2683 Returns 0 if there are outgoing changes, 1 otherwise.
2684 """
2684 """
2685 ret = hg.outgoing(ui, repo, dest, opts)
2685 ret = hg.outgoing(ui, repo, dest, opts)
2686 return ret
2686 return ret
2687
2687
2688 def parents(ui, repo, file_=None, **opts):
2688 def parents(ui, repo, file_=None, **opts):
2689 """show the parents of the working directory or revision
2689 """show the parents of the working directory or revision
2690
2690
2691 Print the working directory's parent revisions. If a revision is
2691 Print the working directory's parent revisions. If a revision is
2692 given via -r/--rev, the parent of that revision will be printed.
2692 given via -r/--rev, the parent of that revision will be printed.
2693 If a file argument is given, the revision in which the file was
2693 If a file argument is given, the revision in which the file was
2694 last changed (before the working directory revision or the
2694 last changed (before the working directory revision or the
2695 argument to --rev if given) is printed.
2695 argument to --rev if given) is printed.
2696
2696
2697 Returns 0 on success.
2697 Returns 0 on success.
2698 """
2698 """
2699
2699
2700 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2700 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2701
2701
2702 if file_:
2702 if file_:
2703 m = cmdutil.match(repo, (file_,), opts)
2703 m = cmdutil.match(repo, (file_,), opts)
2704 if m.anypats() or len(m.files()) != 1:
2704 if m.anypats() or len(m.files()) != 1:
2705 raise util.Abort(_('can only specify an explicit filename'))
2705 raise util.Abort(_('can only specify an explicit filename'))
2706 file_ = m.files()[0]
2706 file_ = m.files()[0]
2707 filenodes = []
2707 filenodes = []
2708 for cp in ctx.parents():
2708 for cp in ctx.parents():
2709 if not cp:
2709 if not cp:
2710 continue
2710 continue
2711 try:
2711 try:
2712 filenodes.append(cp.filenode(file_))
2712 filenodes.append(cp.filenode(file_))
2713 except error.LookupError:
2713 except error.LookupError:
2714 pass
2714 pass
2715 if not filenodes:
2715 if not filenodes:
2716 raise util.Abort(_("'%s' not found in manifest!") % file_)
2716 raise util.Abort(_("'%s' not found in manifest!") % file_)
2717 fl = repo.file(file_)
2717 fl = repo.file(file_)
2718 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2718 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2719 else:
2719 else:
2720 p = [cp.node() for cp in ctx.parents()]
2720 p = [cp.node() for cp in ctx.parents()]
2721
2721
2722 displayer = cmdutil.show_changeset(ui, repo, opts)
2722 displayer = cmdutil.show_changeset(ui, repo, opts)
2723 for n in p:
2723 for n in p:
2724 if n != nullid:
2724 if n != nullid:
2725 displayer.show(repo[n])
2725 displayer.show(repo[n])
2726 displayer.close()
2726 displayer.close()
2727
2727
2728 def paths(ui, repo, search=None):
2728 def paths(ui, repo, search=None):
2729 """show aliases for remote repositories
2729 """show aliases for remote repositories
2730
2730
2731 Show definition of symbolic path name NAME. If no name is given,
2731 Show definition of symbolic path name NAME. If no name is given,
2732 show definition of all available names.
2732 show definition of all available names.
2733
2733
2734 Path names are defined in the [paths] section of your
2734 Path names are defined in the [paths] section of your
2735 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2735 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2736 repository, ``.hg/hgrc`` is used, too.
2736 repository, ``.hg/hgrc`` is used, too.
2737
2737
2738 The path names ``default`` and ``default-push`` have a special
2738 The path names ``default`` and ``default-push`` have a special
2739 meaning. When performing a push or pull operation, they are used
2739 meaning. When performing a push or pull operation, they are used
2740 as fallbacks if no location is specified on the command-line.
2740 as fallbacks if no location is specified on the command-line.
2741 When ``default-push`` is set, it will be used for push and
2741 When ``default-push`` is set, it will be used for push and
2742 ``default`` will be used for pull; otherwise ``default`` is used
2742 ``default`` will be used for pull; otherwise ``default`` is used
2743 as the fallback for both. When cloning a repository, the clone
2743 as the fallback for both. When cloning a repository, the clone
2744 source is written as ``default`` in ``.hg/hgrc``. Note that
2744 source is written as ``default`` in ``.hg/hgrc``. Note that
2745 ``default`` and ``default-push`` apply to all inbound (e.g.
2745 ``default`` and ``default-push`` apply to all inbound (e.g.
2746 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2746 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2747 :hg:`bundle`) operations.
2747 :hg:`bundle`) operations.
2748
2748
2749 See :hg:`help urls` for more information.
2749 See :hg:`help urls` for more information.
2750
2750
2751 Returns 0 on success.
2751 Returns 0 on success.
2752 """
2752 """
2753 if search:
2753 if search:
2754 for name, path in ui.configitems("paths"):
2754 for name, path in ui.configitems("paths"):
2755 if name == search:
2755 if name == search:
2756 ui.write("%s\n" % url.hidepassword(path))
2756 ui.write("%s\n" % url.hidepassword(path))
2757 return
2757 return
2758 ui.warn(_("not found!\n"))
2758 ui.warn(_("not found!\n"))
2759 return 1
2759 return 1
2760 else:
2760 else:
2761 for name, path in ui.configitems("paths"):
2761 for name, path in ui.configitems("paths"):
2762 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2762 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2763
2763
2764 def postincoming(ui, repo, modheads, optupdate, checkout):
2764 def postincoming(ui, repo, modheads, optupdate, checkout):
2765 if modheads == 0:
2765 if modheads == 0:
2766 return
2766 return
2767 if optupdate:
2767 if optupdate:
2768 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2768 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2769 return hg.update(repo, checkout)
2769 return hg.update(repo, checkout)
2770 else:
2770 else:
2771 ui.status(_("not updating, since new heads added\n"))
2771 ui.status(_("not updating, since new heads added\n"))
2772 if modheads > 1:
2772 if modheads > 1:
2773 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2773 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2774 else:
2774 else:
2775 ui.status(_("(run 'hg update' to get a working copy)\n"))
2775 ui.status(_("(run 'hg update' to get a working copy)\n"))
2776
2776
2777 def pull(ui, repo, source="default", **opts):
2777 def pull(ui, repo, source="default", **opts):
2778 """pull changes from the specified source
2778 """pull changes from the specified source
2779
2779
2780 Pull changes from a remote repository to a local one.
2780 Pull changes from a remote repository to a local one.
2781
2781
2782 This finds all changes from the repository at the specified path
2782 This finds all changes from the repository at the specified path
2783 or URL and adds them to a local repository (the current one unless
2783 or URL and adds them to a local repository (the current one unless
2784 -R is specified). By default, this does not update the copy of the
2784 -R is specified). By default, this does not update the copy of the
2785 project in the working directory.
2785 project in the working directory.
2786
2786
2787 Use :hg:`incoming` if you want to see what would have been added
2787 Use :hg:`incoming` if you want to see what would have been added
2788 by a pull at the time you issued this command. If you then decide
2788 by a pull at the time you issued this command. If you then decide
2789 to add those changes to the repository, you should use :hg:`pull
2789 to add those changes to the repository, you should use :hg:`pull
2790 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2790 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2791
2791
2792 If SOURCE is omitted, the 'default' path will be used.
2792 If SOURCE is omitted, the 'default' path will be used.
2793 See :hg:`help urls` for more information.
2793 See :hg:`help urls` for more information.
2794
2794
2795 Returns 0 on success, 1 if an update had unresolved files.
2795 Returns 0 on success, 1 if an update had unresolved files.
2796 """
2796 """
2797 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2797 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2798 other = hg.repository(hg.remoteui(repo, opts), source)
2798 other = hg.repository(hg.remoteui(repo, opts), source)
2799 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2799 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2800 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2800 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2801 if revs:
2801 if revs:
2802 try:
2802 try:
2803 revs = [other.lookup(rev) for rev in revs]
2803 revs = [other.lookup(rev) for rev in revs]
2804 except error.CapabilityError:
2804 except error.CapabilityError:
2805 err = _("other repository doesn't support revision lookup, "
2805 err = _("other repository doesn't support revision lookup, "
2806 "so a rev cannot be specified.")
2806 "so a rev cannot be specified.")
2807 raise util.Abort(err)
2807 raise util.Abort(err)
2808
2808
2809 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2809 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2810 if checkout:
2810 if checkout:
2811 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2811 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2812 repo._subtoppath = source
2812 repo._subtoppath = source
2813 try:
2813 try:
2814 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2814 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2815 finally:
2815 finally:
2816 del repo._subtoppath
2816 del repo._subtoppath
2817
2817
2818 def push(ui, repo, dest=None, **opts):
2818 def push(ui, repo, dest=None, **opts):
2819 """push changes to the specified destination
2819 """push changes to the specified destination
2820
2820
2821 Push changesets from the local repository to the specified
2821 Push changesets from the local repository to the specified
2822 destination.
2822 destination.
2823
2823
2824 This operation is symmetrical to pull: it is identical to a pull
2824 This operation is symmetrical to pull: it is identical to a pull
2825 in the destination repository from the current one.
2825 in the destination repository from the current one.
2826
2826
2827 By default, push will not allow creation of new heads at the
2827 By default, push will not allow creation of new heads at the
2828 destination, since multiple heads would make it unclear which head
2828 destination, since multiple heads would make it unclear which head
2829 to use. In this situation, it is recommended to pull and merge
2829 to use. In this situation, it is recommended to pull and merge
2830 before pushing.
2830 before pushing.
2831
2831
2832 Use --new-branch if you want to allow push to create a new named
2832 Use --new-branch if you want to allow push to create a new named
2833 branch that is not present at the destination. This allows you to
2833 branch that is not present at the destination. This allows you to
2834 only create a new branch without forcing other changes.
2834 only create a new branch without forcing other changes.
2835
2835
2836 Use -f/--force to override the default behavior and push all
2836 Use -f/--force to override the default behavior and push all
2837 changesets on all branches.
2837 changesets on all branches.
2838
2838
2839 If -r/--rev is used, the specified revision and all its ancestors
2839 If -r/--rev is used, the specified revision and all its ancestors
2840 will be pushed to the remote repository.
2840 will be pushed to the remote repository.
2841
2841
2842 Please see :hg:`help urls` for important details about ``ssh://``
2842 Please see :hg:`help urls` for important details about ``ssh://``
2843 URLs. If DESTINATION is omitted, a default path will be used.
2843 URLs. If DESTINATION is omitted, a default path will be used.
2844
2844
2845 Returns 0 if push was successful, 1 if nothing to push.
2845 Returns 0 if push was successful, 1 if nothing to push.
2846 """
2846 """
2847 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2847 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2848 dest, branches = hg.parseurl(dest, opts.get('branch'))
2848 dest, branches = hg.parseurl(dest, opts.get('branch'))
2849 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2849 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2850 other = hg.repository(hg.remoteui(repo, opts), dest)
2850 other = hg.repository(hg.remoteui(repo, opts), dest)
2851 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2851 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2852 if revs:
2852 if revs:
2853 revs = [repo.lookup(rev) for rev in revs]
2853 revs = [repo.lookup(rev) for rev in revs]
2854
2854
2855 repo._subtoppath = dest
2855 repo._subtoppath = dest
2856 try:
2856 try:
2857 # push subrepos depth-first for coherent ordering
2857 # push subrepos depth-first for coherent ordering
2858 c = repo['']
2858 c = repo['']
2859 subs = c.substate # only repos that are committed
2859 subs = c.substate # only repos that are committed
2860 for s in sorted(subs):
2860 for s in sorted(subs):
2861 if not c.sub(s).push(opts.get('force')):
2861 if not c.sub(s).push(opts.get('force')):
2862 return False
2862 return False
2863 finally:
2863 finally:
2864 del repo._subtoppath
2864 del repo._subtoppath
2865 r = repo.push(other, opts.get('force'), revs=revs,
2865 r = repo.push(other, opts.get('force'), revs=revs,
2866 newbranch=opts.get('new_branch'))
2866 newbranch=opts.get('new_branch'))
2867 return r == 0
2867 return r == 0
2868
2868
2869 def recover(ui, repo):
2869 def recover(ui, repo):
2870 """roll back an interrupted transaction
2870 """roll back an interrupted transaction
2871
2871
2872 Recover from an interrupted commit or pull.
2872 Recover from an interrupted commit or pull.
2873
2873
2874 This command tries to fix the repository status after an
2874 This command tries to fix the repository status after an
2875 interrupted operation. It should only be necessary when Mercurial
2875 interrupted operation. It should only be necessary when Mercurial
2876 suggests it.
2876 suggests it.
2877
2877
2878 Returns 0 if successful, 1 if nothing to recover or verify fails.
2878 Returns 0 if successful, 1 if nothing to recover or verify fails.
2879 """
2879 """
2880 if repo.recover():
2880 if repo.recover():
2881 return hg.verify(repo)
2881 return hg.verify(repo)
2882 return 1
2882 return 1
2883
2883
2884 def remove(ui, repo, *pats, **opts):
2884 def remove(ui, repo, *pats, **opts):
2885 """remove the specified files on the next commit
2885 """remove the specified files on the next commit
2886
2886
2887 Schedule the indicated files for removal from the repository.
2887 Schedule the indicated files for removal from the repository.
2888
2888
2889 This only removes files from the current branch, not from the
2889 This only removes files from the current branch, not from the
2890 entire project history. -A/--after can be used to remove only
2890 entire project history. -A/--after can be used to remove only
2891 files that have already been deleted, -f/--force can be used to
2891 files that have already been deleted, -f/--force can be used to
2892 force deletion, and -Af can be used to remove files from the next
2892 force deletion, and -Af can be used to remove files from the next
2893 revision without deleting them from the working directory.
2893 revision without deleting them from the working directory.
2894
2894
2895 The following table details the behavior of remove for different
2895 The following table details the behavior of remove for different
2896 file states (columns) and option combinations (rows). The file
2896 file states (columns) and option combinations (rows). The file
2897 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2897 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2898 reported by :hg:`status`). The actions are Warn, Remove (from
2898 reported by :hg:`status`). The actions are Warn, Remove (from
2899 branch) and Delete (from disk)::
2899 branch) and Delete (from disk)::
2900
2900
2901 A C M !
2901 A C M !
2902 none W RD W R
2902 none W RD W R
2903 -f R RD RD R
2903 -f R RD RD R
2904 -A W W W R
2904 -A W W W R
2905 -Af R R R R
2905 -Af R R R R
2906
2906
2907 This command schedules the files to be removed at the next commit.
2907 This command schedules the files to be removed at the next commit.
2908 To undo a remove before that, see :hg:`revert`.
2908 To undo a remove before that, see :hg:`revert`.
2909
2909
2910 Returns 0 on success, 1 if any warnings encountered.
2910 Returns 0 on success, 1 if any warnings encountered.
2911 """
2911 """
2912
2912
2913 ret = 0
2913 ret = 0
2914 after, force = opts.get('after'), opts.get('force')
2914 after, force = opts.get('after'), opts.get('force')
2915 if not pats and not after:
2915 if not pats and not after:
2916 raise util.Abort(_('no files specified'))
2916 raise util.Abort(_('no files specified'))
2917
2917
2918 m = cmdutil.match(repo, pats, opts)
2918 m = cmdutil.match(repo, pats, opts)
2919 s = repo.status(match=m, clean=True)
2919 s = repo.status(match=m, clean=True)
2920 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2920 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2921
2921
2922 for f in m.files():
2922 for f in m.files():
2923 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2923 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2924 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2924 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2925 ret = 1
2925 ret = 1
2926
2926
2927 if force:
2927 if force:
2928 remove, forget = modified + deleted + clean, added
2928 remove, forget = modified + deleted + clean, added
2929 elif after:
2929 elif after:
2930 remove, forget = deleted, []
2930 remove, forget = deleted, []
2931 for f in modified + added + clean:
2931 for f in modified + added + clean:
2932 ui.warn(_('not removing %s: file still exists (use -f'
2932 ui.warn(_('not removing %s: file still exists (use -f'
2933 ' to force removal)\n') % m.rel(f))
2933 ' to force removal)\n') % m.rel(f))
2934 ret = 1
2934 ret = 1
2935 else:
2935 else:
2936 remove, forget = deleted + clean, []
2936 remove, forget = deleted + clean, []
2937 for f in modified:
2937 for f in modified:
2938 ui.warn(_('not removing %s: file is modified (use -f'
2938 ui.warn(_('not removing %s: file is modified (use -f'
2939 ' to force removal)\n') % m.rel(f))
2939 ' to force removal)\n') % m.rel(f))
2940 ret = 1
2940 ret = 1
2941 for f in added:
2941 for f in added:
2942 ui.warn(_('not removing %s: file has been marked for add (use -f'
2942 ui.warn(_('not removing %s: file has been marked for add (use -f'
2943 ' to force removal)\n') % m.rel(f))
2943 ' to force removal)\n') % m.rel(f))
2944 ret = 1
2944 ret = 1
2945
2945
2946 for f in sorted(remove + forget):
2946 for f in sorted(remove + forget):
2947 if ui.verbose or not m.exact(f):
2947 if ui.verbose or not m.exact(f):
2948 ui.status(_('removing %s\n') % m.rel(f))
2948 ui.status(_('removing %s\n') % m.rel(f))
2949
2949
2950 repo[None].forget(forget)
2950 repo[None].forget(forget)
2951 repo[None].remove(remove, unlink=not after)
2951 repo[None].remove(remove, unlink=not after)
2952 return ret
2952 return ret
2953
2953
2954 def rename(ui, repo, *pats, **opts):
2954 def rename(ui, repo, *pats, **opts):
2955 """rename files; equivalent of copy + remove
2955 """rename files; equivalent of copy + remove
2956
2956
2957 Mark dest as copies of sources; mark sources for deletion. If dest
2957 Mark dest as copies of sources; mark sources for deletion. If dest
2958 is a directory, copies are put in that directory. If dest is a
2958 is a directory, copies are put in that directory. If dest is a
2959 file, there can only be one source.
2959 file, there can only be one source.
2960
2960
2961 By default, this command copies the contents of files as they
2961 By default, this command copies the contents of files as they
2962 exist in the working directory. If invoked with -A/--after, the
2962 exist in the working directory. If invoked with -A/--after, the
2963 operation is recorded, but no copying is performed.
2963 operation is recorded, but no copying is performed.
2964
2964
2965 This command takes effect at the next commit. To undo a rename
2965 This command takes effect at the next commit. To undo a rename
2966 before that, see :hg:`revert`.
2966 before that, see :hg:`revert`.
2967
2967
2968 Returns 0 on success, 1 if errors are encountered.
2968 Returns 0 on success, 1 if errors are encountered.
2969 """
2969 """
2970 wlock = repo.wlock(False)
2970 wlock = repo.wlock(False)
2971 try:
2971 try:
2972 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2972 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2973 finally:
2973 finally:
2974 wlock.release()
2974 wlock.release()
2975
2975
2976 def resolve(ui, repo, *pats, **opts):
2976 def resolve(ui, repo, *pats, **opts):
2977 """redo merges or set/view the merge status of files
2977 """redo merges or set/view the merge status of files
2978
2978
2979 Merges with unresolved conflicts are often the result of
2979 Merges with unresolved conflicts are often the result of
2980 non-interactive merging using the ``internal:merge`` configuration
2980 non-interactive merging using the ``internal:merge`` configuration
2981 setting, or a command-line merge tool like ``diff3``. The resolve
2981 setting, or a command-line merge tool like ``diff3``. The resolve
2982 command is used to manage the files involved in a merge, after
2982 command is used to manage the files involved in a merge, after
2983 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2983 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2984 working directory must have two parents).
2984 working directory must have two parents).
2985
2985
2986 The resolve command can be used in the following ways:
2986 The resolve command can be used in the following ways:
2987
2987
2988 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
2988 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
2989 files, discarding any previous merge attempts. Re-merging is not
2989 files, discarding any previous merge attempts. Re-merging is not
2990 performed for files already marked as resolved. Use ``--all/-a``
2990 performed for files already marked as resolved. Use ``--all/-a``
2991 to selects all unresolved files. ``--tool`` can be used to specify
2991 to selects all unresolved files. ``--tool`` can be used to specify
2992 the merge tool used for the given files. It overrides the HGMERGE
2992 the merge tool used for the given files. It overrides the HGMERGE
2993 environment variable and your configuration files.
2993 environment variable and your configuration files.
2994
2994
2995 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2995 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2996 (e.g. after having manually fixed-up the files). The default is
2996 (e.g. after having manually fixed-up the files). The default is
2997 to mark all unresolved files.
2997 to mark all unresolved files.
2998
2998
2999 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2999 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3000 default is to mark all resolved files.
3000 default is to mark all resolved files.
3001
3001
3002 - :hg:`resolve -l`: list files which had or still have conflicts.
3002 - :hg:`resolve -l`: list files which had or still have conflicts.
3003 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3003 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3004
3004
3005 Note that Mercurial will not let you commit files with unresolved
3005 Note that Mercurial will not let you commit files with unresolved
3006 merge conflicts. You must use :hg:`resolve -m ...` before you can
3006 merge conflicts. You must use :hg:`resolve -m ...` before you can
3007 commit after a conflicting merge.
3007 commit after a conflicting merge.
3008
3008
3009 Returns 0 on success, 1 if any files fail a resolve attempt.
3009 Returns 0 on success, 1 if any files fail a resolve attempt.
3010 """
3010 """
3011
3011
3012 all, mark, unmark, show, nostatus = \
3012 all, mark, unmark, show, nostatus = \
3013 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3013 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3014
3014
3015 if (show and (mark or unmark)) or (mark and unmark):
3015 if (show and (mark or unmark)) or (mark and unmark):
3016 raise util.Abort(_("too many options specified"))
3016 raise util.Abort(_("too many options specified"))
3017 if pats and all:
3017 if pats and all:
3018 raise util.Abort(_("can't specify --all and patterns"))
3018 raise util.Abort(_("can't specify --all and patterns"))
3019 if not (all or pats or show or mark or unmark):
3019 if not (all or pats or show or mark or unmark):
3020 raise util.Abort(_('no files or directories specified; '
3020 raise util.Abort(_('no files or directories specified; '
3021 'use --all to remerge all files'))
3021 'use --all to remerge all files'))
3022
3022
3023 ms = mergemod.mergestate(repo)
3023 ms = mergemod.mergestate(repo)
3024 m = cmdutil.match(repo, pats, opts)
3024 m = cmdutil.match(repo, pats, opts)
3025 ret = 0
3025 ret = 0
3026
3026
3027 for f in ms:
3027 for f in ms:
3028 if m(f):
3028 if m(f):
3029 if show:
3029 if show:
3030 if nostatus:
3030 if nostatus:
3031 ui.write("%s\n" % f)
3031 ui.write("%s\n" % f)
3032 else:
3032 else:
3033 ui.write("%s %s\n" % (ms[f].upper(), f),
3033 ui.write("%s %s\n" % (ms[f].upper(), f),
3034 label='resolve.' +
3034 label='resolve.' +
3035 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3035 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3036 elif mark:
3036 elif mark:
3037 ms.mark(f, "r")
3037 ms.mark(f, "r")
3038 elif unmark:
3038 elif unmark:
3039 ms.mark(f, "u")
3039 ms.mark(f, "u")
3040 else:
3040 else:
3041 wctx = repo[None]
3041 wctx = repo[None]
3042 mctx = wctx.parents()[-1]
3042 mctx = wctx.parents()[-1]
3043
3043
3044 # backup pre-resolve (merge uses .orig for its own purposes)
3044 # backup pre-resolve (merge uses .orig for its own purposes)
3045 a = repo.wjoin(f)
3045 a = repo.wjoin(f)
3046 util.copyfile(a, a + ".resolve")
3046 util.copyfile(a, a + ".resolve")
3047
3047
3048 try:
3048 try:
3049 # resolve file
3049 # resolve file
3050 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3050 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3051 if ms.resolve(f, wctx, mctx):
3051 if ms.resolve(f, wctx, mctx):
3052 ret = 1
3052 ret = 1
3053 finally:
3053 finally:
3054 ui.setconfig('ui', 'forcemerge', '')
3054 ui.setconfig('ui', 'forcemerge', '')
3055
3055
3056 # replace filemerge's .orig file with our resolve file
3056 # replace filemerge's .orig file with our resolve file
3057 util.rename(a + ".resolve", a + ".orig")
3057 util.rename(a + ".resolve", a + ".orig")
3058
3058
3059 ms.commit()
3059 ms.commit()
3060 return ret
3060 return ret
3061
3061
3062 def revert(ui, repo, *pats, **opts):
3062 def revert(ui, repo, *pats, **opts):
3063 """restore individual files or directories to an earlier state
3063 """restore individual files or directories to an earlier state
3064
3064
3065 .. note::
3065 .. note::
3066 This command is most likely not what you are looking for.
3066 This command is most likely not what you are looking for.
3067 Revert will partially overwrite content in the working
3067 Revert will partially overwrite content in the working
3068 directory without changing the working directory parents. Use
3068 directory without changing the working directory parents. Use
3069 :hg:`update -r rev` to check out earlier revisions, or
3069 :hg:`update -r rev` to check out earlier revisions, or
3070 :hg:`update --clean .` to undo a merge which has added another
3070 :hg:`update --clean .` to undo a merge which has added another
3071 parent.
3071 parent.
3072
3072
3073 With no revision specified, revert the named files or directories
3073 With no revision specified, revert the named files or directories
3074 to the contents they had in the parent of the working directory.
3074 to the contents they had in the parent of the working directory.
3075 This restores the contents of the affected files to an unmodified
3075 This restores the contents of the affected files to an unmodified
3076 state and unschedules adds, removes, copies, and renames. If the
3076 state and unschedules adds, removes, copies, and renames. If the
3077 working directory has two parents, you must explicitly specify a
3077 working directory has two parents, you must explicitly specify a
3078 revision.
3078 revision.
3079
3079
3080 Using the -r/--rev option, revert the given files or directories
3080 Using the -r/--rev option, revert the given files or directories
3081 to their contents as of a specific revision. This can be helpful
3081 to their contents as of a specific revision. This can be helpful
3082 to "roll back" some or all of an earlier change. See :hg:`help
3082 to "roll back" some or all of an earlier change. See :hg:`help
3083 dates` for a list of formats valid for -d/--date.
3083 dates` for a list of formats valid for -d/--date.
3084
3084
3085 Revert modifies the working directory. It does not commit any
3085 Revert modifies the working directory. It does not commit any
3086 changes, or change the parent of the working directory. If you
3086 changes, or change the parent of the working directory. If you
3087 revert to a revision other than the parent of the working
3087 revert to a revision other than the parent of the working
3088 directory, the reverted files will thus appear modified
3088 directory, the reverted files will thus appear modified
3089 afterwards.
3089 afterwards.
3090
3090
3091 If a file has been deleted, it is restored. If the executable mode
3091 If a file has been deleted, it is restored. If the executable mode
3092 of a file was changed, it is reset.
3092 of a file was changed, it is reset.
3093
3093
3094 If names are given, all files matching the names are reverted.
3094 If names are given, all files matching the names are reverted.
3095 If no arguments are given, no files are reverted.
3095 If no arguments are given, no files are reverted.
3096
3096
3097 Modified files are saved with a .orig suffix before reverting.
3097 Modified files are saved with a .orig suffix before reverting.
3098 To disable these backups, use --no-backup.
3098 To disable these backups, use --no-backup.
3099
3099
3100 Returns 0 on success.
3100 Returns 0 on success.
3101 """
3101 """
3102
3102
3103 if opts.get("date"):
3103 if opts.get("date"):
3104 if opts.get("rev"):
3104 if opts.get("rev"):
3105 raise util.Abort(_("you can't specify a revision and a date"))
3105 raise util.Abort(_("you can't specify a revision and a date"))
3106 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3106 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3107
3107
3108 if not pats and not opts.get('all'):
3108 if not pats and not opts.get('all'):
3109 raise util.Abort(_('no files or directories specified; '
3109 raise util.Abort(_('no files or directories specified; '
3110 'use --all to revert the whole repo'))
3110 'use --all to revert the whole repo'))
3111
3111
3112 parent, p2 = repo.dirstate.parents()
3112 parent, p2 = repo.dirstate.parents()
3113 if not opts.get('rev') and p2 != nullid:
3113 if not opts.get('rev') and p2 != nullid:
3114 raise util.Abort(_('uncommitted merge - please provide a '
3114 raise util.Abort(_('uncommitted merge - please provide a '
3115 'specific revision'))
3115 'specific revision'))
3116 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3116 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3117 node = ctx.node()
3117 node = ctx.node()
3118 mf = ctx.manifest()
3118 mf = ctx.manifest()
3119 if node == parent:
3119 if node == parent:
3120 pmf = mf
3120 pmf = mf
3121 else:
3121 else:
3122 pmf = None
3122 pmf = None
3123
3123
3124 # need all matching names in dirstate and manifest of target rev,
3124 # need all matching names in dirstate and manifest of target rev,
3125 # so have to walk both. do not print errors if files exist in one
3125 # so have to walk both. do not print errors if files exist in one
3126 # but not other.
3126 # but not other.
3127
3127
3128 names = {}
3128 names = {}
3129
3129
3130 wlock = repo.wlock()
3130 wlock = repo.wlock()
3131 try:
3131 try:
3132 # walk dirstate.
3132 # walk dirstate.
3133
3133
3134 m = cmdutil.match(repo, pats, opts)
3134 m = cmdutil.match(repo, pats, opts)
3135 m.bad = lambda x, y: False
3135 m.bad = lambda x, y: False
3136 for abs in repo.walk(m):
3136 for abs in repo.walk(m):
3137 names[abs] = m.rel(abs), m.exact(abs)
3137 names[abs] = m.rel(abs), m.exact(abs)
3138
3138
3139 # walk target manifest.
3139 # walk target manifest.
3140
3140
3141 def badfn(path, msg):
3141 def badfn(path, msg):
3142 if path in names:
3142 if path in names:
3143 return
3143 return
3144 path_ = path + '/'
3144 path_ = path + '/'
3145 for f in names:
3145 for f in names:
3146 if f.startswith(path_):
3146 if f.startswith(path_):
3147 return
3147 return
3148 ui.warn("%s: %s\n" % (m.rel(path), msg))
3148 ui.warn("%s: %s\n" % (m.rel(path), msg))
3149
3149
3150 m = cmdutil.match(repo, pats, opts)
3150 m = cmdutil.match(repo, pats, opts)
3151 m.bad = badfn
3151 m.bad = badfn
3152 for abs in repo[node].walk(m):
3152 for abs in repo[node].walk(m):
3153 if abs not in names:
3153 if abs not in names:
3154 names[abs] = m.rel(abs), m.exact(abs)
3154 names[abs] = m.rel(abs), m.exact(abs)
3155
3155
3156 m = cmdutil.matchfiles(repo, names)
3156 m = cmdutil.matchfiles(repo, names)
3157 changes = repo.status(match=m)[:4]
3157 changes = repo.status(match=m)[:4]
3158 modified, added, removed, deleted = map(set, changes)
3158 modified, added, removed, deleted = map(set, changes)
3159
3159
3160 # if f is a rename, also revert the source
3160 # if f is a rename, also revert the source
3161 cwd = repo.getcwd()
3161 cwd = repo.getcwd()
3162 for f in added:
3162 for f in added:
3163 src = repo.dirstate.copied(f)
3163 src = repo.dirstate.copied(f)
3164 if src and src not in names and repo.dirstate[src] == 'r':
3164 if src and src not in names and repo.dirstate[src] == 'r':
3165 removed.add(src)
3165 removed.add(src)
3166 names[src] = (repo.pathto(src, cwd), True)
3166 names[src] = (repo.pathto(src, cwd), True)
3167
3167
3168 def removeforget(abs):
3168 def removeforget(abs):
3169 if repo.dirstate[abs] == 'a':
3169 if repo.dirstate[abs] == 'a':
3170 return _('forgetting %s\n')
3170 return _('forgetting %s\n')
3171 return _('removing %s\n')
3171 return _('removing %s\n')
3172
3172
3173 revert = ([], _('reverting %s\n'))
3173 revert = ([], _('reverting %s\n'))
3174 add = ([], _('adding %s\n'))
3174 add = ([], _('adding %s\n'))
3175 remove = ([], removeforget)
3175 remove = ([], removeforget)
3176 undelete = ([], _('undeleting %s\n'))
3176 undelete = ([], _('undeleting %s\n'))
3177
3177
3178 disptable = (
3178 disptable = (
3179 # dispatch table:
3179 # dispatch table:
3180 # file state
3180 # file state
3181 # action if in target manifest
3181 # action if in target manifest
3182 # action if not in target manifest
3182 # action if not in target manifest
3183 # make backup if in target manifest
3183 # make backup if in target manifest
3184 # make backup if not in target manifest
3184 # make backup if not in target manifest
3185 (modified, revert, remove, True, True),
3185 (modified, revert, remove, True, True),
3186 (added, revert, remove, True, False),
3186 (added, revert, remove, True, False),
3187 (removed, undelete, None, False, False),
3187 (removed, undelete, None, False, False),
3188 (deleted, revert, remove, False, False),
3188 (deleted, revert, remove, False, False),
3189 )
3189 )
3190
3190
3191 for abs, (rel, exact) in sorted(names.items()):
3191 for abs, (rel, exact) in sorted(names.items()):
3192 mfentry = mf.get(abs)
3192 mfentry = mf.get(abs)
3193 target = repo.wjoin(abs)
3193 target = repo.wjoin(abs)
3194 def handle(xlist, dobackup):
3194 def handle(xlist, dobackup):
3195 xlist[0].append(abs)
3195 xlist[0].append(abs)
3196 if (dobackup and not opts.get('no_backup') and
3196 if (dobackup and not opts.get('no_backup') and
3197 os.path.lexists(target)):
3197 os.path.lexists(target)):
3198 bakname = "%s.orig" % rel
3198 bakname = "%s.orig" % rel
3199 ui.note(_('saving current version of %s as %s\n') %
3199 ui.note(_('saving current version of %s as %s\n') %
3200 (rel, bakname))
3200 (rel, bakname))
3201 if not opts.get('dry_run'):
3201 if not opts.get('dry_run'):
3202 util.rename(target, bakname)
3202 util.rename(target, bakname)
3203 if ui.verbose or not exact:
3203 if ui.verbose or not exact:
3204 msg = xlist[1]
3204 msg = xlist[1]
3205 if not isinstance(msg, basestring):
3205 if not isinstance(msg, basestring):
3206 msg = msg(abs)
3206 msg = msg(abs)
3207 ui.status(msg % rel)
3207 ui.status(msg % rel)
3208 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3208 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3209 if abs not in table:
3209 if abs not in table:
3210 continue
3210 continue
3211 # file has changed in dirstate
3211 # file has changed in dirstate
3212 if mfentry:
3212 if mfentry:
3213 handle(hitlist, backuphit)
3213 handle(hitlist, backuphit)
3214 elif misslist is not None:
3214 elif misslist is not None:
3215 handle(misslist, backupmiss)
3215 handle(misslist, backupmiss)
3216 break
3216 break
3217 else:
3217 else:
3218 if abs not in repo.dirstate:
3218 if abs not in repo.dirstate:
3219 if mfentry:
3219 if mfentry:
3220 handle(add, True)
3220 handle(add, True)
3221 elif exact:
3221 elif exact:
3222 ui.warn(_('file not managed: %s\n') % rel)
3222 ui.warn(_('file not managed: %s\n') % rel)
3223 continue
3223 continue
3224 # file has not changed in dirstate
3224 # file has not changed in dirstate
3225 if node == parent:
3225 if node == parent:
3226 if exact:
3226 if exact:
3227 ui.warn(_('no changes needed to %s\n') % rel)
3227 ui.warn(_('no changes needed to %s\n') % rel)
3228 continue
3228 continue
3229 if pmf is None:
3229 if pmf is None:
3230 # only need parent manifest in this unlikely case,
3230 # only need parent manifest in this unlikely case,
3231 # so do not read by default
3231 # so do not read by default
3232 pmf = repo[parent].manifest()
3232 pmf = repo[parent].manifest()
3233 if abs in pmf:
3233 if abs in pmf:
3234 if mfentry:
3234 if mfentry:
3235 # if version of file is same in parent and target
3235 # if version of file is same in parent and target
3236 # manifests, do nothing
3236 # manifests, do nothing
3237 if (pmf[abs] != mfentry or
3237 if (pmf[abs] != mfentry or
3238 pmf.flags(abs) != mf.flags(abs)):
3238 pmf.flags(abs) != mf.flags(abs)):
3239 handle(revert, False)
3239 handle(revert, False)
3240 else:
3240 else:
3241 handle(remove, False)
3241 handle(remove, False)
3242
3242
3243 if not opts.get('dry_run'):
3243 if not opts.get('dry_run'):
3244 def checkout(f):
3244 def checkout(f):
3245 fc = ctx[f]
3245 fc = ctx[f]
3246 repo.wwrite(f, fc.data(), fc.flags())
3246 repo.wwrite(f, fc.data(), fc.flags())
3247
3247
3248 audit_path = util.path_auditor(repo.root)
3248 audit_path = util.path_auditor(repo.root)
3249 for f in remove[0]:
3249 for f in remove[0]:
3250 if repo.dirstate[f] == 'a':
3250 if repo.dirstate[f] == 'a':
3251 repo.dirstate.forget(f)
3251 repo.dirstate.forget(f)
3252 continue
3252 continue
3253 audit_path(f)
3253 audit_path(f)
3254 try:
3254 try:
3255 util.unlink(repo.wjoin(f))
3255 util.unlink(repo.wjoin(f))
3256 except OSError:
3256 except OSError:
3257 pass
3257 pass
3258 repo.dirstate.remove(f)
3258 repo.dirstate.remove(f)
3259
3259
3260 normal = None
3260 normal = None
3261 if node == parent:
3261 if node == parent:
3262 # We're reverting to our parent. If possible, we'd like status
3262 # We're reverting to our parent. If possible, we'd like status
3263 # to report the file as clean. We have to use normallookup for
3263 # to report the file as clean. We have to use normallookup for
3264 # merges to avoid losing information about merged/dirty files.
3264 # merges to avoid losing information about merged/dirty files.
3265 if p2 != nullid:
3265 if p2 != nullid:
3266 normal = repo.dirstate.normallookup
3266 normal = repo.dirstate.normallookup
3267 else:
3267 else:
3268 normal = repo.dirstate.normal
3268 normal = repo.dirstate.normal
3269 for f in revert[0]:
3269 for f in revert[0]:
3270 checkout(f)
3270 checkout(f)
3271 if normal:
3271 if normal:
3272 normal(f)
3272 normal(f)
3273
3273
3274 for f in add[0]:
3274 for f in add[0]:
3275 checkout(f)
3275 checkout(f)
3276 repo.dirstate.add(f)
3276 repo.dirstate.add(f)
3277
3277
3278 normal = repo.dirstate.normallookup
3278 normal = repo.dirstate.normallookup
3279 if node == parent and p2 == nullid:
3279 if node == parent and p2 == nullid:
3280 normal = repo.dirstate.normal
3280 normal = repo.dirstate.normal
3281 for f in undelete[0]:
3281 for f in undelete[0]:
3282 checkout(f)
3282 checkout(f)
3283 normal(f)
3283 normal(f)
3284
3284
3285 finally:
3285 finally:
3286 wlock.release()
3286 wlock.release()
3287
3287
3288 def rollback(ui, repo, **opts):
3288 def rollback(ui, repo, **opts):
3289 """roll back the last transaction (dangerous)
3289 """roll back the last transaction (dangerous)
3290
3290
3291 This command should be used with care. There is only one level of
3291 This command should be used with care. There is only one level of
3292 rollback, and there is no way to undo a rollback. It will also
3292 rollback, and there is no way to undo a rollback. It will also
3293 restore the dirstate at the time of the last transaction, losing
3293 restore the dirstate at the time of the last transaction, losing
3294 any dirstate changes since that time. This command does not alter
3294 any dirstate changes since that time. This command does not alter
3295 the working directory.
3295 the working directory.
3296
3296
3297 Transactions are used to encapsulate the effects of all commands
3297 Transactions are used to encapsulate the effects of all commands
3298 that create new changesets or propagate existing changesets into a
3298 that create new changesets or propagate existing changesets into a
3299 repository. For example, the following commands are transactional,
3299 repository. For example, the following commands are transactional,
3300 and their effects can be rolled back:
3300 and their effects can be rolled back:
3301
3301
3302 - commit
3302 - commit
3303 - import
3303 - import
3304 - pull
3304 - pull
3305 - push (with this repository as the destination)
3305 - push (with this repository as the destination)
3306 - unbundle
3306 - unbundle
3307
3307
3308 This command is not intended for use on public repositories. Once
3308 This command is not intended for use on public repositories. Once
3309 changes are visible for pull by other users, rolling a transaction
3309 changes are visible for pull by other users, rolling a transaction
3310 back locally is ineffective (someone else may already have pulled
3310 back locally is ineffective (someone else may already have pulled
3311 the changes). Furthermore, a race is possible with readers of the
3311 the changes). Furthermore, a race is possible with readers of the
3312 repository; for example an in-progress pull from the repository
3312 repository; for example an in-progress pull from the repository
3313 may fail if a rollback is performed.
3313 may fail if a rollback is performed.
3314
3314
3315 Returns 0 on success, 1 if no rollback data is available.
3315 Returns 0 on success, 1 if no rollback data is available.
3316 """
3316 """
3317 return repo.rollback(opts.get('dry_run'))
3317 return repo.rollback(opts.get('dry_run'))
3318
3318
3319 def root(ui, repo):
3319 def root(ui, repo):
3320 """print the root (top) of the current working directory
3320 """print the root (top) of the current working directory
3321
3321
3322 Print the root directory of the current repository.
3322 Print the root directory of the current repository.
3323
3323
3324 Returns 0 on success.
3324 Returns 0 on success.
3325 """
3325 """
3326 ui.write(repo.root + "\n")
3326 ui.write(repo.root + "\n")
3327
3327
3328 def serve(ui, repo, **opts):
3328 def serve(ui, repo, **opts):
3329 """start stand-alone webserver
3329 """start stand-alone webserver
3330
3330
3331 Start a local HTTP repository browser and pull server. You can use
3331 Start a local HTTP repository browser and pull server. You can use
3332 this for ad-hoc sharing and browing of repositories. It is
3332 this for ad-hoc sharing and browing of repositories. It is
3333 recommended to use a real web server to serve a repository for
3333 recommended to use a real web server to serve a repository for
3334 longer periods of time.
3334 longer periods of time.
3335
3335
3336 Please note that the server does not implement access control.
3336 Please note that the server does not implement access control.
3337 This means that, by default, anybody can read from the server and
3337 This means that, by default, anybody can read from the server and
3338 nobody can write to it by default. Set the ``web.allow_push``
3338 nobody can write to it by default. Set the ``web.allow_push``
3339 option to ``*`` to allow everybody to push to the server. You
3339 option to ``*`` to allow everybody to push to the server. You
3340 should use a real web server if you need to authenticate users.
3340 should use a real web server if you need to authenticate users.
3341
3341
3342 By default, the server logs accesses to stdout and errors to
3342 By default, the server logs accesses to stdout and errors to
3343 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3343 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3344 files.
3344 files.
3345
3345
3346 To have the server choose a free port number to listen on, specify
3346 To have the server choose a free port number to listen on, specify
3347 a port number of 0; in this case, the server will print the port
3347 a port number of 0; in this case, the server will print the port
3348 number it uses.
3348 number it uses.
3349
3349
3350 Returns 0 on success.
3350 Returns 0 on success.
3351 """
3351 """
3352
3352
3353 if opts["stdio"]:
3353 if opts["stdio"]:
3354 if repo is None:
3354 if repo is None:
3355 raise error.RepoError(_("There is no Mercurial repository here"
3355 raise error.RepoError(_("There is no Mercurial repository here"
3356 " (.hg not found)"))
3356 " (.hg not found)"))
3357 s = sshserver.sshserver(ui, repo)
3357 s = sshserver.sshserver(ui, repo)
3358 s.serve_forever()
3358 s.serve_forever()
3359
3359
3360 # this way we can check if something was given in the command-line
3360 # this way we can check if something was given in the command-line
3361 if opts.get('port'):
3361 if opts.get('port'):
3362 opts['port'] = util.getport(opts.get('port'))
3362 opts['port'] = util.getport(opts.get('port'))
3363
3363
3364 baseui = repo and repo.baseui or ui
3364 baseui = repo and repo.baseui or ui
3365 optlist = ("name templates style address port prefix ipv6"
3365 optlist = ("name templates style address port prefix ipv6"
3366 " accesslog errorlog certificate encoding")
3366 " accesslog errorlog certificate encoding")
3367 for o in optlist.split():
3367 for o in optlist.split():
3368 val = opts.get(o, '')
3368 val = opts.get(o, '')
3369 if val in (None, ''): # should check against default options instead
3369 if val in (None, ''): # should check against default options instead
3370 continue
3370 continue
3371 baseui.setconfig("web", o, val)
3371 baseui.setconfig("web", o, val)
3372 if repo and repo.ui != baseui:
3372 if repo and repo.ui != baseui:
3373 repo.ui.setconfig("web", o, val)
3373 repo.ui.setconfig("web", o, val)
3374
3374
3375 o = opts.get('web_conf') or opts.get('webdir_conf')
3375 o = opts.get('web_conf') or opts.get('webdir_conf')
3376 if not o:
3376 if not o:
3377 if not repo:
3377 if not repo:
3378 raise error.RepoError(_("There is no Mercurial repository"
3378 raise error.RepoError(_("There is no Mercurial repository"
3379 " here (.hg not found)"))
3379 " here (.hg not found)"))
3380 o = repo.root
3380 o = repo.root
3381
3381
3382 app = hgweb.hgweb(o, baseui=ui)
3382 app = hgweb.hgweb(o, baseui=ui)
3383
3383
3384 class service(object):
3384 class service(object):
3385 def init(self):
3385 def init(self):
3386 util.set_signal_handler()
3386 util.set_signal_handler()
3387 self.httpd = hgweb.server.create_server(ui, app)
3387 self.httpd = hgweb.server.create_server(ui, app)
3388
3388
3389 if opts['port'] and not ui.verbose:
3389 if opts['port'] and not ui.verbose:
3390 return
3390 return
3391
3391
3392 if self.httpd.prefix:
3392 if self.httpd.prefix:
3393 prefix = self.httpd.prefix.strip('/') + '/'
3393 prefix = self.httpd.prefix.strip('/') + '/'
3394 else:
3394 else:
3395 prefix = ''
3395 prefix = ''
3396
3396
3397 port = ':%d' % self.httpd.port
3397 port = ':%d' % self.httpd.port
3398 if port == ':80':
3398 if port == ':80':
3399 port = ''
3399 port = ''
3400
3400
3401 bindaddr = self.httpd.addr
3401 bindaddr = self.httpd.addr
3402 if bindaddr == '0.0.0.0':
3402 if bindaddr == '0.0.0.0':
3403 bindaddr = '*'
3403 bindaddr = '*'
3404 elif ':' in bindaddr: # IPv6
3404 elif ':' in bindaddr: # IPv6
3405 bindaddr = '[%s]' % bindaddr
3405 bindaddr = '[%s]' % bindaddr
3406
3406
3407 fqaddr = self.httpd.fqaddr
3407 fqaddr = self.httpd.fqaddr
3408 if ':' in fqaddr:
3408 if ':' in fqaddr:
3409 fqaddr = '[%s]' % fqaddr
3409 fqaddr = '[%s]' % fqaddr
3410 if opts['port']:
3410 if opts['port']:
3411 write = ui.status
3411 write = ui.status
3412 else:
3412 else:
3413 write = ui.write
3413 write = ui.write
3414 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3414 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3415 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3415 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3416
3416
3417 def run(self):
3417 def run(self):
3418 self.httpd.serve_forever()
3418 self.httpd.serve_forever()
3419
3419
3420 service = service()
3420 service = service()
3421
3421
3422 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3422 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3423
3423
3424 def status(ui, repo, *pats, **opts):
3424 def status(ui, repo, *pats, **opts):
3425 """show changed files in the working directory
3425 """show changed files in the working directory
3426
3426
3427 Show status of files in the repository. If names are given, only
3427 Show status of files in the repository. If names are given, only
3428 files that match are shown. Files that are clean or ignored or
3428 files that match are shown. Files that are clean or ignored or
3429 the source of a copy/move operation, are not listed unless
3429 the source of a copy/move operation, are not listed unless
3430 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3430 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3431 Unless options described with "show only ..." are given, the
3431 Unless options described with "show only ..." are given, the
3432 options -mardu are used.
3432 options -mardu are used.
3433
3433
3434 Option -q/--quiet hides untracked (unknown and ignored) files
3434 Option -q/--quiet hides untracked (unknown and ignored) files
3435 unless explicitly requested with -u/--unknown or -i/--ignored.
3435 unless explicitly requested with -u/--unknown or -i/--ignored.
3436
3436
3437 .. note::
3437 .. note::
3438 status may appear to disagree with diff if permissions have
3438 status may appear to disagree with diff if permissions have
3439 changed or a merge has occurred. The standard diff format does
3439 changed or a merge has occurred. The standard diff format does
3440 not report permission changes and diff only reports changes
3440 not report permission changes and diff only reports changes
3441 relative to one merge parent.
3441 relative to one merge parent.
3442
3442
3443 If one revision is given, it is used as the base revision.
3443 If one revision is given, it is used as the base revision.
3444 If two revisions are given, the differences between them are
3444 If two revisions are given, the differences between them are
3445 shown. The --change option can also be used as a shortcut to list
3445 shown. The --change option can also be used as a shortcut to list
3446 the changed files of a revision from its first parent.
3446 the changed files of a revision from its first parent.
3447
3447
3448 The codes used to show the status of files are::
3448 The codes used to show the status of files are::
3449
3449
3450 M = modified
3450 M = modified
3451 A = added
3451 A = added
3452 R = removed
3452 R = removed
3453 C = clean
3453 C = clean
3454 ! = missing (deleted by non-hg command, but still tracked)
3454 ! = missing (deleted by non-hg command, but still tracked)
3455 ? = not tracked
3455 ? = not tracked
3456 I = ignored
3456 I = ignored
3457 = origin of the previous file listed as A (added)
3457 = origin of the previous file listed as A (added)
3458
3458
3459 Returns 0 on success.
3459 Returns 0 on success.
3460 """
3460 """
3461
3461
3462 revs = opts.get('rev')
3462 revs = opts.get('rev')
3463 change = opts.get('change')
3463 change = opts.get('change')
3464
3464
3465 if revs and change:
3465 if revs and change:
3466 msg = _('cannot specify --rev and --change at the same time')
3466 msg = _('cannot specify --rev and --change at the same time')
3467 raise util.Abort(msg)
3467 raise util.Abort(msg)
3468 elif change:
3468 elif change:
3469 node2 = repo.lookup(change)
3469 node2 = repo.lookup(change)
3470 node1 = repo[node2].parents()[0].node()
3470 node1 = repo[node2].parents()[0].node()
3471 else:
3471 else:
3472 node1, node2 = cmdutil.revpair(repo, revs)
3472 node1, node2 = cmdutil.revpair(repo, revs)
3473
3473
3474 cwd = (pats and repo.getcwd()) or ''
3474 cwd = (pats and repo.getcwd()) or ''
3475 end = opts.get('print0') and '\0' or '\n'
3475 end = opts.get('print0') and '\0' or '\n'
3476 copy = {}
3476 copy = {}
3477 states = 'modified added removed deleted unknown ignored clean'.split()
3477 states = 'modified added removed deleted unknown ignored clean'.split()
3478 show = [k for k in states if opts.get(k)]
3478 show = [k for k in states if opts.get(k)]
3479 if opts.get('all'):
3479 if opts.get('all'):
3480 show += ui.quiet and (states[:4] + ['clean']) or states
3480 show += ui.quiet and (states[:4] + ['clean']) or states
3481 if not show:
3481 if not show:
3482 show = ui.quiet and states[:4] or states[:5]
3482 show = ui.quiet and states[:4] or states[:5]
3483
3483
3484 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3484 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3485 'ignored' in show, 'clean' in show, 'unknown' in show,
3485 'ignored' in show, 'clean' in show, 'unknown' in show,
3486 opts.get('subrepos'))
3486 opts.get('subrepos'))
3487 changestates = zip(states, 'MAR!?IC', stat)
3487 changestates = zip(states, 'MAR!?IC', stat)
3488
3488
3489 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3489 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3490 ctxn = repo[nullid]
3490 ctxn = repo[nullid]
3491 ctx1 = repo[node1]
3491 ctx1 = repo[node1]
3492 ctx2 = repo[node2]
3492 ctx2 = repo[node2]
3493 added = stat[1]
3493 added = stat[1]
3494 if node2 is None:
3494 if node2 is None:
3495 added = stat[0] + stat[1] # merged?
3495 added = stat[0] + stat[1] # merged?
3496
3496
3497 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3497 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3498 if k in added:
3498 if k in added:
3499 copy[k] = v
3499 copy[k] = v
3500 elif v in added:
3500 elif v in added:
3501 copy[v] = k
3501 copy[v] = k
3502
3502
3503 for state, char, files in changestates:
3503 for state, char, files in changestates:
3504 if state in show:
3504 if state in show:
3505 format = "%s %%s%s" % (char, end)
3505 format = "%s %%s%s" % (char, end)
3506 if opts.get('no_status'):
3506 if opts.get('no_status'):
3507 format = "%%s%s" % end
3507 format = "%%s%s" % end
3508
3508
3509 for f in files:
3509 for f in files:
3510 ui.write(format % repo.pathto(f, cwd),
3510 ui.write(format % repo.pathto(f, cwd),
3511 label='status.' + state)
3511 label='status.' + state)
3512 if f in copy:
3512 if f in copy:
3513 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3513 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3514 label='status.copied')
3514 label='status.copied')
3515
3515
3516 def summary(ui, repo, **opts):
3516 def summary(ui, repo, **opts):
3517 """summarize working directory state
3517 """summarize working directory state
3518
3518
3519 This generates a brief summary of the working directory state,
3519 This generates a brief summary of the working directory state,
3520 including parents, branch, commit status, and available updates.
3520 including parents, branch, commit status, and available updates.
3521
3521
3522 With the --remote option, this will check the default paths for
3522 With the --remote option, this will check the default paths for
3523 incoming and outgoing changes. This can be time-consuming.
3523 incoming and outgoing changes. This can be time-consuming.
3524
3524
3525 Returns 0 on success.
3525 Returns 0 on success.
3526 """
3526 """
3527
3527
3528 ctx = repo[None]
3528 ctx = repo[None]
3529 parents = ctx.parents()
3529 parents = ctx.parents()
3530 pnode = parents[0].node()
3530 pnode = parents[0].node()
3531
3531
3532 for p in parents:
3532 for p in parents:
3533 # label with log.changeset (instead of log.parent) since this
3533 # label with log.changeset (instead of log.parent) since this
3534 # shows a working directory parent *changeset*:
3534 # shows a working directory parent *changeset*:
3535 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3535 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3536 label='log.changeset')
3536 label='log.changeset')
3537 ui.write(' '.join(p.tags()), label='log.tag')
3537 ui.write(' '.join(p.tags()), label='log.tag')
3538 if p.rev() == -1:
3538 if p.rev() == -1:
3539 if not len(repo):
3539 if not len(repo):
3540 ui.write(_(' (empty repository)'))
3540 ui.write(_(' (empty repository)'))
3541 else:
3541 else:
3542 ui.write(_(' (no revision checked out)'))
3542 ui.write(_(' (no revision checked out)'))
3543 ui.write('\n')
3543 ui.write('\n')
3544 if p.description():
3544 if p.description():
3545 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3545 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3546 label='log.summary')
3546 label='log.summary')
3547
3547
3548 branch = ctx.branch()
3548 branch = ctx.branch()
3549 bheads = repo.branchheads(branch)
3549 bheads = repo.branchheads(branch)
3550 m = _('branch: %s\n') % branch
3550 m = _('branch: %s\n') % branch
3551 if branch != 'default':
3551 if branch != 'default':
3552 ui.write(m, label='log.branch')
3552 ui.write(m, label='log.branch')
3553 else:
3553 else:
3554 ui.status(m, label='log.branch')
3554 ui.status(m, label='log.branch')
3555
3555
3556 st = list(repo.status(unknown=True))[:6]
3556 st = list(repo.status(unknown=True))[:6]
3557
3557
3558 c = repo.dirstate.copies()
3558 c = repo.dirstate.copies()
3559 copied, renamed = [], []
3559 copied, renamed = [], []
3560 for d, s in c.iteritems():
3560 for d, s in c.iteritems():
3561 if s in st[2]:
3561 if s in st[2]:
3562 st[2].remove(s)
3562 st[2].remove(s)
3563 renamed.append(d)
3563 renamed.append(d)
3564 else:
3564 else:
3565 copied.append(d)
3565 copied.append(d)
3566 if d in st[1]:
3566 if d in st[1]:
3567 st[1].remove(d)
3567 st[1].remove(d)
3568 st.insert(3, renamed)
3568 st.insert(3, renamed)
3569 st.insert(4, copied)
3569 st.insert(4, copied)
3570
3570
3571 ms = mergemod.mergestate(repo)
3571 ms = mergemod.mergestate(repo)
3572 st.append([f for f in ms if ms[f] == 'u'])
3572 st.append([f for f in ms if ms[f] == 'u'])
3573
3573
3574 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3574 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3575 st.append(subs)
3575 st.append(subs)
3576
3576
3577 labels = [ui.label(_('%d modified'), 'status.modified'),
3577 labels = [ui.label(_('%d modified'), 'status.modified'),
3578 ui.label(_('%d added'), 'status.added'),
3578 ui.label(_('%d added'), 'status.added'),
3579 ui.label(_('%d removed'), 'status.removed'),
3579 ui.label(_('%d removed'), 'status.removed'),
3580 ui.label(_('%d renamed'), 'status.copied'),
3580 ui.label(_('%d renamed'), 'status.copied'),
3581 ui.label(_('%d copied'), 'status.copied'),
3581 ui.label(_('%d copied'), 'status.copied'),
3582 ui.label(_('%d deleted'), 'status.deleted'),
3582 ui.label(_('%d deleted'), 'status.deleted'),
3583 ui.label(_('%d unknown'), 'status.unknown'),
3583 ui.label(_('%d unknown'), 'status.unknown'),
3584 ui.label(_('%d ignored'), 'status.ignored'),
3584 ui.label(_('%d ignored'), 'status.ignored'),
3585 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3585 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3586 ui.label(_('%d subrepos'), 'status.modified')]
3586 ui.label(_('%d subrepos'), 'status.modified')]
3587 t = []
3587 t = []
3588 for s, l in zip(st, labels):
3588 for s, l in zip(st, labels):
3589 if s:
3589 if s:
3590 t.append(l % len(s))
3590 t.append(l % len(s))
3591
3591
3592 t = ', '.join(t)
3592 t = ', '.join(t)
3593 cleanworkdir = False
3593 cleanworkdir = False
3594
3594
3595 if len(parents) > 1:
3595 if len(parents) > 1:
3596 t += _(' (merge)')
3596 t += _(' (merge)')
3597 elif branch != parents[0].branch():
3597 elif branch != parents[0].branch():
3598 t += _(' (new branch)')
3598 t += _(' (new branch)')
3599 elif (parents[0].extra().get('close') and
3599 elif (parents[0].extra().get('close') and
3600 pnode in repo.branchheads(branch, closed=True)):
3600 pnode in repo.branchheads(branch, closed=True)):
3601 t += _(' (head closed)')
3601 t += _(' (head closed)')
3602 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3602 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3603 t += _(' (clean)')
3603 t += _(' (clean)')
3604 cleanworkdir = True
3604 cleanworkdir = True
3605 elif pnode not in bheads:
3605 elif pnode not in bheads:
3606 t += _(' (new branch head)')
3606 t += _(' (new branch head)')
3607
3607
3608 if cleanworkdir:
3608 if cleanworkdir:
3609 ui.status(_('commit: %s\n') % t.strip())
3609 ui.status(_('commit: %s\n') % t.strip())
3610 else:
3610 else:
3611 ui.write(_('commit: %s\n') % t.strip())
3611 ui.write(_('commit: %s\n') % t.strip())
3612
3612
3613 # all ancestors of branch heads - all ancestors of parent = new csets
3613 # all ancestors of branch heads - all ancestors of parent = new csets
3614 new = [0] * len(repo)
3614 new = [0] * len(repo)
3615 cl = repo.changelog
3615 cl = repo.changelog
3616 for a in [cl.rev(n) for n in bheads]:
3616 for a in [cl.rev(n) for n in bheads]:
3617 new[a] = 1
3617 new[a] = 1
3618 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3618 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3619 new[a] = 1
3619 new[a] = 1
3620 for a in [p.rev() for p in parents]:
3620 for a in [p.rev() for p in parents]:
3621 if a >= 0:
3621 if a >= 0:
3622 new[a] = 0
3622 new[a] = 0
3623 for a in cl.ancestors(*[p.rev() for p in parents]):
3623 for a in cl.ancestors(*[p.rev() for p in parents]):
3624 new[a] = 0
3624 new[a] = 0
3625 new = sum(new)
3625 new = sum(new)
3626
3626
3627 if new == 0:
3627 if new == 0:
3628 ui.status(_('update: (current)\n'))
3628 ui.status(_('update: (current)\n'))
3629 elif pnode not in bheads:
3629 elif pnode not in bheads:
3630 ui.write(_('update: %d new changesets (update)\n') % new)
3630 ui.write(_('update: %d new changesets (update)\n') % new)
3631 else:
3631 else:
3632 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3632 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3633 (new, len(bheads)))
3633 (new, len(bheads)))
3634
3634
3635 if opts.get('remote'):
3635 if opts.get('remote'):
3636 t = []
3636 t = []
3637 source, branches = hg.parseurl(ui.expandpath('default'))
3637 source, branches = hg.parseurl(ui.expandpath('default'))
3638 other = hg.repository(hg.remoteui(repo, {}), source)
3638 other = hg.repository(hg.remoteui(repo, {}), source)
3639 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3639 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3640 ui.debug('comparing with %s\n' % url.hidepassword(source))
3640 ui.debug('comparing with %s\n' % url.hidepassword(source))
3641 repo.ui.pushbuffer()
3641 repo.ui.pushbuffer()
3642 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3642 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3643 repo.ui.popbuffer()
3643 repo.ui.popbuffer()
3644 if incoming:
3644 if incoming:
3645 t.append(_('1 or more incoming'))
3645 t.append(_('1 or more incoming'))
3646
3646
3647 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3647 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3648 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3648 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3649 other = hg.repository(hg.remoteui(repo, {}), dest)
3649 other = hg.repository(hg.remoteui(repo, {}), dest)
3650 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3650 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3651 repo.ui.pushbuffer()
3651 repo.ui.pushbuffer()
3652 o = discovery.findoutgoing(repo, other)
3652 o = discovery.findoutgoing(repo, other)
3653 repo.ui.popbuffer()
3653 repo.ui.popbuffer()
3654 o = repo.changelog.nodesbetween(o, None)[0]
3654 o = repo.changelog.nodesbetween(o, None)[0]
3655 if o:
3655 if o:
3656 t.append(_('%d outgoing') % len(o))
3656 t.append(_('%d outgoing') % len(o))
3657
3657
3658 if t:
3658 if t:
3659 ui.write(_('remote: %s\n') % (', '.join(t)))
3659 ui.write(_('remote: %s\n') % (', '.join(t)))
3660 else:
3660 else:
3661 ui.status(_('remote: (synced)\n'))
3661 ui.status(_('remote: (synced)\n'))
3662
3662
3663 def tag(ui, repo, name1, *names, **opts):
3663 def tag(ui, repo, name1, *names, **opts):
3664 """add one or more tags for the current or given revision
3664 """add one or more tags for the current or given revision
3665
3665
3666 Name a particular revision using <name>.
3666 Name a particular revision using <name>.
3667
3667
3668 Tags are used to name particular revisions of the repository and are
3668 Tags are used to name particular revisions of the repository and are
3669 very useful to compare different revisions, to go back to significant
3669 very useful to compare different revisions, to go back to significant
3670 earlier versions or to mark branch points as releases, etc.
3670 earlier versions or to mark branch points as releases, etc.
3671
3671
3672 If no revision is given, the parent of the working directory is
3672 If no revision is given, the parent of the working directory is
3673 used, or tip if no revision is checked out.
3673 used, or tip if no revision is checked out.
3674
3674
3675 To facilitate version control, distribution, and merging of tags,
3675 To facilitate version control, distribution, and merging of tags,
3676 they are stored as a file named ".hgtags" which is managed
3676 they are stored as a file named ".hgtags" which is managed
3677 similarly to other project files and can be hand-edited if
3677 similarly to other project files and can be hand-edited if
3678 necessary. The file '.hg/localtags' is used for local tags (not
3678 necessary. The file '.hg/localtags' is used for local tags (not
3679 shared among repositories).
3679 shared among repositories).
3680
3680
3681 See :hg:`help dates` for a list of formats valid for -d/--date.
3681 See :hg:`help dates` for a list of formats valid for -d/--date.
3682
3682
3683 Since tag names have priority over branch names during revision
3683 Since tag names have priority over branch names during revision
3684 lookup, using an existing branch name as a tag name is discouraged.
3684 lookup, using an existing branch name as a tag name is discouraged.
3685
3685
3686 Returns 0 on success.
3686 Returns 0 on success.
3687 """
3687 """
3688
3688
3689 rev_ = "."
3689 rev_ = "."
3690 names = [t.strip() for t in (name1,) + names]
3690 names = [t.strip() for t in (name1,) + names]
3691 if len(names) != len(set(names)):
3691 if len(names) != len(set(names)):
3692 raise util.Abort(_('tag names must be unique'))
3692 raise util.Abort(_('tag names must be unique'))
3693 for n in names:
3693 for n in names:
3694 if n in ['tip', '.', 'null']:
3694 if n in ['tip', '.', 'null']:
3695 raise util.Abort(_('the name \'%s\' is reserved') % n)
3695 raise util.Abort(_('the name \'%s\' is reserved') % n)
3696 if not n:
3696 if not n:
3697 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3697 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3698 if opts.get('rev') and opts.get('remove'):
3698 if opts.get('rev') and opts.get('remove'):
3699 raise util.Abort(_("--rev and --remove are incompatible"))
3699 raise util.Abort(_("--rev and --remove are incompatible"))
3700 if opts.get('rev'):
3700 if opts.get('rev'):
3701 rev_ = opts['rev']
3701 rev_ = opts['rev']
3702 message = opts.get('message')
3702 message = opts.get('message')
3703 if opts.get('remove'):
3703 if opts.get('remove'):
3704 expectedtype = opts.get('local') and 'local' or 'global'
3704 expectedtype = opts.get('local') and 'local' or 'global'
3705 for n in names:
3705 for n in names:
3706 if not repo.tagtype(n):
3706 if not repo.tagtype(n):
3707 raise util.Abort(_('tag \'%s\' does not exist') % n)
3707 raise util.Abort(_('tag \'%s\' does not exist') % n)
3708 if repo.tagtype(n) != expectedtype:
3708 if repo.tagtype(n) != expectedtype:
3709 if expectedtype == 'global':
3709 if expectedtype == 'global':
3710 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3710 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3711 else:
3711 else:
3712 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3712 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3713 rev_ = nullid
3713 rev_ = nullid
3714 if not message:
3714 if not message:
3715 # we don't translate commit messages
3715 # we don't translate commit messages
3716 message = 'Removed tag %s' % ', '.join(names)
3716 message = 'Removed tag %s' % ', '.join(names)
3717 elif not opts.get('force'):
3717 elif not opts.get('force'):
3718 for n in names:
3718 for n in names:
3719 if n in repo.tags():
3719 if n in repo.tags():
3720 raise util.Abort(_('tag \'%s\' already exists '
3720 raise util.Abort(_('tag \'%s\' already exists '
3721 '(use -f to force)') % n)
3721 '(use -f to force)') % n)
3722 if not rev_ and repo.dirstate.parents()[1] != nullid:
3722 if not rev_ and repo.dirstate.parents()[1] != nullid:
3723 raise util.Abort(_('uncommitted merge - please provide a '
3723 raise util.Abort(_('uncommitted merge - please provide a '
3724 'specific revision'))
3724 'specific revision'))
3725 r = cmdutil.revsingle(repo, rev_).node()
3725 r = cmdutil.revsingle(repo, rev_).node()
3726
3726
3727 if not message:
3727 if not message:
3728 # we don't translate commit messages
3728 # we don't translate commit messages
3729 message = ('Added tag %s for changeset %s' %
3729 message = ('Added tag %s for changeset %s' %
3730 (', '.join(names), short(r)))
3730 (', '.join(names), short(r)))
3731
3731
3732 date = opts.get('date')
3732 date = opts.get('date')
3733 if date:
3733 if date:
3734 date = util.parsedate(date)
3734 date = util.parsedate(date)
3735
3735
3736 if opts.get('edit'):
3736 if opts.get('edit'):
3737 message = ui.edit(message, ui.username())
3737 message = ui.edit(message, ui.username())
3738
3738
3739 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3739 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3740
3740
3741 def tags(ui, repo):
3741 def tags(ui, repo):
3742 """list repository tags
3742 """list repository tags
3743
3743
3744 This lists both regular and local tags. When the -v/--verbose
3744 This lists both regular and local tags. When the -v/--verbose
3745 switch is used, a third column "local" is printed for local tags.
3745 switch is used, a third column "local" is printed for local tags.
3746
3746
3747 Returns 0 on success.
3747 Returns 0 on success.
3748 """
3748 """
3749
3749
3750 hexfunc = ui.debugflag and hex or short
3750 hexfunc = ui.debugflag and hex or short
3751 tagtype = ""
3751 tagtype = ""
3752
3752
3753 for t, n in reversed(repo.tagslist()):
3753 for t, n in reversed(repo.tagslist()):
3754 if ui.quiet:
3754 if ui.quiet:
3755 ui.write("%s\n" % t)
3755 ui.write("%s\n" % t)
3756 continue
3756 continue
3757
3757
3758 try:
3758 try:
3759 hn = hexfunc(n)
3759 hn = hexfunc(n)
3760 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3760 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3761 except error.LookupError:
3761 except error.LookupError:
3762 r = " ?:%s" % hn
3762 r = " ?:%s" % hn
3763 else:
3763 else:
3764 spaces = " " * (30 - encoding.colwidth(t))
3764 spaces = " " * (30 - encoding.colwidth(t))
3765 if ui.verbose:
3765 if ui.verbose:
3766 if repo.tagtype(t) == 'local':
3766 if repo.tagtype(t) == 'local':
3767 tagtype = " local"
3767 tagtype = " local"
3768 else:
3768 else:
3769 tagtype = ""
3769 tagtype = ""
3770 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3770 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3771
3771
3772 def tip(ui, repo, **opts):
3772 def tip(ui, repo, **opts):
3773 """show the tip revision
3773 """show the tip revision
3774
3774
3775 The tip revision (usually just called the tip) is the changeset
3775 The tip revision (usually just called the tip) is the changeset
3776 most recently added to the repository (and therefore the most
3776 most recently added to the repository (and therefore the most
3777 recently changed head).
3777 recently changed head).
3778
3778
3779 If you have just made a commit, that commit will be the tip. If
3779 If you have just made a commit, that commit will be the tip. If
3780 you have just pulled changes from another repository, the tip of
3780 you have just pulled changes from another repository, the tip of
3781 that repository becomes the current tip. The "tip" tag is special
3781 that repository becomes the current tip. The "tip" tag is special
3782 and cannot be renamed or assigned to a different changeset.
3782 and cannot be renamed or assigned to a different changeset.
3783
3783
3784 Returns 0 on success.
3784 Returns 0 on success.
3785 """
3785 """
3786 displayer = cmdutil.show_changeset(ui, repo, opts)
3786 displayer = cmdutil.show_changeset(ui, repo, opts)
3787 displayer.show(repo[len(repo) - 1])
3787 displayer.show(repo[len(repo) - 1])
3788 displayer.close()
3788 displayer.close()
3789
3789
3790 def unbundle(ui, repo, fname1, *fnames, **opts):
3790 def unbundle(ui, repo, fname1, *fnames, **opts):
3791 """apply one or more changegroup files
3791 """apply one or more changegroup files
3792
3792
3793 Apply one or more compressed changegroup files generated by the
3793 Apply one or more compressed changegroup files generated by the
3794 bundle command.
3794 bundle command.
3795
3795
3796 Returns 0 on success, 1 if an update has unresolved files.
3796 Returns 0 on success, 1 if an update has unresolved files.
3797 """
3797 """
3798 fnames = (fname1,) + fnames
3798 fnames = (fname1,) + fnames
3799
3799
3800 lock = repo.lock()
3800 lock = repo.lock()
3801 try:
3801 try:
3802 for fname in fnames:
3802 for fname in fnames:
3803 f = url.open(ui, fname)
3803 f = url.open(ui, fname)
3804 gen = changegroup.readbundle(f, fname)
3804 gen = changegroup.readbundle(f, fname)
3805 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3805 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3806 lock=lock)
3806 lock=lock)
3807 finally:
3807 finally:
3808 lock.release()
3808 lock.release()
3809
3809
3810 return postincoming(ui, repo, modheads, opts.get('update'), None)
3810 return postincoming(ui, repo, modheads, opts.get('update'), None)
3811
3811
3812 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3812 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3813 """update working directory (or switch revisions)
3813 """update working directory (or switch revisions)
3814
3814
3815 Update the repository's working directory to the specified
3815 Update the repository's working directory to the specified
3816 changeset. If no changeset is specified, update to the tip of the
3816 changeset. If no changeset is specified, update to the tip of the
3817 current named branch.
3817 current named branch.
3818
3818
3819 If the changeset is not a descendant of the working directory's
3819 If the changeset is not a descendant of the working directory's
3820 parent, the update is aborted. With the -c/--check option, the
3820 parent, the update is aborted. With the -c/--check option, the
3821 working directory is checked for uncommitted changes; if none are
3821 working directory is checked for uncommitted changes; if none are
3822 found, the working directory is updated to the specified
3822 found, the working directory is updated to the specified
3823 changeset.
3823 changeset.
3824
3824
3825 The following rules apply when the working directory contains
3825 The following rules apply when the working directory contains
3826 uncommitted changes:
3826 uncommitted changes:
3827
3827
3828 1. If neither -c/--check nor -C/--clean is specified, and if
3828 1. If neither -c/--check nor -C/--clean is specified, and if
3829 the requested changeset is an ancestor or descendant of
3829 the requested changeset is an ancestor or descendant of
3830 the working directory's parent, the uncommitted changes
3830 the working directory's parent, the uncommitted changes
3831 are merged into the requested changeset and the merged
3831 are merged into the requested changeset and the merged
3832 result is left uncommitted. If the requested changeset is
3832 result is left uncommitted. If the requested changeset is
3833 not an ancestor or descendant (that is, it is on another
3833 not an ancestor or descendant (that is, it is on another
3834 branch), the update is aborted and the uncommitted changes
3834 branch), the update is aborted and the uncommitted changes
3835 are preserved.
3835 are preserved.
3836
3836
3837 2. With the -c/--check option, the update is aborted and the
3837 2. With the -c/--check option, the update is aborted and the
3838 uncommitted changes are preserved.
3838 uncommitted changes are preserved.
3839
3839
3840 3. With the -C/--clean option, uncommitted changes are discarded and
3840 3. With the -C/--clean option, uncommitted changes are discarded and
3841 the working directory is updated to the requested changeset.
3841 the working directory is updated to the requested changeset.
3842
3842
3843 Use null as the changeset to remove the working directory (like
3843 Use null as the changeset to remove the working directory (like
3844 :hg:`clone -U`).
3844 :hg:`clone -U`).
3845
3845
3846 If you want to update just one file to an older changeset, use
3846 If you want to update just one file to an older changeset, use
3847 :hg:`revert`.
3847 :hg:`revert`.
3848
3848
3849 See :hg:`help dates` for a list of formats valid for -d/--date.
3849 See :hg:`help dates` for a list of formats valid for -d/--date.
3850
3850
3851 Returns 0 on success, 1 if there are unresolved files.
3851 Returns 0 on success, 1 if there are unresolved files.
3852 """
3852 """
3853 if rev and node:
3853 if rev and node:
3854 raise util.Abort(_("please specify just one revision"))
3854 raise util.Abort(_("please specify just one revision"))
3855
3855
3856 if not rev:
3856 if not rev:
3857 rev = node
3857 rev = node
3858
3858
3859 rev = cmdutil.revsingle(repo, rev, rev).rev()
3859 rev = cmdutil.revsingle(repo, rev, rev).rev()
3860
3860
3861 if check and clean:
3861 if check and clean:
3862 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3862 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3863
3863
3864 if check:
3864 if check:
3865 # we could use dirty() but we can ignore merge and branch trivia
3865 # we could use dirty() but we can ignore merge and branch trivia
3866 c = repo[None]
3866 c = repo[None]
3867 if c.modified() or c.added() or c.removed():
3867 if c.modified() or c.added() or c.removed():
3868 raise util.Abort(_("uncommitted local changes"))
3868 raise util.Abort(_("uncommitted local changes"))
3869
3869
3870 if date:
3870 if date:
3871 if rev:
3871 if rev:
3872 raise util.Abort(_("you can't specify a revision and a date"))
3872 raise util.Abort(_("you can't specify a revision and a date"))
3873 rev = cmdutil.finddate(ui, repo, date)
3873 rev = cmdutil.finddate(ui, repo, date)
3874
3874
3875 if clean or check:
3875 if clean or check:
3876 return hg.clean(repo, rev)
3876 return hg.clean(repo, rev)
3877 else:
3877 else:
3878 return hg.update(repo, rev)
3878 return hg.update(repo, rev)
3879
3879
3880 def verify(ui, repo):
3880 def verify(ui, repo):
3881 """verify the integrity of the repository
3881 """verify the integrity of the repository
3882
3882
3883 Verify the integrity of the current repository.
3883 Verify the integrity of the current repository.
3884
3884
3885 This will perform an extensive check of the repository's
3885 This will perform an extensive check of the repository's
3886 integrity, validating the hashes and checksums of each entry in
3886 integrity, validating the hashes and checksums of each entry in
3887 the changelog, manifest, and tracked files, as well as the
3887 the changelog, manifest, and tracked files, as well as the
3888 integrity of their crosslinks and indices.
3888 integrity of their crosslinks and indices.
3889
3889
3890 Returns 0 on success, 1 if errors are encountered.
3890 Returns 0 on success, 1 if errors are encountered.
3891 """
3891 """
3892 return hg.verify(repo)
3892 return hg.verify(repo)
3893
3893
3894 def version_(ui):
3894 def version_(ui):
3895 """output version and copyright information"""
3895 """output version and copyright information"""
3896 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3896 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3897 % util.version())
3897 % util.version())
3898 ui.status(_(
3898 ui.status(_(
3899 "(see http://mercurial.selenic.com for more information)\n"
3899 "(see http://mercurial.selenic.com for more information)\n"
3900 "\nCopyright (C) 2005-2010 Matt Mackall and others\n"
3900 "\nCopyright (C) 2005-2010 Matt Mackall and others\n"
3901 "This is free software; see the source for copying conditions. "
3901 "This is free software; see the source for copying conditions. "
3902 "There is NO\nwarranty; "
3902 "There is NO\nwarranty; "
3903 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3903 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3904 ))
3904 ))
3905
3905
3906 # Command options and aliases are listed here, alphabetically
3906 # Command options and aliases are listed here, alphabetically
3907
3907
3908 globalopts = [
3908 globalopts = [
3909 ('R', 'repository', '',
3909 ('R', 'repository', '',
3910 _('repository root directory or name of overlay bundle file'),
3910 _('repository root directory or name of overlay bundle file'),
3911 _('REPO')),
3911 _('REPO')),
3912 ('', 'cwd', '',
3912 ('', 'cwd', '',
3913 _('change working directory'), _('DIR')),
3913 _('change working directory'), _('DIR')),
3914 ('y', 'noninteractive', None,
3914 ('y', 'noninteractive', None,
3915 _('do not prompt, assume \'yes\' for any required answers')),
3915 _('do not prompt, assume \'yes\' for any required answers')),
3916 ('q', 'quiet', None, _('suppress output')),
3916 ('q', 'quiet', None, _('suppress output')),
3917 ('v', 'verbose', None, _('enable additional output')),
3917 ('v', 'verbose', None, _('enable additional output')),
3918 ('', 'config', [],
3918 ('', 'config', [],
3919 _('set/override config option (use \'section.name=value\')'),
3919 _('set/override config option (use \'section.name=value\')'),
3920 _('CONFIG')),
3920 _('CONFIG')),
3921 ('', 'debug', None, _('enable debugging output')),
3921 ('', 'debug', None, _('enable debugging output')),
3922 ('', 'debugger', None, _('start debugger')),
3922 ('', 'debugger', None, _('start debugger')),
3923 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3923 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3924 _('ENCODE')),
3924 _('ENCODE')),
3925 ('', 'encodingmode', encoding.encodingmode,
3925 ('', 'encodingmode', encoding.encodingmode,
3926 _('set the charset encoding mode'), _('MODE')),
3926 _('set the charset encoding mode'), _('MODE')),
3927 ('', 'traceback', None, _('always print a traceback on exception')),
3927 ('', 'traceback', None, _('always print a traceback on exception')),
3928 ('', 'time', None, _('time how long the command takes')),
3928 ('', 'time', None, _('time how long the command takes')),
3929 ('', 'profile', None, _('print command execution profile')),
3929 ('', 'profile', None, _('print command execution profile')),
3930 ('', 'version', None, _('output version information and exit')),
3930 ('', 'version', None, _('output version information and exit')),
3931 ('h', 'help', None, _('display help and exit')),
3931 ('h', 'help', None, _('display help and exit')),
3932 ]
3932 ]
3933
3933
3934 dryrunopts = [('n', 'dry-run', None,
3934 dryrunopts = [('n', 'dry-run', None,
3935 _('do not perform actions, just print output'))]
3935 _('do not perform actions, just print output'))]
3936
3936
3937 remoteopts = [
3937 remoteopts = [
3938 ('e', 'ssh', '',
3938 ('e', 'ssh', '',
3939 _('specify ssh command to use'), _('CMD')),
3939 _('specify ssh command to use'), _('CMD')),
3940 ('', 'remotecmd', '',
3940 ('', 'remotecmd', '',
3941 _('specify hg command to run on the remote side'), _('CMD')),
3941 _('specify hg command to run on the remote side'), _('CMD')),
3942 ]
3942 ]
3943
3943
3944 walkopts = [
3944 walkopts = [
3945 ('I', 'include', [],
3945 ('I', 'include', [],
3946 _('include names matching the given patterns'), _('PATTERN')),
3946 _('include names matching the given patterns'), _('PATTERN')),
3947 ('X', 'exclude', [],
3947 ('X', 'exclude', [],
3948 _('exclude names matching the given patterns'), _('PATTERN')),
3948 _('exclude names matching the given patterns'), _('PATTERN')),
3949 ]
3949 ]
3950
3950
3951 commitopts = [
3951 commitopts = [
3952 ('m', 'message', '',
3952 ('m', 'message', '',
3953 _('use text as commit message'), _('TEXT')),
3953 _('use text as commit message'), _('TEXT')),
3954 ('l', 'logfile', '',
3954 ('l', 'logfile', '',
3955 _('read commit message from file'), _('FILE')),
3955 _('read commit message from file'), _('FILE')),
3956 ]
3956 ]
3957
3957
3958 commitopts2 = [
3958 commitopts2 = [
3959 ('d', 'date', '',
3959 ('d', 'date', '',
3960 _('record datecode as commit date'), _('DATE')),
3960 _('record datecode as commit date'), _('DATE')),
3961 ('u', 'user', '',
3961 ('u', 'user', '',
3962 _('record the specified user as committer'), _('USER')),
3962 _('record the specified user as committer'), _('USER')),
3963 ]
3963 ]
3964
3964
3965 templateopts = [
3965 templateopts = [
3966 ('', 'style', '',
3966 ('', 'style', '',
3967 _('display using template map file'), _('STYLE')),
3967 _('display using template map file'), _('STYLE')),
3968 ('', 'template', '',
3968 ('', 'template', '',
3969 _('display with template'), _('TEMPLATE')),
3969 _('display with template'), _('TEMPLATE')),
3970 ]
3970 ]
3971
3971
3972 logopts = [
3972 logopts = [
3973 ('p', 'patch', None, _('show patch')),
3973 ('p', 'patch', None, _('show patch')),
3974 ('g', 'git', None, _('use git extended diff format')),
3974 ('g', 'git', None, _('use git extended diff format')),
3975 ('l', 'limit', '',
3975 ('l', 'limit', '',
3976 _('limit number of changes displayed'), _('NUM')),
3976 _('limit number of changes displayed'), _('NUM')),
3977 ('M', 'no-merges', None, _('do not show merges')),
3977 ('M', 'no-merges', None, _('do not show merges')),
3978 ('', 'stat', None, _('output diffstat-style summary of changes')),
3978 ('', 'stat', None, _('output diffstat-style summary of changes')),
3979 ] + templateopts
3979 ] + templateopts
3980
3980
3981 diffopts = [
3981 diffopts = [
3982 ('a', 'text', None, _('treat all files as text')),
3982 ('a', 'text', None, _('treat all files as text')),
3983 ('g', 'git', None, _('use git extended diff format')),
3983 ('g', 'git', None, _('use git extended diff format')),
3984 ('', 'nodates', None, _('omit dates from diff headers'))
3984 ('', 'nodates', None, _('omit dates from diff headers'))
3985 ]
3985 ]
3986
3986
3987 diffopts2 = [
3987 diffopts2 = [
3988 ('p', 'show-function', None, _('show which function each change is in')),
3988 ('p', 'show-function', None, _('show which function each change is in')),
3989 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3989 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3990 ('w', 'ignore-all-space', None,
3990 ('w', 'ignore-all-space', None,
3991 _('ignore white space when comparing lines')),
3991 _('ignore white space when comparing lines')),
3992 ('b', 'ignore-space-change', None,
3992 ('b', 'ignore-space-change', None,
3993 _('ignore changes in the amount of white space')),
3993 _('ignore changes in the amount of white space')),
3994 ('B', 'ignore-blank-lines', None,
3994 ('B', 'ignore-blank-lines', None,
3995 _('ignore changes whose lines are all blank')),
3995 _('ignore changes whose lines are all blank')),
3996 ('U', 'unified', '',
3996 ('U', 'unified', '',
3997 _('number of lines of context to show'), _('NUM')),
3997 _('number of lines of context to show'), _('NUM')),
3998 ('', 'stat', None, _('output diffstat-style summary of changes')),
3998 ('', 'stat', None, _('output diffstat-style summary of changes')),
3999 ]
3999 ]
4000
4000
4001 similarityopts = [
4001 similarityopts = [
4002 ('s', 'similarity', '',
4002 ('s', 'similarity', '',
4003 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4003 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4004 ]
4004 ]
4005
4005
4006 subrepoopts = [
4006 subrepoopts = [
4007 ('S', 'subrepos', None,
4007 ('S', 'subrepos', None,
4008 _('recurse into subrepositories'))
4008 _('recurse into subrepositories'))
4009 ]
4009 ]
4010
4010
4011 table = {
4011 table = {
4012 "^add": (add, walkopts + subrepoopts + dryrunopts,
4012 "^add": (add, walkopts + subrepoopts + dryrunopts,
4013 _('[OPTION]... [FILE]...')),
4013 _('[OPTION]... [FILE]...')),
4014 "addremove":
4014 "addremove":
4015 (addremove, similarityopts + walkopts + dryrunopts,
4015 (addremove, similarityopts + walkopts + dryrunopts,
4016 _('[OPTION]... [FILE]...')),
4016 _('[OPTION]... [FILE]...')),
4017 "^annotate|blame":
4017 "^annotate|blame":
4018 (annotate,
4018 (annotate,
4019 [('r', 'rev', '',
4019 [('r', 'rev', '',
4020 _('annotate the specified revision'), _('REV')),
4020 _('annotate the specified revision'), _('REV')),
4021 ('', 'follow', None,
4021 ('', 'follow', None,
4022 _('follow copies/renames and list the filename (DEPRECATED)')),
4022 _('follow copies/renames and list the filename (DEPRECATED)')),
4023 ('', 'no-follow', None, _("don't follow copies and renames")),
4023 ('', 'no-follow', None, _("don't follow copies and renames")),
4024 ('a', 'text', None, _('treat all files as text')),
4024 ('a', 'text', None, _('treat all files as text')),
4025 ('u', 'user', None, _('list the author (long with -v)')),
4025 ('u', 'user', None, _('list the author (long with -v)')),
4026 ('f', 'file', None, _('list the filename')),
4026 ('f', 'file', None, _('list the filename')),
4027 ('d', 'date', None, _('list the date (short with -q)')),
4027 ('d', 'date', None, _('list the date (short with -q)')),
4028 ('n', 'number', None, _('list the revision number (default)')),
4028 ('n', 'number', None, _('list the revision number (default)')),
4029 ('c', 'changeset', None, _('list the changeset')),
4029 ('c', 'changeset', None, _('list the changeset')),
4030 ('l', 'line-number', None,
4030 ('l', 'line-number', None,
4031 _('show line number at the first appearance'))
4031 _('show line number at the first appearance'))
4032 ] + walkopts,
4032 ] + walkopts,
4033 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4033 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4034 "archive":
4034 "archive":
4035 (archive,
4035 (archive,
4036 [('', 'no-decode', None, _('do not pass files through decoders')),
4036 [('', 'no-decode', None, _('do not pass files through decoders')),
4037 ('p', 'prefix', '',
4037 ('p', 'prefix', '',
4038 _('directory prefix for files in archive'), _('PREFIX')),
4038 _('directory prefix for files in archive'), _('PREFIX')),
4039 ('r', 'rev', '',
4039 ('r', 'rev', '',
4040 _('revision to distribute'), _('REV')),
4040 _('revision to distribute'), _('REV')),
4041 ('t', 'type', '',
4041 ('t', 'type', '',
4042 _('type of distribution to create'), _('TYPE')),
4042 _('type of distribution to create'), _('TYPE')),
4043 ] + subrepoopts + walkopts,
4043 ] + subrepoopts + walkopts,
4044 _('[OPTION]... DEST')),
4044 _('[OPTION]... DEST')),
4045 "backout":
4045 "backout":
4046 (backout,
4046 (backout,
4047 [('', 'merge', None,
4047 [('', 'merge', None,
4048 _('merge with old dirstate parent after backout')),
4048 _('merge with old dirstate parent after backout')),
4049 ('', 'parent', '',
4049 ('', 'parent', '',
4050 _('parent to choose when backing out merge'), _('REV')),
4050 _('parent to choose when backing out merge'), _('REV')),
4051 ('t', 'tool', '',
4051 ('t', 'tool', '',
4052 _('specify merge tool')),
4052 _('specify merge tool')),
4053 ('r', 'rev', '',
4053 ('r', 'rev', '',
4054 _('revision to backout'), _('REV')),
4054 _('revision to backout'), _('REV')),
4055 ] + walkopts + commitopts + commitopts2,
4055 ] + walkopts + commitopts + commitopts2,
4056 _('[OPTION]... [-r] REV')),
4056 _('[OPTION]... [-r] REV')),
4057 "bisect":
4057 "bisect":
4058 (bisect,
4058 (bisect,
4059 [('r', 'reset', False, _('reset bisect state')),
4059 [('r', 'reset', False, _('reset bisect state')),
4060 ('g', 'good', False, _('mark changeset good')),
4060 ('g', 'good', False, _('mark changeset good')),
4061 ('b', 'bad', False, _('mark changeset bad')),
4061 ('b', 'bad', False, _('mark changeset bad')),
4062 ('s', 'skip', False, _('skip testing changeset')),
4062 ('s', 'skip', False, _('skip testing changeset')),
4063 ('c', 'command', '',
4063 ('c', 'command', '',
4064 _('use command to check changeset state'), _('CMD')),
4064 _('use command to check changeset state'), _('CMD')),
4065 ('U', 'noupdate', False, _('do not update to target'))],
4065 ('U', 'noupdate', False, _('do not update to target'))],
4066 _("[-gbsr] [-U] [-c CMD] [REV]")),
4066 _("[-gbsr] [-U] [-c CMD] [REV]")),
4067 "branch":
4067 "branch":
4068 (branch,
4068 (branch,
4069 [('f', 'force', None,
4069 [('f', 'force', None,
4070 _('set branch name even if it shadows an existing branch')),
4070 _('set branch name even if it shadows an existing branch')),
4071 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4071 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4072 _('[-fC] [NAME]')),
4072 _('[-fC] [NAME]')),
4073 "branches":
4073 "branches":
4074 (branches,
4074 (branches,
4075 [('a', 'active', False,
4075 [('a', 'active', False,
4076 _('show only branches that have unmerged heads')),
4076 _('show only branches that have unmerged heads')),
4077 ('c', 'closed', False,
4077 ('c', 'closed', False,
4078 _('show normal and closed branches'))],
4078 _('show normal and closed branches'))],
4079 _('[-ac]')),
4079 _('[-ac]')),
4080 "bundle":
4080 "bundle":
4081 (bundle,
4081 (bundle,
4082 [('f', 'force', None,
4082 [('f', 'force', None,
4083 _('run even when the destination is unrelated')),
4083 _('run even when the destination is unrelated')),
4084 ('r', 'rev', [],
4084 ('r', 'rev', [],
4085 _('a changeset intended to be added to the destination'),
4085 _('a changeset intended to be added to the destination'),
4086 _('REV')),
4086 _('REV')),
4087 ('b', 'branch', [],
4087 ('b', 'branch', [],
4088 _('a specific branch you would like to bundle'),
4088 _('a specific branch you would like to bundle'),
4089 _('BRANCH')),
4089 _('BRANCH')),
4090 ('', 'base', [],
4090 ('', 'base', [],
4091 _('a base changeset assumed to be available at the destination'),
4091 _('a base changeset assumed to be available at the destination'),
4092 _('REV')),
4092 _('REV')),
4093 ('a', 'all', None, _('bundle all changesets in the repository')),
4093 ('a', 'all', None, _('bundle all changesets in the repository')),
4094 ('t', 'type', 'bzip2',
4094 ('t', 'type', 'bzip2',
4095 _('bundle compression type to use'), _('TYPE')),
4095 _('bundle compression type to use'), _('TYPE')),
4096 ] + remoteopts,
4096 ] + remoteopts,
4097 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4097 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4098 "cat":
4098 "cat":
4099 (cat,
4099 (cat,
4100 [('o', 'output', '',
4100 [('o', 'output', '',
4101 _('print output to file with formatted name'), _('FORMAT')),
4101 _('print output to file with formatted name'), _('FORMAT')),
4102 ('r', 'rev', '',
4102 ('r', 'rev', '',
4103 _('print the given revision'), _('REV')),
4103 _('print the given revision'), _('REV')),
4104 ('', 'decode', None, _('apply any matching decode filter')),
4104 ('', 'decode', None, _('apply any matching decode filter')),
4105 ] + walkopts,
4105 ] + walkopts,
4106 _('[OPTION]... FILE...')),
4106 _('[OPTION]... FILE...')),
4107 "^clone":
4107 "^clone":
4108 (clone,
4108 (clone,
4109 [('U', 'noupdate', None,
4109 [('U', 'noupdate', None,
4110 _('the clone will include an empty working copy (only a repository)')),
4110 _('the clone will include an empty working copy (only a repository)')),
4111 ('u', 'updaterev', '',
4111 ('u', 'updaterev', '',
4112 _('revision, tag or branch to check out'), _('REV')),
4112 _('revision, tag or branch to check out'), _('REV')),
4113 ('r', 'rev', [],
4113 ('r', 'rev', [],
4114 _('include the specified changeset'), _('REV')),
4114 _('include the specified changeset'), _('REV')),
4115 ('b', 'branch', [],
4115 ('b', 'branch', [],
4116 _('clone only the specified branch'), _('BRANCH')),
4116 _('clone only the specified branch'), _('BRANCH')),
4117 ('', 'pull', None, _('use pull protocol to copy metadata')),
4117 ('', 'pull', None, _('use pull protocol to copy metadata')),
4118 ('', 'uncompressed', None,
4118 ('', 'uncompressed', None,
4119 _('use uncompressed transfer (fast over LAN)')),
4119 _('use uncompressed transfer (fast over LAN)')),
4120 ] + remoteopts,
4120 ] + remoteopts,
4121 _('[OPTION]... SOURCE [DEST]')),
4121 _('[OPTION]... SOURCE [DEST]')),
4122 "^commit|ci":
4122 "^commit|ci":
4123 (commit,
4123 (commit,
4124 [('A', 'addremove', None,
4124 [('A', 'addremove', None,
4125 _('mark new/missing files as added/removed before committing')),
4125 _('mark new/missing files as added/removed before committing')),
4126 ('', 'close-branch', None,
4126 ('', 'close-branch', None,
4127 _('mark a branch as closed, hiding it from the branch list')),
4127 _('mark a branch as closed, hiding it from the branch list')),
4128 ] + walkopts + commitopts + commitopts2,
4128 ] + walkopts + commitopts + commitopts2,
4129 _('[OPTION]... [FILE]...')),
4129 _('[OPTION]... [FILE]...')),
4130 "copy|cp":
4130 "copy|cp":
4131 (copy,
4131 (copy,
4132 [('A', 'after', None, _('record a copy that has already occurred')),
4132 [('A', 'after', None, _('record a copy that has already occurred')),
4133 ('f', 'force', None,
4133 ('f', 'force', None,
4134 _('forcibly copy over an existing managed file')),
4134 _('forcibly copy over an existing managed file')),
4135 ] + walkopts + dryrunopts,
4135 ] + walkopts + dryrunopts,
4136 _('[OPTION]... [SOURCE]... DEST')),
4136 _('[OPTION]... [SOURCE]... DEST')),
4137 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4137 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4138 "debugbuilddag":
4138 "debugbuilddag":
4139 (debugbuilddag,
4139 (debugbuilddag,
4140 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4140 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4141 ('a', 'appended-file', None, _('add single file all revs append to')),
4141 ('a', 'appended-file', None, _('add single file all revs append to')),
4142 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4142 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4143 ('n', 'new-file', None, _('add new file at each rev')),
4143 ('n', 'new-file', None, _('add new file at each rev')),
4144 ],
4144 ],
4145 _('[OPTION]... TEXT')),
4145 _('[OPTION]... TEXT')),
4146 "debugcheckstate": (debugcheckstate, [], ''),
4146 "debugcheckstate": (debugcheckstate, [], ''),
4147 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4147 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4148 "debugcomplete":
4148 "debugcomplete":
4149 (debugcomplete,
4149 (debugcomplete,
4150 [('o', 'options', None, _('show the command options'))],
4150 [('o', 'options', None, _('show the command options'))],
4151 _('[-o] CMD')),
4151 _('[-o] CMD')),
4152 "debugdag":
4152 "debugdag":
4153 (debugdag,
4153 (debugdag,
4154 [('t', 'tags', None, _('use tags as labels')),
4154 [('t', 'tags', None, _('use tags as labels')),
4155 ('b', 'branches', None, _('annotate with branch names')),
4155 ('b', 'branches', None, _('annotate with branch names')),
4156 ('', 'dots', None, _('use dots for runs')),
4156 ('', 'dots', None, _('use dots for runs')),
4157 ('s', 'spaces', None, _('separate elements by spaces')),
4157 ('s', 'spaces', None, _('separate elements by spaces')),
4158 ],
4158 ],
4159 _('[OPTION]... [FILE [REV]...]')),
4159 _('[OPTION]... [FILE [REV]...]')),
4160 "debugdate":
4160 "debugdate":
4161 (debugdate,
4161 (debugdate,
4162 [('e', 'extended', None, _('try extended date formats'))],
4162 [('e', 'extended', None, _('try extended date formats'))],
4163 _('[-e] DATE [RANGE]')),
4163 _('[-e] DATE [RANGE]')),
4164 "debugdata": (debugdata, [], _('FILE REV')),
4164 "debugdata": (debugdata, [], _('FILE REV')),
4165 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4165 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4166 "debugindex": (debugindex,
4166 "debugindex": (debugindex,
4167 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4167 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4168 _('FILE')),
4168 _('FILE')),
4169 "debugindexdot": (debugindexdot, [], _('FILE')),
4169 "debugindexdot": (debugindexdot, [], _('FILE')),
4170 "debuginstall": (debuginstall, [], ''),
4170 "debuginstall": (debuginstall, [], ''),
4171 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4171 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4172 "debugrebuildstate":
4172 "debugrebuildstate":
4173 (debugrebuildstate,
4173 (debugrebuildstate,
4174 [('r', 'rev', '',
4174 [('r', 'rev', '',
4175 _('revision to rebuild to'), _('REV'))],
4175 _('revision to rebuild to'), _('REV'))],
4176 _('[-r REV] [REV]')),
4176 _('[-r REV] [REV]')),
4177 "debugrename":
4177 "debugrename":
4178 (debugrename,
4178 (debugrename,
4179 [('r', 'rev', '',
4179 [('r', 'rev', '',
4180 _('revision to debug'), _('REV'))],
4180 _('revision to debug'), _('REV'))],
4181 _('[-r REV] FILE')),
4181 _('[-r REV] FILE')),
4182 "debugrevspec":
4182 "debugrevspec":
4183 (debugrevspec, [], ('REVSPEC')),
4183 (debugrevspec, [], ('REVSPEC')),
4184 "debugsetparents":
4184 "debugsetparents":
4185 (debugsetparents, [], _('REV1 [REV2]')),
4185 (debugsetparents, [], _('REV1 [REV2]')),
4186 "debugstate":
4186 "debugstate":
4187 (debugstate,
4187 (debugstate,
4188 [('', 'nodates', None, _('do not display the saved mtime'))],
4188 [('', 'nodates', None, _('do not display the saved mtime'))],
4189 _('[OPTION]...')),
4189 _('[OPTION]...')),
4190 "debugsub":
4190 "debugsub":
4191 (debugsub,
4191 (debugsub,
4192 [('r', 'rev', '',
4192 [('r', 'rev', '',
4193 _('revision to check'), _('REV'))],
4193 _('revision to check'), _('REV'))],
4194 _('[-r REV] [REV]')),
4194 _('[-r REV] [REV]')),
4195 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4195 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4196 "^diff":
4196 "^diff":
4197 (diff,
4197 (diff,
4198 [('r', 'rev', [],
4198 [('r', 'rev', [],
4199 _('revision'), _('REV')),
4199 _('revision'), _('REV')),
4200 ('c', 'change', '',
4200 ('c', 'change', '',
4201 _('change made by revision'), _('REV'))
4201 _('change made by revision'), _('REV'))
4202 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4202 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4203 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4203 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4204 "^export":
4204 "^export":
4205 (export,
4205 (export,
4206 [('o', 'output', '',
4206 [('o', 'output', '',
4207 _('print output to file with formatted name'), _('FORMAT')),
4207 _('print output to file with formatted name'), _('FORMAT')),
4208 ('', 'switch-parent', None, _('diff against the second parent')),
4208 ('', 'switch-parent', None, _('diff against the second parent')),
4209 ('r', 'rev', [],
4209 ('r', 'rev', [],
4210 _('revisions to export'), _('REV')),
4210 _('revisions to export'), _('REV')),
4211 ] + diffopts,
4211 ] + diffopts,
4212 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4212 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4213 "^forget":
4213 "^forget":
4214 (forget,
4214 (forget,
4215 [] + walkopts,
4215 [] + walkopts,
4216 _('[OPTION]... FILE...')),
4216 _('[OPTION]... FILE...')),
4217 "grep":
4217 "grep":
4218 (grep,
4218 (grep,
4219 [('0', 'print0', None, _('end fields with NUL')),
4219 [('0', 'print0', None, _('end fields with NUL')),
4220 ('', 'all', None, _('print all revisions that match')),
4220 ('', 'all', None, _('print all revisions that match')),
4221 ('f', 'follow', None,
4221 ('f', 'follow', None,
4222 _('follow changeset history,'
4222 _('follow changeset history,'
4223 ' or file history across copies and renames')),
4223 ' or file history across copies and renames')),
4224 ('i', 'ignore-case', None, _('ignore case when matching')),
4224 ('i', 'ignore-case', None, _('ignore case when matching')),
4225 ('l', 'files-with-matches', None,
4225 ('l', 'files-with-matches', None,
4226 _('print only filenames and revisions that match')),
4226 _('print only filenames and revisions that match')),
4227 ('n', 'line-number', None, _('print matching line numbers')),
4227 ('n', 'line-number', None, _('print matching line numbers')),
4228 ('r', 'rev', [],
4228 ('r', 'rev', [],
4229 _('only search files changed within revision range'), _('REV')),
4229 _('only search files changed within revision range'), _('REV')),
4230 ('u', 'user', None, _('list the author (long with -v)')),
4230 ('u', 'user', None, _('list the author (long with -v)')),
4231 ('d', 'date', None, _('list the date (short with -q)')),
4231 ('d', 'date', None, _('list the date (short with -q)')),
4232 ] + walkopts,
4232 ] + walkopts,
4233 _('[OPTION]... PATTERN [FILE]...')),
4233 _('[OPTION]... PATTERN [FILE]...')),
4234 "heads":
4234 "heads":
4235 (heads,
4235 (heads,
4236 [('r', 'rev', '',
4236 [('r', 'rev', '',
4237 _('show only heads which are descendants of STARTREV'),
4237 _('show only heads which are descendants of STARTREV'),
4238 _('STARTREV')),
4238 _('STARTREV')),
4239 ('t', 'topo', False, _('show topological heads only')),
4239 ('t', 'topo', False, _('show topological heads only')),
4240 ('a', 'active', False,
4240 ('a', 'active', False,
4241 _('show active branchheads only (DEPRECATED)')),
4241 _('show active branchheads only (DEPRECATED)')),
4242 ('c', 'closed', False,
4242 ('c', 'closed', False,
4243 _('show normal and closed branch heads')),
4243 _('show normal and closed branch heads')),
4244 ] + templateopts,
4244 ] + templateopts,
4245 _('[-ac] [-r STARTREV] [REV]...')),
4245 _('[-ac] [-r STARTREV] [REV]...')),
4246 "help": (help_, [], _('[TOPIC]')),
4246 "help": (help_, [], _('[TOPIC]')),
4247 "identify|id":
4247 "identify|id":
4248 (identify,
4248 (identify,
4249 [('r', 'rev', '',
4249 [('r', 'rev', '',
4250 _('identify the specified revision'), _('REV')),
4250 _('identify the specified revision'), _('REV')),
4251 ('n', 'num', None, _('show local revision number')),
4251 ('n', 'num', None, _('show local revision number')),
4252 ('i', 'id', None, _('show global revision id')),
4252 ('i', 'id', None, _('show global revision id')),
4253 ('b', 'branch', None, _('show branch')),
4253 ('b', 'branch', None, _('show branch')),
4254 ('t', 'tags', None, _('show tags'))],
4254 ('t', 'tags', None, _('show tags'))],
4255 _('[-nibt] [-r REV] [SOURCE]')),
4255 _('[-nibt] [-r REV] [SOURCE]')),
4256 "import|patch":
4256 "import|patch":
4257 (import_,
4257 (import_,
4258 [('p', 'strip', 1,
4258 [('p', 'strip', 1,
4259 _('directory strip option for patch. This has the same '
4259 _('directory strip option for patch. This has the same '
4260 'meaning as the corresponding patch option'),
4260 'meaning as the corresponding patch option'),
4261 _('NUM')),
4261 _('NUM')),
4262 ('b', 'base', '',
4262 ('b', 'base', '',
4263 _('base path'), _('PATH')),
4263 _('base path'), _('PATH')),
4264 ('f', 'force', None,
4264 ('f', 'force', None,
4265 _('skip check for outstanding uncommitted changes')),
4265 _('skip check for outstanding uncommitted changes')),
4266 ('', 'no-commit', None,
4266 ('', 'no-commit', None,
4267 _("don't commit, just update the working directory")),
4267 _("don't commit, just update the working directory")),
4268 ('', 'exact', None,
4268 ('', 'exact', None,
4269 _('apply patch to the nodes from which it was generated')),
4269 _('apply patch to the nodes from which it was generated')),
4270 ('', 'import-branch', None,
4270 ('', 'import-branch', None,
4271 _('use any branch information in patch (implied by --exact)'))] +
4271 _('use any branch information in patch (implied by --exact)'))] +
4272 commitopts + commitopts2 + similarityopts,
4272 commitopts + commitopts2 + similarityopts,
4273 _('[OPTION]... PATCH...')),
4273 _('[OPTION]... PATCH...')),
4274 "incoming|in":
4274 "incoming|in":
4275 (incoming,
4275 (incoming,
4276 [('f', 'force', None,
4276 [('f', 'force', None,
4277 _('run even if remote repository is unrelated')),
4277 _('run even if remote repository is unrelated')),
4278 ('n', 'newest-first', None, _('show newest record first')),
4278 ('n', 'newest-first', None, _('show newest record first')),
4279 ('', 'bundle', '',
4279 ('', 'bundle', '',
4280 _('file to store the bundles into'), _('FILE')),
4280 _('file to store the bundles into'), _('FILE')),
4281 ('r', 'rev', [],
4281 ('r', 'rev', [],
4282 _('a remote changeset intended to be added'), _('REV')),
4282 _('a remote changeset intended to be added'), _('REV')),
4283 ('b', 'branch', [],
4283 ('b', 'branch', [],
4284 _('a specific branch you would like to pull'), _('BRANCH')),
4284 _('a specific branch you would like to pull'), _('BRANCH')),
4285 ] + logopts + remoteopts + subrepoopts,
4285 ] + logopts + remoteopts + subrepoopts,
4286 _('[-p] [-n] [-M] [-f] [-r REV]...'
4286 _('[-p] [-n] [-M] [-f] [-r REV]...'
4287 ' [--bundle FILENAME] [SOURCE]')),
4287 ' [--bundle FILENAME] [SOURCE]')),
4288 "^init":
4288 "^init":
4289 (init,
4289 (init,
4290 remoteopts,
4290 remoteopts,
4291 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4291 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4292 "locate":
4292 "locate":
4293 (locate,
4293 (locate,
4294 [('r', 'rev', '',
4294 [('r', 'rev', '',
4295 _('search the repository as it is in REV'), _('REV')),
4295 _('search the repository as it is in REV'), _('REV')),
4296 ('0', 'print0', None,
4296 ('0', 'print0', None,
4297 _('end filenames with NUL, for use with xargs')),
4297 _('end filenames with NUL, for use with xargs')),
4298 ('f', 'fullpath', None,
4298 ('f', 'fullpath', None,
4299 _('print complete paths from the filesystem root')),
4299 _('print complete paths from the filesystem root')),
4300 ] + walkopts,
4300 ] + walkopts,
4301 _('[OPTION]... [PATTERN]...')),
4301 _('[OPTION]... [PATTERN]...')),
4302 "^log|history":
4302 "^log|history":
4303 (log,
4303 (log,
4304 [('f', 'follow', None,
4304 [('f', 'follow', None,
4305 _('follow changeset history,'
4305 _('follow changeset history,'
4306 ' or file history across copies and renames')),
4306 ' or file history across copies and renames')),
4307 ('', 'follow-first', None,
4307 ('', 'follow-first', None,
4308 _('only follow the first parent of merge changesets')),
4308 _('only follow the first parent of merge changesets')),
4309 ('d', 'date', '',
4309 ('d', 'date', '',
4310 _('show revisions matching date spec'), _('DATE')),
4310 _('show revisions matching date spec'), _('DATE')),
4311 ('C', 'copies', None, _('show copied files')),
4311 ('C', 'copies', None, _('show copied files')),
4312 ('k', 'keyword', [],
4312 ('k', 'keyword', [],
4313 _('do case-insensitive search for a given text'), _('TEXT')),
4313 _('do case-insensitive search for a given text'), _('TEXT')),
4314 ('r', 'rev', [],
4314 ('r', 'rev', [],
4315 _('show the specified revision or range'), _('REV')),
4315 _('show the specified revision or range'), _('REV')),
4316 ('', 'removed', None, _('include revisions where files were removed')),
4316 ('', 'removed', None, _('include revisions where files were removed')),
4317 ('m', 'only-merges', None, _('show only merges')),
4317 ('m', 'only-merges', None, _('show only merges')),
4318 ('u', 'user', [],
4318 ('u', 'user', [],
4319 _('revisions committed by user'), _('USER')),
4319 _('revisions committed by user'), _('USER')),
4320 ('', 'only-branch', [],
4320 ('', 'only-branch', [],
4321 _('show only changesets within the given named branch (DEPRECATED)'),
4321 _('show only changesets within the given named branch (DEPRECATED)'),
4322 _('BRANCH')),
4322 _('BRANCH')),
4323 ('b', 'branch', [],
4323 ('b', 'branch', [],
4324 _('show changesets within the given named branch'), _('BRANCH')),
4324 _('show changesets within the given named branch'), _('BRANCH')),
4325 ('P', 'prune', [],
4325 ('P', 'prune', [],
4326 _('do not display revision or any of its ancestors'), _('REV')),
4326 _('do not display revision or any of its ancestors'), _('REV')),
4327 ] + logopts + walkopts,
4327 ] + logopts + walkopts,
4328 _('[OPTION]... [FILE]')),
4328 _('[OPTION]... [FILE]')),
4329 "manifest":
4329 "manifest":
4330 (manifest,
4330 (manifest,
4331 [('r', 'rev', '',
4331 [('r', 'rev', '',
4332 _('revision to display'), _('REV'))],
4332 _('revision to display'), _('REV'))],
4333 _('[-r REV]')),
4333 _('[-r REV]')),
4334 "^merge":
4334 "^merge":
4335 (merge,
4335 (merge,
4336 [('f', 'force', None, _('force a merge with outstanding changes')),
4336 [('f', 'force', None, _('force a merge with outstanding changes')),
4337 ('t', 'tool', '', _('specify merge tool')),
4337 ('t', 'tool', '', _('specify merge tool')),
4338 ('r', 'rev', '',
4338 ('r', 'rev', '',
4339 _('revision to merge'), _('REV')),
4339 _('revision to merge'), _('REV')),
4340 ('P', 'preview', None,
4340 ('P', 'preview', None,
4341 _('review revisions to merge (no merge is performed)'))],
4341 _('review revisions to merge (no merge is performed)'))],
4342 _('[-P] [-f] [[-r] REV]')),
4342 _('[-P] [-f] [[-r] REV]')),
4343 "outgoing|out":
4343 "outgoing|out":
4344 (outgoing,
4344 (outgoing,
4345 [('f', 'force', None,
4345 [('f', 'force', None,
4346 _('run even when the destination is unrelated')),
4346 _('run even when the destination is unrelated')),
4347 ('r', 'rev', [],
4347 ('r', 'rev', [],
4348 _('a changeset intended to be included in the destination'),
4348 _('a changeset intended to be included in the destination'),
4349 _('REV')),
4349 _('REV')),
4350 ('n', 'newest-first', None, _('show newest record first')),
4350 ('n', 'newest-first', None, _('show newest record first')),
4351 ('b', 'branch', [],
4351 ('b', 'branch', [],
4352 _('a specific branch you would like to push'), _('BRANCH')),
4352 _('a specific branch you would like to push'), _('BRANCH')),
4353 ] + logopts + remoteopts + subrepoopts,
4353 ] + logopts + remoteopts + subrepoopts,
4354 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4354 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4355 "parents":
4355 "parents":
4356 (parents,
4356 (parents,
4357 [('r', 'rev', '',
4357 [('r', 'rev', '',
4358 _('show parents of the specified revision'), _('REV')),
4358 _('show parents of the specified revision'), _('REV')),
4359 ] + templateopts,
4359 ] + templateopts,
4360 _('[-r REV] [FILE]')),
4360 _('[-r REV] [FILE]')),
4361 "paths": (paths, [], _('[NAME]')),
4361 "paths": (paths, [], _('[NAME]')),
4362 "^pull":
4362 "^pull":
4363 (pull,
4363 (pull,
4364 [('u', 'update', None,
4364 [('u', 'update', None,
4365 _('update to new branch head if changesets were pulled')),
4365 _('update to new branch head if changesets were pulled')),
4366 ('f', 'force', None,
4366 ('f', 'force', None,
4367 _('run even when remote repository is unrelated')),
4367 _('run even when remote repository is unrelated')),
4368 ('r', 'rev', [],
4368 ('r', 'rev', [],
4369 _('a remote changeset intended to be added'), _('REV')),
4369 _('a remote changeset intended to be added'), _('REV')),
4370 ('b', 'branch', [],
4370 ('b', 'branch', [],
4371 _('a specific branch you would like to pull'), _('BRANCH')),
4371 _('a specific branch you would like to pull'), _('BRANCH')),
4372 ] + remoteopts,
4372 ] + remoteopts,
4373 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4373 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4374 "^push":
4374 "^push":
4375 (push,
4375 (push,
4376 [('f', 'force', None, _('force push')),
4376 [('f', 'force', None, _('force push')),
4377 ('r', 'rev', [],
4377 ('r', 'rev', [],
4378 _('a changeset intended to be included in the destination'),
4378 _('a changeset intended to be included in the destination'),
4379 _('REV')),
4379 _('REV')),
4380 ('b', 'branch', [],
4380 ('b', 'branch', [],
4381 _('a specific branch you would like to push'), _('BRANCH')),
4381 _('a specific branch you would like to push'), _('BRANCH')),
4382 ('', 'new-branch', False, _('allow pushing a new branch')),
4382 ('', 'new-branch', False, _('allow pushing a new branch')),
4383 ] + remoteopts,
4383 ] + remoteopts,
4384 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4384 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4385 "recover": (recover, []),
4385 "recover": (recover, []),
4386 "^remove|rm":
4386 "^remove|rm":
4387 (remove,
4387 (remove,
4388 [('A', 'after', None, _('record delete for missing files')),
4388 [('A', 'after', None, _('record delete for missing files')),
4389 ('f', 'force', None,
4389 ('f', 'force', None,
4390 _('remove (and delete) file even if added or modified')),
4390 _('remove (and delete) file even if added or modified')),
4391 ] + walkopts,
4391 ] + walkopts,
4392 _('[OPTION]... FILE...')),
4392 _('[OPTION]... FILE...')),
4393 "rename|move|mv":
4393 "rename|move|mv":
4394 (rename,
4394 (rename,
4395 [('A', 'after', None, _('record a rename that has already occurred')),
4395 [('A', 'after', None, _('record a rename that has already occurred')),
4396 ('f', 'force', None,
4396 ('f', 'force', None,
4397 _('forcibly copy over an existing managed file')),
4397 _('forcibly copy over an existing managed file')),
4398 ] + walkopts + dryrunopts,
4398 ] + walkopts + dryrunopts,
4399 _('[OPTION]... SOURCE... DEST')),
4399 _('[OPTION]... SOURCE... DEST')),
4400 "resolve":
4400 "resolve":
4401 (resolve,
4401 (resolve,
4402 [('a', 'all', None, _('select all unresolved files')),
4402 [('a', 'all', None, _('select all unresolved files')),
4403 ('l', 'list', None, _('list state of files needing merge')),
4403 ('l', 'list', None, _('list state of files needing merge')),
4404 ('m', 'mark', None, _('mark files as resolved')),
4404 ('m', 'mark', None, _('mark files as resolved')),
4405 ('u', 'unmark', None, _('mark files as unresolved')),
4405 ('u', 'unmark', None, _('mark files as unresolved')),
4406 ('t', 'tool', '', _('specify merge tool')),
4406 ('t', 'tool', '', _('specify merge tool')),
4407 ('n', 'no-status', None, _('hide status prefix'))]
4407 ('n', 'no-status', None, _('hide status prefix'))]
4408 + walkopts,
4408 + walkopts,
4409 _('[OPTION]... [FILE]...')),
4409 _('[OPTION]... [FILE]...')),
4410 "revert":
4410 "revert":
4411 (revert,
4411 (revert,
4412 [('a', 'all', None, _('revert all changes when no arguments given')),
4412 [('a', 'all', None, _('revert all changes when no arguments given')),
4413 ('d', 'date', '',
4413 ('d', 'date', '',
4414 _('tipmost revision matching date'), _('DATE')),
4414 _('tipmost revision matching date'), _('DATE')),
4415 ('r', 'rev', '',
4415 ('r', 'rev', '',
4416 _('revert to the specified revision'), _('REV')),
4416 _('revert to the specified revision'), _('REV')),
4417 ('', 'no-backup', None, _('do not save backup copies of files')),
4417 ('', 'no-backup', None, _('do not save backup copies of files')),
4418 ] + walkopts + dryrunopts,
4418 ] + walkopts + dryrunopts,
4419 _('[OPTION]... [-r REV] [NAME]...')),
4419 _('[OPTION]... [-r REV] [NAME]...')),
4420 "rollback": (rollback, dryrunopts),
4420 "rollback": (rollback, dryrunopts),
4421 "root": (root, []),
4421 "root": (root, []),
4422 "^serve":
4422 "^serve":
4423 (serve,
4423 (serve,
4424 [('A', 'accesslog', '',
4424 [('A', 'accesslog', '',
4425 _('name of access log file to write to'), _('FILE')),
4425 _('name of access log file to write to'), _('FILE')),
4426 ('d', 'daemon', None, _('run server in background')),
4426 ('d', 'daemon', None, _('run server in background')),
4427 ('', 'daemon-pipefds', '',
4427 ('', 'daemon-pipefds', '',
4428 _('used internally by daemon mode'), _('NUM')),
4428 _('used internally by daemon mode'), _('NUM')),
4429 ('E', 'errorlog', '',
4429 ('E', 'errorlog', '',
4430 _('name of error log file to write to'), _('FILE')),
4430 _('name of error log file to write to'), _('FILE')),
4431 # use string type, then we can check if something was passed
4431 # use string type, then we can check if something was passed
4432 ('p', 'port', '',
4432 ('p', 'port', '',
4433 _('port to listen on (default: 8000)'), _('PORT')),
4433 _('port to listen on (default: 8000)'), _('PORT')),
4434 ('a', 'address', '',
4434 ('a', 'address', '',
4435 _('address to listen on (default: all interfaces)'), _('ADDR')),
4435 _('address to listen on (default: all interfaces)'), _('ADDR')),
4436 ('', 'prefix', '',
4436 ('', 'prefix', '',
4437 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4437 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4438 ('n', 'name', '',
4438 ('n', 'name', '',
4439 _('name to show in web pages (default: working directory)'),
4439 _('name to show in web pages (default: working directory)'),
4440 _('NAME')),
4440 _('NAME')),
4441 ('', 'web-conf', '',
4441 ('', 'web-conf', '',
4442 _('name of the hgweb config file (see "hg help hgweb")'),
4442 _('name of the hgweb config file (see "hg help hgweb")'),
4443 _('FILE')),
4443 _('FILE')),
4444 ('', 'webdir-conf', '',
4444 ('', 'webdir-conf', '',
4445 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4445 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4446 ('', 'pid-file', '',
4446 ('', 'pid-file', '',
4447 _('name of file to write process ID to'), _('FILE')),
4447 _('name of file to write process ID to'), _('FILE')),
4448 ('', 'stdio', None, _('for remote clients')),
4448 ('', 'stdio', None, _('for remote clients')),
4449 ('t', 'templates', '',
4449 ('t', 'templates', '',
4450 _('web templates to use'), _('TEMPLATE')),
4450 _('web templates to use'), _('TEMPLATE')),
4451 ('', 'style', '',
4451 ('', 'style', '',
4452 _('template style to use'), _('STYLE')),
4452 _('template style to use'), _('STYLE')),
4453 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4453 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4454 ('', 'certificate', '',
4454 ('', 'certificate', '',
4455 _('SSL certificate file'), _('FILE'))],
4455 _('SSL certificate file'), _('FILE'))],
4456 _('[OPTION]...')),
4456 _('[OPTION]...')),
4457 "showconfig|debugconfig":
4457 "showconfig|debugconfig":
4458 (showconfig,
4458 (showconfig,
4459 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4459 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4460 _('[-u] [NAME]...')),
4460 _('[-u] [NAME]...')),
4461 "^summary|sum":
4461 "^summary|sum":
4462 (summary,
4462 (summary,
4463 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4463 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4464 "^status|st":
4464 "^status|st":
4465 (status,
4465 (status,
4466 [('A', 'all', None, _('show status of all files')),
4466 [('A', 'all', None, _('show status of all files')),
4467 ('m', 'modified', None, _('show only modified files')),
4467 ('m', 'modified', None, _('show only modified files')),
4468 ('a', 'added', None, _('show only added files')),
4468 ('a', 'added', None, _('show only added files')),
4469 ('r', 'removed', None, _('show only removed files')),
4469 ('r', 'removed', None, _('show only removed files')),
4470 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4470 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4471 ('c', 'clean', None, _('show only files without changes')),
4471 ('c', 'clean', None, _('show only files without changes')),
4472 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4472 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4473 ('i', 'ignored', None, _('show only ignored files')),
4473 ('i', 'ignored', None, _('show only ignored files')),
4474 ('n', 'no-status', None, _('hide status prefix')),
4474 ('n', 'no-status', None, _('hide status prefix')),
4475 ('C', 'copies', None, _('show source of copied files')),
4475 ('C', 'copies', None, _('show source of copied files')),
4476 ('0', 'print0', None,
4476 ('0', 'print0', None,
4477 _('end filenames with NUL, for use with xargs')),
4477 _('end filenames with NUL, for use with xargs')),
4478 ('', 'rev', [],
4478 ('', 'rev', [],
4479 _('show difference from revision'), _('REV')),
4479 _('show difference from revision'), _('REV')),
4480 ('', 'change', '',
4480 ('', 'change', '',
4481 _('list the changed files of a revision'), _('REV')),
4481 _('list the changed files of a revision'), _('REV')),
4482 ] + walkopts + subrepoopts,
4482 ] + walkopts + subrepoopts,
4483 _('[OPTION]... [FILE]...')),
4483 _('[OPTION]... [FILE]...')),
4484 "tag":
4484 "tag":
4485 (tag,
4485 (tag,
4486 [('f', 'force', None, _('replace existing tag')),
4486 [('f', 'force', None, _('replace existing tag')),
4487 ('l', 'local', None, _('make the tag local')),
4487 ('l', 'local', None, _('make the tag local')),
4488 ('r', 'rev', '',
4488 ('r', 'rev', '',
4489 _('revision to tag'), _('REV')),
4489 _('revision to tag'), _('REV')),
4490 ('', 'remove', None, _('remove a tag')),
4490 ('', 'remove', None, _('remove a tag')),
4491 # -l/--local is already there, commitopts cannot be used
4491 # -l/--local is already there, commitopts cannot be used
4492 ('e', 'edit', None, _('edit commit message')),
4492 ('e', 'edit', None, _('edit commit message')),
4493 ('m', 'message', '',
4493 ('m', 'message', '',
4494 _('use <text> as commit message'), _('TEXT')),
4494 _('use <text> as commit message'), _('TEXT')),
4495 ] + commitopts2,
4495 ] + commitopts2,
4496 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4496 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4497 "tags": (tags, [], ''),
4497 "tags": (tags, [], ''),
4498 "tip":
4498 "tip":
4499 (tip,
4499 (tip,
4500 [('p', 'patch', None, _('show patch')),
4500 [('p', 'patch', None, _('show patch')),
4501 ('g', 'git', None, _('use git extended diff format')),
4501 ('g', 'git', None, _('use git extended diff format')),
4502 ] + templateopts,
4502 ] + templateopts,
4503 _('[-p] [-g]')),
4503 _('[-p] [-g]')),
4504 "unbundle":
4504 "unbundle":
4505 (unbundle,
4505 (unbundle,
4506 [('u', 'update', None,
4506 [('u', 'update', None,
4507 _('update to new branch head if changesets were unbundled'))],
4507 _('update to new branch head if changesets were unbundled'))],
4508 _('[-u] FILE...')),
4508 _('[-u] FILE...')),
4509 "^update|up|checkout|co":
4509 "^update|up|checkout|co":
4510 (update,
4510 (update,
4511 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4511 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4512 ('c', 'check', None,
4512 ('c', 'check', None,
4513 _('update across branches if no uncommitted changes')),
4513 _('update across branches if no uncommitted changes')),
4514 ('d', 'date', '',
4514 ('d', 'date', '',
4515 _('tipmost revision matching date'), _('DATE')),
4515 _('tipmost revision matching date'), _('DATE')),
4516 ('r', 'rev', '',
4516 ('r', 'rev', '',
4517 _('revision'), _('REV'))],
4517 _('revision'), _('REV'))],
4518 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4518 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4519 "verify": (verify, []),
4519 "verify": (verify, []),
4520 "version": (version_, []),
4520 "version": (version_, []),
4521 }
4521 }
4522
4522
4523 norepo = ("clone init version help debugcommands debugcomplete"
4523 norepo = ("clone init version help debugcommands debugcomplete"
4524 " debugdate debuginstall debugfsinfo debugpushkey")
4524 " debugdate debuginstall debugfsinfo debugpushkey")
4525 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4525 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4526 " debugdata debugindex debugindexdot")
4526 " debugdata debugindex debugindexdot")
@@ -1,185 +1,180 b''
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Utility functions that use win32 API.
8 """Utility functions that use win32 API.
9
9
10 Mark Hammond's win32all package allows better functionality on
10 Mark Hammond's win32all package allows better functionality on
11 Windows. This module overrides definitions in util.py. If not
11 Windows. This module overrides definitions in util.py. If not
12 available, import of this module will fail, and generic code will be
12 available, import of this module will fail, and generic code will be
13 used.
13 used.
14 """
14 """
15
15
16 import win32api
16 import win32api
17
17
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
19 import winerror, win32gui, win32console
19 import winerror, win32gui, win32console
20 import osutil, encoding
20 import osutil, encoding
21 from win32com.shell import shell, shellcon
21 from win32com.shell import shell, shellcon
22
22
23 def os_link(src, dst):
23 def os_link(src, dst):
24 try:
24 try:
25 win32file.CreateHardLink(dst, src)
25 win32file.CreateHardLink(dst, src)
26 except pywintypes.error:
26 except pywintypes.error:
27 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
27 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
28 except NotImplementedError: # Another fake error win Win98
28 except NotImplementedError: # Another fake error win Win98
29 raise OSError(errno.EINVAL, 'Hardlinking not supported')
29 raise OSError(errno.EINVAL, 'Hardlinking not supported')
30
30
31 def _getfileinfo(pathname):
31 def _getfileinfo(pathname):
32 """Return number of hardlinks for the given file."""
32 """Return number of hardlinks for the given file."""
33 try:
33 try:
34 fh = win32file.CreateFile(pathname,
34 fh = win32file.CreateFile(pathname,
35 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
35 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
36 None, win32file.OPEN_EXISTING, 0, None)
36 None, win32file.OPEN_EXISTING, 0, None)
37 except pywintypes.error:
37 except pywintypes.error:
38 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
38 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
39 try:
39 try:
40 return win32file.GetFileInformationByHandle(fh)
40 return win32file.GetFileInformationByHandle(fh)
41 finally:
41 finally:
42 fh.Close()
42 fh.Close()
43
43
44 def nlinks(pathname):
44 def nlinks(pathname):
45 """Return number of hardlinks for the given file."""
45 """Return number of hardlinks for the given file."""
46 return _getfileinfo(pathname)[7]
46 return _getfileinfo(pathname)[7]
47
47
48 def samefile(fpath1, fpath2):
48 def samefile(fpath1, fpath2):
49 """Returns whether fpath1 and fpath2 refer to the same file. This is only
49 """Returns whether fpath1 and fpath2 refer to the same file. This is only
50 guaranteed to work for files, not directories."""
50 guaranteed to work for files, not directories."""
51 res1 = _getfileinfo(fpath1)
51 res1 = _getfileinfo(fpath1)
52 res2 = _getfileinfo(fpath2)
52 res2 = _getfileinfo(fpath2)
53 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
53 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
54 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
54 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
55
55
56 def samedevice(fpath1, fpath2):
56 def samedevice(fpath1, fpath2):
57 """Returns whether fpath1 and fpath2 are on the same device. This is only
57 """Returns whether fpath1 and fpath2 are on the same device. This is only
58 guaranteed to work for files, not directories."""
58 guaranteed to work for files, not directories."""
59 res1 = _getfileinfo(fpath1)
59 res1 = _getfileinfo(fpath1)
60 res2 = _getfileinfo(fpath2)
60 res2 = _getfileinfo(fpath2)
61 return res1[4] == res2[4]
61 return res1[4] == res2[4]
62
62
63 def testpid(pid):
63 def testpid(pid):
64 '''return True if pid is still running or unable to
64 '''return True if pid is still running or unable to
65 determine, False otherwise'''
65 determine, False otherwise'''
66 try:
66 try:
67 handle = win32api.OpenProcess(
67 handle = win32api.OpenProcess(
68 win32con.PROCESS_QUERY_INFORMATION, False, pid)
68 win32con.PROCESS_QUERY_INFORMATION, False, pid)
69 if handle:
69 if handle:
70 status = win32process.GetExitCodeProcess(handle)
70 status = win32process.GetExitCodeProcess(handle)
71 return status == win32con.STILL_ACTIVE
71 return status == win32con.STILL_ACTIVE
72 except pywintypes.error, details:
72 except pywintypes.error, details:
73 return details[0] != winerror.ERROR_INVALID_PARAMETER
73 return details[0] != winerror.ERROR_INVALID_PARAMETER
74 return True
74 return True
75
75
76 def lookup_reg(key, valname=None, scope=None):
76 def lookup_reg(key, valname=None, scope=None):
77 ''' Look up a key/value name in the Windows registry.
77 ''' Look up a key/value name in the Windows registry.
78
78
79 valname: value name. If unspecified, the default value for the key
79 valname: value name. If unspecified, the default value for the key
80 is used.
80 is used.
81 scope: optionally specify scope for registry lookup, this can be
81 scope: optionally specify scope for registry lookup, this can be
82 a sequence of scopes to look up in order. Default (CURRENT_USER,
82 a sequence of scopes to look up in order. Default (CURRENT_USER,
83 LOCAL_MACHINE).
83 LOCAL_MACHINE).
84 '''
84 '''
85 try:
85 try:
86 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
86 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
87 QueryValueEx, OpenKey
87 QueryValueEx, OpenKey
88 except ImportError:
88 except ImportError:
89 return None
89 return None
90
90
91 if scope is None:
91 if scope is None:
92 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
92 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
93 elif not isinstance(scope, (list, tuple)):
93 elif not isinstance(scope, (list, tuple)):
94 scope = (scope,)
94 scope = (scope,)
95 for s in scope:
95 for s in scope:
96 try:
96 try:
97 val = QueryValueEx(OpenKey(s, key), valname)[0]
97 val = QueryValueEx(OpenKey(s, key), valname)[0]
98 # never let a Unicode string escape into the wild
98 # never let a Unicode string escape into the wild
99 return encoding.tolocal(val.encode('UTF-8'))
99 return encoding.tolocal(val.encode('UTF-8'))
100 except EnvironmentError:
100 except EnvironmentError:
101 pass
101 pass
102
102
103 def system_rcpath_win32():
103 def system_rcpath_win32():
104 '''return default os-specific hgrc search path'''
104 '''return default os-specific hgrc search path'''
105 proc = win32api.GetCurrentProcess()
105 filename = win32api.GetModuleFileName(0)
106 try:
107 # This will fail on windows < NT
108 filename = win32process.GetModuleFileNameEx(proc, 0)
109 except:
110 filename = win32api.GetModuleFileName(0)
111 # Use mercurial.ini found in directory with hg.exe
106 # Use mercurial.ini found in directory with hg.exe
112 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
107 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
113 if os.path.isfile(progrc):
108 if os.path.isfile(progrc):
114 return [progrc]
109 return [progrc]
115 # Use hgrc.d found in directory with hg.exe
110 # Use hgrc.d found in directory with hg.exe
116 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
111 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
117 if os.path.isdir(progrcd):
112 if os.path.isdir(progrcd):
118 rcpath = []
113 rcpath = []
119 for f, kind in osutil.listdir(progrcd):
114 for f, kind in osutil.listdir(progrcd):
120 if f.endswith('.rc'):
115 if f.endswith('.rc'):
121 rcpath.append(os.path.join(progrcd, f))
116 rcpath.append(os.path.join(progrcd, f))
122 return rcpath
117 return rcpath
123 # else look for a system rcpath in the registry
118 # else look for a system rcpath in the registry
124 try:
119 try:
125 value = win32api.RegQueryValue(
120 value = win32api.RegQueryValue(
126 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
121 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
127 rcpath = []
122 rcpath = []
128 for p in value.split(os.pathsep):
123 for p in value.split(os.pathsep):
129 if p.lower().endswith('mercurial.ini'):
124 if p.lower().endswith('mercurial.ini'):
130 rcpath.append(p)
125 rcpath.append(p)
131 elif os.path.isdir(p):
126 elif os.path.isdir(p):
132 for f, kind in osutil.listdir(p):
127 for f, kind in osutil.listdir(p):
133 if f.endswith('.rc'):
128 if f.endswith('.rc'):
134 rcpath.append(os.path.join(p, f))
129 rcpath.append(os.path.join(p, f))
135 return rcpath
130 return rcpath
136 except pywintypes.error:
131 except pywintypes.error:
137 return []
132 return []
138
133
139 def user_rcpath_win32():
134 def user_rcpath_win32():
140 '''return os-specific hgrc search path to the user dir'''
135 '''return os-specific hgrc search path to the user dir'''
141 userdir = os.path.expanduser('~')
136 userdir = os.path.expanduser('~')
142 if sys.getwindowsversion()[3] != 2 and userdir == '~':
137 if sys.getwindowsversion()[3] != 2 and userdir == '~':
143 # We are on win < nt: fetch the APPDATA directory location and use
138 # We are on win < nt: fetch the APPDATA directory location and use
144 # the parent directory as the user home dir.
139 # the parent directory as the user home dir.
145 appdir = shell.SHGetPathFromIDList(
140 appdir = shell.SHGetPathFromIDList(
146 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
141 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
147 userdir = os.path.dirname(appdir)
142 userdir = os.path.dirname(appdir)
148 return [os.path.join(userdir, 'mercurial.ini'),
143 return [os.path.join(userdir, 'mercurial.ini'),
149 os.path.join(userdir, '.hgrc')]
144 os.path.join(userdir, '.hgrc')]
150
145
151 def getuser():
146 def getuser():
152 '''return name of current user'''
147 '''return name of current user'''
153 return win32api.GetUserName()
148 return win32api.GetUserName()
154
149
155 def set_signal_handler_win32():
150 def set_signal_handler_win32():
156 """Register a termination handler for console events including
151 """Register a termination handler for console events including
157 CTRL+C. python signal handlers do not work well with socket
152 CTRL+C. python signal handlers do not work well with socket
158 operations.
153 operations.
159 """
154 """
160 def handler(event):
155 def handler(event):
161 win32process.ExitProcess(1)
156 win32process.ExitProcess(1)
162 win32api.SetConsoleCtrlHandler(handler)
157 win32api.SetConsoleCtrlHandler(handler)
163
158
164 def hidewindow():
159 def hidewindow():
165 def callback(*args, **kwargs):
160 def callback(*args, **kwargs):
166 hwnd, pid = args
161 hwnd, pid = args
167 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
162 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
168 if pid == wpid:
163 if pid == wpid:
169 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
164 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
170
165
171 pid = win32process.GetCurrentProcessId()
166 pid = win32process.GetCurrentProcessId()
172 win32gui.EnumWindows(callback, pid)
167 win32gui.EnumWindows(callback, pid)
173
168
174 def termwidth():
169 def termwidth():
175 try:
170 try:
176 # Query stderr to avoid problems with redirections
171 # Query stderr to avoid problems with redirections
177 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
172 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
178 try:
173 try:
179 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
174 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
180 width = window.Right - window.Left
175 width = window.Right - window.Left
181 return width
176 return width
182 finally:
177 finally:
183 screenbuf.Detach()
178 screenbuf.Detach()
184 except pywintypes.error:
179 except pywintypes.error:
185 return 79
180 return 79
General Comments 0
You need to be logged in to leave comments. Login now