##// END OF EJS Templates
Document log date ranges and mention 'hg help dates' for all commands (issue998)
Thomas Arendsen Hein -
r6163:1f733c2f default
parent child Browse files
Show More
@@ -1,99 +1,102
1 1 # fetch.py - pull and merge remote changes
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from mercurial.i18n import _
9 9 from mercurial.node import *
10 10 from mercurial import commands, cmdutil, hg, node, util
11 11
12 12 def fetch(ui, repo, source='default', **opts):
13 13 '''Pull changes from a remote repository, merge new changes if needed.
14 14
15 15 This finds all changes from the repository at the specified path
16 16 or URL and adds them to the local repository.
17 17
18 18 If the pulled changes add a new head, the head is automatically
19 19 merged, and the result of the merge is committed. Otherwise, the
20 working directory is updated.'''
20 working directory is updated.
21
22 See 'hg help dates' for a list of formats valid for -d/--date.
23 '''
21 24
22 25 def postincoming(other, modheads):
23 26 if modheads == 0:
24 27 return 0
25 28 if modheads == 1:
26 29 return hg.clean(repo, repo.changelog.tip())
27 30 newheads = repo.heads(parent)
28 31 newchildren = [n for n in repo.heads(parent) if n != parent]
29 32 newparent = parent
30 33 if newchildren:
31 34 newparent = newchildren[0]
32 35 hg.clean(repo, newparent)
33 36 newheads = [n for n in repo.heads() if n != newparent]
34 37 err = False
35 38 if newheads:
36 39 ui.status(_('merging with new head %d:%s\n') %
37 40 (repo.changelog.rev(newheads[0]), short(newheads[0])))
38 41 err = hg.merge(repo, newheads[0], remind=False)
39 42 if not err and len(newheads) > 1:
40 43 ui.status(_('not merging with %d other new heads '
41 44 '(use "hg heads" and "hg merge" to merge them)') %
42 45 (len(newheads) - 1))
43 46 if not err:
44 47 mod, add, rem = repo.status()[:3]
45 48 message = (cmdutil.logmessage(opts) or
46 49 (_('Automated merge with %s') %
47 50 util.removeauth(other.url())))
48 51 n = repo.commit(mod + add + rem, message,
49 52 opts['user'], opts['date'],
50 53 force_editor=opts.get('force_editor'))
51 54 ui.status(_('new changeset %d:%s merges remote changes '
52 55 'with local\n') % (repo.changelog.rev(n),
53 56 short(n)))
54 57 def pull():
55 58 cmdutil.setremoteconfig(ui, opts)
56 59
57 60 other = hg.repository(ui, ui.expandpath(source))
58 61 ui.status(_('pulling from %s\n') %
59 62 util.hidepassword(ui.expandpath(source)))
60 63 revs = None
61 64 if opts['rev'] and not other.local():
62 65 raise util.Abort(_("fetch -r doesn't work for remote repositories yet"))
63 66 elif opts['rev']:
64 67 revs = [other.lookup(rev) for rev in opts['rev']]
65 68 modheads = repo.pull(other, heads=revs)
66 69 return postincoming(other, modheads)
67 70
68 71 date = opts.get('date')
69 72 if date:
70 73 opts['date'] = util.parsedate(date)
71 74
72 75 parent, p2 = repo.dirstate.parents()
73 76 if parent != repo.changelog.tip():
74 77 raise util.Abort(_('working dir not at tip '
75 78 '(use "hg update" to check out tip)'))
76 79 if p2 != nullid:
77 80 raise util.Abort(_('outstanding uncommitted merge'))
78 81 wlock = lock = None
79 82 try:
80 83 wlock = repo.wlock()
81 84 lock = repo.lock()
82 85 mod, add, rem = repo.status()[:3]
83 86 if mod or add or rem:
84 87 raise util.Abort(_('outstanding uncommitted changes'))
85 88 if len(repo.heads()) > 1:
86 89 raise util.Abort(_('multiple heads in this repository '
87 90 '(use "hg heads" and "hg merge" to merge)'))
88 91 return pull()
89 92 finally:
90 93 del lock, wlock
91 94
92 95 cmdtable = {
93 96 'fetch':
94 97 (fetch,
95 98 [('r', 'rev', [], _('a specific revision you would like to pull')),
96 99 ('f', 'force-editor', None, _('edit commit message')),
97 100 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
98 101 _('hg fetch [SOURCE]')),
99 102 }
@@ -1,284 +1,286
1 1 # GnuPG signing extension for Mercurial
2 2 #
3 3 # Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 import os, tempfile, binascii
9 9 from mercurial import util, commands
10 10 from mercurial import node as hgnode
11 11 from mercurial.i18n import _
12 12
13 13 class gpg:
14 14 def __init__(self, path, key=None):
15 15 self.path = path
16 16 self.key = (key and " --local-user \"%s\"" % key) or ""
17 17
18 18 def sign(self, data):
19 19 gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key)
20 20 return util.filter(data, gpgcmd)
21 21
22 22 def verify(self, data, sig):
23 23 """ returns of the good and bad signatures"""
24 24 sigfile = datafile = None
25 25 try:
26 26 # create temporary files
27 27 fd, sigfile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".sig")
28 28 fp = os.fdopen(fd, 'wb')
29 29 fp.write(sig)
30 30 fp.close()
31 31 fd, datafile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".txt")
32 32 fp = os.fdopen(fd, 'wb')
33 33 fp.write(data)
34 34 fp.close()
35 35 gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify "
36 36 "\"%s\" \"%s\"" % (self.path, sigfile, datafile))
37 37 ret = util.filter("", gpgcmd)
38 38 finally:
39 39 for f in (sigfile, datafile):
40 40 try:
41 41 if f: os.unlink(f)
42 42 except: pass
43 43 keys = []
44 44 key, fingerprint = None, None
45 45 err = ""
46 46 for l in ret.splitlines():
47 47 # see DETAILS in the gnupg documentation
48 48 # filter the logger output
49 49 if not l.startswith("[GNUPG:]"):
50 50 continue
51 51 l = l[9:]
52 52 if l.startswith("ERRSIG"):
53 53 err = _("error while verifying signature")
54 54 break
55 55 elif l.startswith("VALIDSIG"):
56 56 # fingerprint of the primary key
57 57 fingerprint = l.split()[10]
58 58 elif (l.startswith("GOODSIG") or
59 59 l.startswith("EXPSIG") or
60 60 l.startswith("EXPKEYSIG") or
61 61 l.startswith("BADSIG")):
62 62 if key is not None:
63 63 keys.append(key + [fingerprint])
64 64 key = l.split(" ", 2)
65 65 fingerprint = None
66 66 if err:
67 67 return err, []
68 68 if key is not None:
69 69 keys.append(key + [fingerprint])
70 70 return err, keys
71 71
72 72 def newgpg(ui, **opts):
73 73 """create a new gpg instance"""
74 74 gpgpath = ui.config("gpg", "cmd", "gpg")
75 75 gpgkey = opts.get('key')
76 76 if not gpgkey:
77 77 gpgkey = ui.config("gpg", "key", None)
78 78 return gpg(gpgpath, gpgkey)
79 79
80 80 def sigwalk(repo):
81 81 """
82 82 walk over every sigs, yields a couple
83 83 ((node, version, sig), (filename, linenumber))
84 84 """
85 85 def parsefile(fileiter, context):
86 86 ln = 1
87 87 for l in fileiter:
88 88 if not l:
89 89 continue
90 90 yield (l.split(" ", 2), (context, ln))
91 91 ln +=1
92 92
93 93 fl = repo.file(".hgsigs")
94 94 h = fl.heads()
95 95 h.reverse()
96 96 # read the heads
97 97 for r in h:
98 98 fn = ".hgsigs|%s" % hgnode.short(r)
99 99 for item in parsefile(fl.read(r).splitlines(), fn):
100 100 yield item
101 101 try:
102 102 # read local signatures
103 103 fn = "localsigs"
104 104 for item in parsefile(repo.opener(fn), fn):
105 105 yield item
106 106 except IOError:
107 107 pass
108 108
109 109 def getkeys(ui, repo, mygpg, sigdata, context):
110 110 """get the keys who signed a data"""
111 111 fn, ln = context
112 112 node, version, sig = sigdata
113 113 prefix = "%s:%d" % (fn, ln)
114 114 node = hgnode.bin(node)
115 115
116 116 data = node2txt(repo, node, version)
117 117 sig = binascii.a2b_base64(sig)
118 118 err, keys = mygpg.verify(data, sig)
119 119 if err:
120 120 ui.warn("%s:%d %s\n" % (fn, ln , err))
121 121 return None
122 122
123 123 validkeys = []
124 124 # warn for expired key and/or sigs
125 125 for key in keys:
126 126 if key[0] == "BADSIG":
127 127 ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2]))
128 128 continue
129 129 if key[0] == "EXPSIG":
130 130 ui.write(_("%s Note: Signature has expired"
131 131 " (signed by: \"%s\")\n") % (prefix, key[2]))
132 132 elif key[0] == "EXPKEYSIG":
133 133 ui.write(_("%s Note: This key has expired"
134 134 " (signed by: \"%s\")\n") % (prefix, key[2]))
135 135 validkeys.append((key[1], key[2], key[3]))
136 136 return validkeys
137 137
138 138 def sigs(ui, repo):
139 139 """list signed changesets"""
140 140 mygpg = newgpg(ui)
141 141 revs = {}
142 142
143 143 for data, context in sigwalk(repo):
144 144 node, version, sig = data
145 145 fn, ln = context
146 146 try:
147 147 n = repo.lookup(node)
148 148 except KeyError:
149 149 ui.warn(_("%s:%d node does not exist\n") % (fn, ln))
150 150 continue
151 151 r = repo.changelog.rev(n)
152 152 keys = getkeys(ui, repo, mygpg, data, context)
153 153 if not keys:
154 154 continue
155 155 revs.setdefault(r, [])
156 156 revs[r].extend(keys)
157 157 nodes = list(revs)
158 158 nodes.reverse()
159 159 for rev in nodes:
160 160 for k in revs[rev]:
161 161 r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev)))
162 162 ui.write("%-30s %s\n" % (keystr(ui, k), r))
163 163
164 164 def check(ui, repo, rev):
165 165 """verify all the signatures there may be for a particular revision"""
166 166 mygpg = newgpg(ui)
167 167 rev = repo.lookup(rev)
168 168 hexrev = hgnode.hex(rev)
169 169 keys = []
170 170
171 171 for data, context in sigwalk(repo):
172 172 node, version, sig = data
173 173 if node == hexrev:
174 174 k = getkeys(ui, repo, mygpg, data, context)
175 175 if k:
176 176 keys.extend(k)
177 177
178 178 if not keys:
179 179 ui.write(_("No valid signature for %s\n") % hgnode.short(rev))
180 180 return
181 181
182 182 # print summary
183 183 ui.write("%s is signed by:\n" % hgnode.short(rev))
184 184 for key in keys:
185 185 ui.write(" %s\n" % keystr(ui, key))
186 186
187 187 def keystr(ui, key):
188 188 """associate a string to a key (username, comment)"""
189 189 keyid, user, fingerprint = key
190 190 comment = ui.config("gpg", fingerprint, None)
191 191 if comment:
192 192 return "%s (%s)" % (user, comment)
193 193 else:
194 194 return user
195 195
196 196 def sign(ui, repo, *revs, **opts):
197 197 """add a signature for the current or given revision
198 198
199 199 If no revision is given, the parent of the working directory is used,
200 200 or tip if no revision is checked out.
201
202 See 'hg help dates' for a list of formats valid for -d/--date.
201 203 """
202 204
203 205 mygpg = newgpg(ui, **opts)
204 206 sigver = "0"
205 207 sigmessage = ""
206 208
207 209 date = opts.get('date')
208 210 if date:
209 211 opts['date'] = util.parsedate(date)
210 212
211 213 if revs:
212 214 nodes = [repo.lookup(n) for n in revs]
213 215 else:
214 216 nodes = [node for node in repo.dirstate.parents()
215 217 if node != hgnode.nullid]
216 218 if len(nodes) > 1:
217 219 raise util.Abort(_('uncommitted merge - please provide a '
218 220 'specific revision'))
219 221 if not nodes:
220 222 nodes = [repo.changelog.tip()]
221 223
222 224 for n in nodes:
223 225 hexnode = hgnode.hex(n)
224 226 ui.write("Signing %d:%s\n" % (repo.changelog.rev(n),
225 227 hgnode.short(n)))
226 228 # build data
227 229 data = node2txt(repo, n, sigver)
228 230 sig = mygpg.sign(data)
229 231 if not sig:
230 232 raise util.Abort(_("Error while signing"))
231 233 sig = binascii.b2a_base64(sig)
232 234 sig = sig.replace("\n", "")
233 235 sigmessage += "%s %s %s\n" % (hexnode, sigver, sig)
234 236
235 237 # write it
236 238 if opts['local']:
237 239 repo.opener("localsigs", "ab").write(sigmessage)
238 240 return
239 241
240 242 for x in repo.status()[:5]:
241 243 if ".hgsigs" in x and not opts["force"]:
242 244 raise util.Abort(_("working copy of .hgsigs is changed "
243 245 "(please commit .hgsigs manually "
244 246 "or use --force)"))
245 247
246 248 repo.wfile(".hgsigs", "ab").write(sigmessage)
247 249
248 250 if '.hgsigs' not in repo.dirstate:
249 251 repo.add([".hgsigs"])
250 252
251 253 if opts["no_commit"]:
252 254 return
253 255
254 256 message = opts['message']
255 257 if not message:
256 258 message = "\n".join([_("Added signature for changeset %s")
257 259 % hgnode.short(n)
258 260 for n in nodes])
259 261 try:
260 262 repo.commit([".hgsigs"], message, opts['user'], opts['date'])
261 263 except ValueError, inst:
262 264 raise util.Abort(str(inst))
263 265
264 266 def node2txt(repo, node, ver):
265 267 """map a manifest into some text"""
266 268 if ver == "0":
267 269 return "%s\n" % hgnode.hex(node)
268 270 else:
269 271 raise util.Abort(_("unknown signature version"))
270 272
271 273 cmdtable = {
272 274 "sign":
273 275 (sign,
274 276 [('l', 'local', None, _('make the signature local')),
275 277 ('f', 'force', None, _('sign even if the sigfile is modified')),
276 278 ('', 'no-commit', None, _('do not commit the sigfile after signing')),
277 279 ('k', 'key', '', _('the key id to sign with')),
278 280 ('m', 'message', '', _('commit message')),
279 281 ] + commands.commitopts2,
280 282 _('hg sign [OPTION]... [REVISION]...')),
281 283 "sigcheck": (check, [], _('hg sigcheck REVISION')),
282 284 "sigs": (sigs, [], _('hg sigs')),
283 285 }
284 286
@@ -1,525 +1,527
1 1 # record.py
2 2 #
3 3 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of
6 6 # the GNU General Public License, incorporated herein by reference.
7 7
8 8 '''interactive change selection during commit or qrefresh'''
9 9
10 10 from mercurial.i18n import _
11 11 from mercurial import cmdutil, commands, cmdutil, extensions, hg, mdiff, patch, revlog
12 12 from mercurial import util
13 13 import copy, cStringIO, errno, operator, os, re, shutil, tempfile
14 14
15 15 lines_re = re.compile(r'@@ -(\d+),(\d+) \+(\d+),(\d+) @@\s*(.*)')
16 16
17 17 def scanpatch(fp):
18 18 """like patch.iterhunks, but yield different events
19 19
20 20 - ('file', [header_lines + fromfile + tofile])
21 21 - ('context', [context_lines])
22 22 - ('hunk', [hunk_lines])
23 23 - ('range', (-start,len, +start,len, diffp))
24 24 """
25 25 lr = patch.linereader(fp)
26 26
27 27 def scanwhile(first, p):
28 28 """scan lr while predicate holds"""
29 29 lines = [first]
30 30 while True:
31 31 line = lr.readline()
32 32 if not line:
33 33 break
34 34 if p(line):
35 35 lines.append(line)
36 36 else:
37 37 lr.push(line)
38 38 break
39 39 return lines
40 40
41 41 while True:
42 42 line = lr.readline()
43 43 if not line:
44 44 break
45 45 if line.startswith('diff --git a/'):
46 46 def notheader(line):
47 47 s = line.split(None, 1)
48 48 return not s or s[0] not in ('---', 'diff')
49 49 header = scanwhile(line, notheader)
50 50 fromfile = lr.readline()
51 51 if fromfile.startswith('---'):
52 52 tofile = lr.readline()
53 53 header += [fromfile, tofile]
54 54 else:
55 55 lr.push(fromfile)
56 56 yield 'file', header
57 57 elif line[0] == ' ':
58 58 yield 'context', scanwhile(line, lambda l: l[0] in ' \\')
59 59 elif line[0] in '-+':
60 60 yield 'hunk', scanwhile(line, lambda l: l[0] in '-+\\')
61 61 else:
62 62 m = lines_re.match(line)
63 63 if m:
64 64 yield 'range', m.groups()
65 65 else:
66 66 raise patch.PatchError('unknown patch content: %r' % line)
67 67
68 68 class header(object):
69 69 """patch header
70 70
71 71 XXX shoudn't we move this to mercurial/patch.py ?
72 72 """
73 73 diff_re = re.compile('diff --git a/(.*) b/(.*)$')
74 74 allhunks_re = re.compile('(?:index|new file|deleted file) ')
75 75 pretty_re = re.compile('(?:new file|deleted file) ')
76 76 special_re = re.compile('(?:index|new|deleted|copy|rename) ')
77 77
78 78 def __init__(self, header):
79 79 self.header = header
80 80 self.hunks = []
81 81
82 82 def binary(self):
83 83 for h in self.header:
84 84 if h.startswith('index '):
85 85 return True
86 86
87 87 def pretty(self, fp):
88 88 for h in self.header:
89 89 if h.startswith('index '):
90 90 fp.write(_('this modifies a binary file (all or nothing)\n'))
91 91 break
92 92 if self.pretty_re.match(h):
93 93 fp.write(h)
94 94 if self.binary():
95 95 fp.write(_('this is a binary file\n'))
96 96 break
97 97 if h.startswith('---'):
98 98 fp.write(_('%d hunks, %d lines changed\n') %
99 99 (len(self.hunks),
100 100 sum([h.added + h.removed for h in self.hunks])))
101 101 break
102 102 fp.write(h)
103 103
104 104 def write(self, fp):
105 105 fp.write(''.join(self.header))
106 106
107 107 def allhunks(self):
108 108 for h in self.header:
109 109 if self.allhunks_re.match(h):
110 110 return True
111 111
112 112 def files(self):
113 113 fromfile, tofile = self.diff_re.match(self.header[0]).groups()
114 114 if fromfile == tofile:
115 115 return [fromfile]
116 116 return [fromfile, tofile]
117 117
118 118 def filename(self):
119 119 return self.files()[-1]
120 120
121 121 def __repr__(self):
122 122 return '<header %s>' % (' '.join(map(repr, self.files())))
123 123
124 124 def special(self):
125 125 for h in self.header:
126 126 if self.special_re.match(h):
127 127 return True
128 128
129 129 def countchanges(hunk):
130 130 """hunk -> (n+,n-)"""
131 131 add = len([h for h in hunk if h[0] == '+'])
132 132 rem = len([h for h in hunk if h[0] == '-'])
133 133 return add, rem
134 134
135 135 class hunk(object):
136 136 """patch hunk
137 137
138 138 XXX shouldn't we merge this with patch.hunk ?
139 139 """
140 140 maxcontext = 3
141 141
142 142 def __init__(self, header, fromline, toline, proc, before, hunk, after):
143 143 def trimcontext(number, lines):
144 144 delta = len(lines) - self.maxcontext
145 145 if False and delta > 0:
146 146 return number + delta, lines[:self.maxcontext]
147 147 return number, lines
148 148
149 149 self.header = header
150 150 self.fromline, self.before = trimcontext(fromline, before)
151 151 self.toline, self.after = trimcontext(toline, after)
152 152 self.proc = proc
153 153 self.hunk = hunk
154 154 self.added, self.removed = countchanges(self.hunk)
155 155
156 156 def write(self, fp):
157 157 delta = len(self.before) + len(self.after)
158 158 fromlen = delta + self.removed
159 159 tolen = delta + self.added
160 160 fp.write('@@ -%d,%d +%d,%d @@%s\n' %
161 161 (self.fromline, fromlen, self.toline, tolen,
162 162 self.proc and (' ' + self.proc)))
163 163 fp.write(''.join(self.before + self.hunk + self.after))
164 164
165 165 pretty = write
166 166
167 167 def filename(self):
168 168 return self.header.filename()
169 169
170 170 def __repr__(self):
171 171 return '<hunk %r@%d>' % (self.filename(), self.fromline)
172 172
173 173 def parsepatch(fp):
174 174 """patch -> [] of hunks """
175 175 class parser(object):
176 176 """patch parsing state machine"""
177 177 def __init__(self):
178 178 self.fromline = 0
179 179 self.toline = 0
180 180 self.proc = ''
181 181 self.header = None
182 182 self.context = []
183 183 self.before = []
184 184 self.hunk = []
185 185 self.stream = []
186 186
187 187 def addrange(self, (fromstart, fromend, tostart, toend, proc)):
188 188 self.fromline = int(fromstart)
189 189 self.toline = int(tostart)
190 190 self.proc = proc
191 191
192 192 def addcontext(self, context):
193 193 if self.hunk:
194 194 h = hunk(self.header, self.fromline, self.toline, self.proc,
195 195 self.before, self.hunk, context)
196 196 self.header.hunks.append(h)
197 197 self.stream.append(h)
198 198 self.fromline += len(self.before) + h.removed
199 199 self.toline += len(self.before) + h.added
200 200 self.before = []
201 201 self.hunk = []
202 202 self.proc = ''
203 203 self.context = context
204 204
205 205 def addhunk(self, hunk):
206 206 if self.context:
207 207 self.before = self.context
208 208 self.context = []
209 209 self.hunk = data
210 210
211 211 def newfile(self, hdr):
212 212 self.addcontext([])
213 213 h = header(hdr)
214 214 self.stream.append(h)
215 215 self.header = h
216 216
217 217 def finished(self):
218 218 self.addcontext([])
219 219 return self.stream
220 220
221 221 transitions = {
222 222 'file': {'context': addcontext,
223 223 'file': newfile,
224 224 'hunk': addhunk,
225 225 'range': addrange},
226 226 'context': {'file': newfile,
227 227 'hunk': addhunk,
228 228 'range': addrange},
229 229 'hunk': {'context': addcontext,
230 230 'file': newfile,
231 231 'range': addrange},
232 232 'range': {'context': addcontext,
233 233 'hunk': addhunk},
234 234 }
235 235
236 236 p = parser()
237 237
238 238 state = 'context'
239 239 for newstate, data in scanpatch(fp):
240 240 try:
241 241 p.transitions[state][newstate](p, data)
242 242 except KeyError:
243 243 raise patch.PatchError('unhandled transition: %s -> %s' %
244 244 (state, newstate))
245 245 state = newstate
246 246 return p.finished()
247 247
248 248 def filterpatch(ui, chunks):
249 249 """Interactively filter patch chunks into applied-only chunks"""
250 250 chunks = list(chunks)
251 251 chunks.reverse()
252 252 seen = {}
253 253 def consumefile():
254 254 """fetch next portion from chunks until a 'header' is seen
255 255 NB: header == new-file mark
256 256 """
257 257 consumed = []
258 258 while chunks:
259 259 if isinstance(chunks[-1], header):
260 260 break
261 261 else:
262 262 consumed.append(chunks.pop())
263 263 return consumed
264 264
265 265 resp_all = [None] # this two are changed from inside prompt,
266 266 resp_file = [None] # so can't be usual variables
267 267 applied = {} # 'filename' -> [] of chunks
268 268 def prompt(query):
269 269 """prompt query, and process base inputs
270 270
271 271 - y/n for the rest of file
272 272 - y/n for the rest
273 273 - ? (help)
274 274 - q (quit)
275 275
276 276 else, input is returned to the caller.
277 277 """
278 278 if resp_all[0] is not None:
279 279 return resp_all[0]
280 280 if resp_file[0] is not None:
281 281 return resp_file[0]
282 282 while True:
283 283 r = (ui.prompt(query + _(' [Ynsfdaq?] '), '(?i)[Ynsfdaq?]?$')
284 284 or 'y').lower()
285 285 if r == '?':
286 286 c = record.__doc__.find('y - record this change')
287 287 for l in record.__doc__[c:].splitlines():
288 288 if l: ui.write(_(l.strip()), '\n')
289 289 continue
290 290 elif r == 's':
291 291 r = resp_file[0] = 'n'
292 292 elif r == 'f':
293 293 r = resp_file[0] = 'y'
294 294 elif r == 'd':
295 295 r = resp_all[0] = 'n'
296 296 elif r == 'a':
297 297 r = resp_all[0] = 'y'
298 298 elif r == 'q':
299 299 raise util.Abort(_('user quit'))
300 300 return r
301 301 while chunks:
302 302 chunk = chunks.pop()
303 303 if isinstance(chunk, header):
304 304 # new-file mark
305 305 resp_file = [None]
306 306 fixoffset = 0
307 307 hdr = ''.join(chunk.header)
308 308 if hdr in seen:
309 309 consumefile()
310 310 continue
311 311 seen[hdr] = True
312 312 if resp_all[0] is None:
313 313 chunk.pretty(ui)
314 314 r = prompt(_('examine changes to %s?') %
315 315 _(' and ').join(map(repr, chunk.files())))
316 316 if r == 'y':
317 317 applied[chunk.filename()] = [chunk]
318 318 if chunk.allhunks():
319 319 applied[chunk.filename()] += consumefile()
320 320 else:
321 321 consumefile()
322 322 else:
323 323 # new hunk
324 324 if resp_file[0] is None and resp_all[0] is None:
325 325 chunk.pretty(ui)
326 326 r = prompt(_('record this change to %r?') %
327 327 chunk.filename())
328 328 if r == 'y':
329 329 if fixoffset:
330 330 chunk = copy.copy(chunk)
331 331 chunk.toline += fixoffset
332 332 applied[chunk.filename()].append(chunk)
333 333 else:
334 334 fixoffset += chunk.removed - chunk.added
335 335 return reduce(operator.add, [h for h in applied.itervalues()
336 336 if h[0].special() or len(h) > 1], [])
337 337
338 338 def record(ui, repo, *pats, **opts):
339 339 '''interactively select changes to commit
340 340
341 341 If a list of files is omitted, all changes reported by "hg status"
342 342 will be candidates for recording.
343 343
344 See 'hg help dates' for a list of formats valid for -d/--date.
345
344 346 You will be prompted for whether to record changes to each
345 347 modified file, and for files with multiple changes, for each
346 348 change to use. For each query, the following responses are
347 349 possible:
348 350
349 351 y - record this change
350 352 n - skip this change
351 353
352 354 s - skip remaining changes to this file
353 355 f - record remaining changes to this file
354 356
355 357 d - done, skip remaining changes and files
356 358 a - record all changes to all remaining files
357 359 q - quit, recording no changes
358 360
359 361 ? - display help'''
360 362
361 363 def record_committer(ui, repo, pats, opts):
362 364 commands.commit(ui, repo, *pats, **opts)
363 365
364 366 dorecord(ui, repo, record_committer, *pats, **opts)
365 367
366 368
367 369 def qrecord(ui, repo, patch, *pats, **opts):
368 370 '''interactively record a new patch
369 371
370 372 see 'hg help qnew' & 'hg help record' for more information and usage
371 373 '''
372 374
373 375 try:
374 376 mq = extensions.find('mq')
375 377 except KeyError:
376 378 raise util.Abort(_("'mq' extension not loaded"))
377 379
378 380 def qrecord_committer(ui, repo, pats, opts):
379 381 mq.new(ui, repo, patch, *pats, **opts)
380 382
381 383 opts = opts.copy()
382 384 opts['force'] = True # always 'qnew -f'
383 385 dorecord(ui, repo, qrecord_committer, *pats, **opts)
384 386
385 387
386 388 def dorecord(ui, repo, committer, *pats, **opts):
387 389 if not ui.interactive:
388 390 raise util.Abort(_('running non-interactively, use commit instead'))
389 391
390 392 def recordfunc(ui, repo, files, message, match, opts):
391 393 """This is generic record driver.
392 394
393 395 It's job is to interactively filter local changes, and accordingly
394 396 prepare working dir into a state, where the job can be delegated to
395 397 non-interactive commit command such as 'commit' or 'qrefresh'.
396 398
397 399 After the actual job is done by non-interactive command, working dir
398 400 state is restored to original.
399 401
400 402 In the end we'll record intresting changes, and everything else will be
401 403 left in place, so the user can continue his work.
402 404 """
403 405 if files:
404 406 changes = None
405 407 else:
406 408 changes = repo.status(files=files, match=match)[:5]
407 409 modified, added, removed = changes[:3]
408 410 files = modified + added + removed
409 411 diffopts = mdiff.diffopts(git=True, nodates=True)
410 412 fp = cStringIO.StringIO()
411 413 patch.diff(repo, repo.dirstate.parents()[0], files=files,
412 414 match=match, changes=changes, opts=diffopts, fp=fp)
413 415 fp.seek(0)
414 416
415 417 # 1. filter patch, so we have intending-to apply subset of it
416 418 chunks = filterpatch(ui, parsepatch(fp))
417 419 del fp
418 420
419 421 contenders = {}
420 422 for h in chunks:
421 423 try: contenders.update(dict.fromkeys(h.files()))
422 424 except AttributeError: pass
423 425
424 426 newfiles = [f for f in files if f in contenders]
425 427
426 428 if not newfiles:
427 429 ui.status(_('no changes to record\n'))
428 430 return 0
429 431
430 432 if changes is None:
431 433 changes = repo.status(files=newfiles, match=match)[:5]
432 434 modified = dict.fromkeys(changes[0])
433 435
434 436 # 2. backup changed files, so we can restore them in the end
435 437 backups = {}
436 438 backupdir = repo.join('record-backups')
437 439 try:
438 440 os.mkdir(backupdir)
439 441 except OSError, err:
440 442 if err.errno != errno.EEXIST:
441 443 raise
442 444 try:
443 445 # backup continues
444 446 for f in newfiles:
445 447 if f not in modified:
446 448 continue
447 449 fd, tmpname = tempfile.mkstemp(prefix=f.replace('/', '_')+'.',
448 450 dir=backupdir)
449 451 os.close(fd)
450 452 ui.debug('backup %r as %r\n' % (f, tmpname))
451 453 util.copyfile(repo.wjoin(f), tmpname)
452 454 backups[f] = tmpname
453 455
454 456 fp = cStringIO.StringIO()
455 457 for c in chunks:
456 458 if c.filename() in backups:
457 459 c.write(fp)
458 460 dopatch = fp.tell()
459 461 fp.seek(0)
460 462
461 463 # 3a. apply filtered patch to clean repo (clean)
462 464 if backups:
463 465 hg.revert(repo, repo.dirstate.parents()[0], backups.has_key)
464 466
465 467 # 3b. (apply)
466 468 if dopatch:
467 469 ui.debug('applying patch\n')
468 470 ui.debug(fp.getvalue())
469 471 patch.internalpatch(fp, ui, 1, repo.root)
470 472 del fp
471 473
472 474 # 4. We prepared working directory according to filtered patch.
473 475 # Now is the time to delegate the job to commit/qrefresh or the like!
474 476
475 477 # it is important to first chdir to repo root -- we'll call a
476 478 # highlevel command with list of pathnames relative to repo root
477 479 cwd = os.getcwd()
478 480 os.chdir(repo.root)
479 481 try:
480 482 committer(ui, repo, newfiles, opts)
481 483 finally:
482 484 os.chdir(cwd)
483 485
484 486 return 0
485 487 finally:
486 488 # 5. finally restore backed-up files
487 489 try:
488 490 for realname, tmpname in backups.iteritems():
489 491 ui.debug('restoring %r to %r\n' % (tmpname, realname))
490 492 util.copyfile(tmpname, repo.wjoin(realname))
491 493 os.unlink(tmpname)
492 494 os.rmdir(backupdir)
493 495 except OSError:
494 496 pass
495 497 return cmdutil.commit(ui, repo, recordfunc, pats, opts)
496 498
497 499 cmdtable = {
498 500 "record":
499 501 (record,
500 502
501 503 # add commit options
502 504 commands.table['^commit|ci'][1],
503 505
504 506 _('hg record [OPTION]... [FILE]...')),
505 507 }
506 508
507 509
508 510 def extsetup():
509 511 try:
510 512 mq = extensions.find('mq')
511 513 except KeyError:
512 514 return
513 515
514 516 qcmdtable = {
515 517 "qrecord":
516 518 (qrecord,
517 519
518 520 # add qnew options, except '--force'
519 521 [opt for opt in mq.cmdtable['qnew'][1] if opt[1] != 'force'],
520 522
521 523 _('hg qrecord [OPTION]... PATCH [FILE]...')),
522 524 }
523 525
524 526 cmdtable.update(qcmdtable)
525 527
@@ -1,3135 +1,3146
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import *
9 9 from i18n import _
10 10 import os, re, sys, urllib
11 11 import hg, util, revlog, bundlerepo, extensions
12 12 import difflib, patch, time, help, mdiff, tempfile
13 13 import errno, version, socket
14 14 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15 15
16 16 # Commands start here, listed alphabetically
17 17
18 18 def add(ui, repo, *pats, **opts):
19 19 """add the specified files on the next commit
20 20
21 21 Schedule files to be version controlled and added to the repository.
22 22
23 23 The files will be added to the repository at the next commit. To
24 24 undo an add before that, see hg revert.
25 25
26 26 If no names are given, add all files in the repository.
27 27 """
28 28
29 29 rejected = None
30 30 exacts = {}
31 31 names = []
32 32 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
33 33 badmatch=util.always):
34 34 if exact:
35 35 if ui.verbose:
36 36 ui.status(_('adding %s\n') % rel)
37 37 names.append(abs)
38 38 exacts[abs] = 1
39 39 elif abs not in repo.dirstate:
40 40 ui.status(_('adding %s\n') % rel)
41 41 names.append(abs)
42 42 if not opts.get('dry_run'):
43 43 rejected = repo.add(names)
44 44 rejected = [p for p in rejected if p in exacts]
45 45 return rejected and 1 or 0
46 46
47 47 def addremove(ui, repo, *pats, **opts):
48 48 """add all new files, delete all missing files
49 49
50 50 Add all new files and remove all missing files from the repository.
51 51
52 52 New files are ignored if they match any of the patterns in .hgignore. As
53 53 with add, these changes take effect at the next commit.
54 54
55 55 Use the -s option to detect renamed files. With a parameter > 0,
56 56 this compares every removed file with every added file and records
57 57 those similar enough as renames. This option takes a percentage
58 58 between 0 (disabled) and 100 (files must be identical) as its
59 59 parameter. Detecting renamed files this way can be expensive.
60 60 """
61 61 try:
62 62 sim = float(opts.get('similarity') or 0)
63 63 except ValueError:
64 64 raise util.Abort(_('similarity must be a number'))
65 65 if sim < 0 or sim > 100:
66 66 raise util.Abort(_('similarity must be between 0 and 100'))
67 67 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
68 68
69 69 def annotate(ui, repo, *pats, **opts):
70 70 """show changeset information per file line
71 71
72 72 List changes in files, showing the revision id responsible for each line
73 73
74 74 This command is useful to discover who did a change or when a change took
75 75 place.
76 76
77 77 Without the -a option, annotate will avoid processing files it
78 78 detects as binary. With -a, annotate will generate an annotation
79 79 anyway, probably with undesirable results.
80 80 """
81 81 datefunc = ui.quiet and util.shortdate or util.datestr
82 82 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
83 83
84 84 if not pats:
85 85 raise util.Abort(_('at least one file name or pattern required'))
86 86
87 87 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
88 88 ('number', lambda x: str(x[0].rev())),
89 89 ('changeset', lambda x: short(x[0].node())),
90 90 ('date', getdate),
91 91 ('follow', lambda x: x[0].path()),
92 92 ]
93 93
94 94 if (not opts['user'] and not opts['changeset'] and not opts['date']
95 95 and not opts['follow']):
96 96 opts['number'] = 1
97 97
98 98 linenumber = opts.get('line_number') is not None
99 99 if (linenumber and (not opts['changeset']) and (not opts['number'])):
100 100 raise util.Abort(_('at least one of -n/-c is required for -l'))
101 101
102 102 funcmap = [func for op, func in opmap if opts.get(op)]
103 103 if linenumber:
104 104 lastfunc = funcmap[-1]
105 105 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
106 106
107 107 ctx = repo.changectx(opts['rev'])
108 108
109 109 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
110 110 node=ctx.node()):
111 111 fctx = ctx.filectx(abs)
112 112 if not opts['text'] and util.binary(fctx.data()):
113 113 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
114 114 continue
115 115
116 116 lines = fctx.annotate(follow=opts.get('follow'),
117 117 linenumber=linenumber)
118 118 pieces = []
119 119
120 120 for f in funcmap:
121 121 l = [f(n) for n, dummy in lines]
122 122 if l:
123 123 m = max(map(len, l))
124 124 pieces.append(["%*s" % (m, x) for x in l])
125 125
126 126 if pieces:
127 127 for p, l in zip(zip(*pieces), lines):
128 128 ui.write("%s: %s" % (" ".join(p), l[1]))
129 129
130 130 def archive(ui, repo, dest, **opts):
131 131 '''create unversioned archive of a repository revision
132 132
133 133 By default, the revision used is the parent of the working
134 134 directory; use "-r" to specify a different revision.
135 135
136 136 To specify the type of archive to create, use "-t". Valid
137 137 types are:
138 138
139 139 "files" (default): a directory full of files
140 140 "tar": tar archive, uncompressed
141 141 "tbz2": tar archive, compressed using bzip2
142 142 "tgz": tar archive, compressed using gzip
143 143 "uzip": zip archive, uncompressed
144 144 "zip": zip archive, compressed using deflate
145 145
146 146 The exact name of the destination archive or directory is given
147 147 using a format string; see "hg help export" for details.
148 148
149 149 Each member added to an archive file has a directory prefix
150 150 prepended. Use "-p" to specify a format string for the prefix.
151 151 The default is the basename of the archive, with suffixes removed.
152 152 '''
153 153
154 154 ctx = repo.changectx(opts['rev'])
155 155 if not ctx:
156 156 raise util.Abort(_('repository has no revisions'))
157 157 node = ctx.node()
158 158 dest = cmdutil.make_filename(repo, dest, node)
159 159 if os.path.realpath(dest) == repo.root:
160 160 raise util.Abort(_('repository root cannot be destination'))
161 161 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
162 162 kind = opts.get('type') or 'files'
163 163 prefix = opts['prefix']
164 164 if dest == '-':
165 165 if kind == 'files':
166 166 raise util.Abort(_('cannot archive plain files to stdout'))
167 167 dest = sys.stdout
168 168 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
169 169 prefix = cmdutil.make_filename(repo, prefix, node)
170 170 archival.archive(repo, dest, node, kind, not opts['no_decode'],
171 171 matchfn, prefix)
172 172
173 173 def backout(ui, repo, node=None, rev=None, **opts):
174 174 '''reverse effect of earlier changeset
175 175
176 176 Commit the backed out changes as a new changeset. The new
177 177 changeset is a child of the backed out changeset.
178 178
179 179 If you back out a changeset other than the tip, a new head is
180 180 created. This head will be the new tip and you should merge this
181 181 backout changeset with another head (current one by default).
182 182
183 183 The --merge option remembers the parent of the working directory
184 184 before starting the backout, then merges the new head with that
185 185 changeset afterwards. This saves you from doing the merge by
186 186 hand. The result of this merge is not committed, as for a normal
187 merge.'''
187 merge.
188
189 See 'hg help dates' for a list of formats valid for -d/--date.
190 '''
188 191 if rev and node:
189 192 raise util.Abort(_("please specify just one revision"))
190 193
191 194 if not rev:
192 195 rev = node
193 196
194 197 if not rev:
195 198 raise util.Abort(_("please specify a revision to backout"))
196 199
197 200 date = opts.get('date')
198 201 if date:
199 202 opts['date'] = util.parsedate(date)
200 203
201 204 cmdutil.bail_if_changed(repo)
202 205 node = repo.lookup(rev)
203 206
204 207 op1, op2 = repo.dirstate.parents()
205 208 a = repo.changelog.ancestor(op1, node)
206 209 if a != node:
207 210 raise util.Abort(_('cannot back out change on a different branch'))
208 211
209 212 p1, p2 = repo.changelog.parents(node)
210 213 if p1 == nullid:
211 214 raise util.Abort(_('cannot back out a change with no parents'))
212 215 if p2 != nullid:
213 216 if not opts['parent']:
214 217 raise util.Abort(_('cannot back out a merge changeset without '
215 218 '--parent'))
216 219 p = repo.lookup(opts['parent'])
217 220 if p not in (p1, p2):
218 221 raise util.Abort(_('%s is not a parent of %s') %
219 222 (short(p), short(node)))
220 223 parent = p
221 224 else:
222 225 if opts['parent']:
223 226 raise util.Abort(_('cannot use --parent on non-merge changeset'))
224 227 parent = p1
225 228
226 229 hg.clean(repo, node, show_stats=False)
227 230 revert_opts = opts.copy()
228 231 revert_opts['date'] = None
229 232 revert_opts['all'] = True
230 233 revert_opts['rev'] = hex(parent)
231 234 revert_opts['no_backup'] = None
232 235 revert(ui, repo, **revert_opts)
233 236 commit_opts = opts.copy()
234 237 commit_opts['addremove'] = False
235 238 if not commit_opts['message'] and not commit_opts['logfile']:
236 239 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
237 240 commit_opts['force_editor'] = True
238 241 commit(ui, repo, **commit_opts)
239 242 def nice(node):
240 243 return '%d:%s' % (repo.changelog.rev(node), short(node))
241 244 ui.status(_('changeset %s backs out changeset %s\n') %
242 245 (nice(repo.changelog.tip()), nice(node)))
243 246 if op1 != node:
244 247 hg.clean(repo, op1, show_stats=False)
245 248 if opts['merge']:
246 249 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
247 250 hg.merge(repo, hex(repo.changelog.tip()))
248 251 else:
249 252 ui.status(_('the backout changeset is a new head - '
250 253 'do not forget to merge\n'))
251 254 ui.status(_('(use "backout --merge" '
252 255 'if you want to auto-merge)\n'))
253 256
254 257 def bisect(ui, repo, rev=None, extra=None,
255 258 reset=None, good=None, bad=None, skip=None, noupdate=None):
256 259 """subdivision search of changesets
257 260
258 261 This command helps to find changesets which introduce problems.
259 262 To use, mark the earliest changeset you know exhibits the problem
260 263 as bad, then mark the latest changeset which is free from the
261 264 problem as good. Bisect will update your working directory to a
262 265 revision for testing. Once you have performed tests, mark the
263 266 working directory as bad or good and bisect will either update to
264 267 another candidate changeset or announce that it has found the bad
265 268 revision.
266 269 """
267 270 # backward compatibility
268 271 if rev in "good bad reset init".split():
269 272 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
270 273 cmd, rev, extra = rev, extra, None
271 274 if cmd == "good":
272 275 good = True
273 276 elif cmd == "bad":
274 277 bad = True
275 278 else:
276 279 reset = True
277 280 elif extra or good + bad + skip + reset > 1:
278 281 raise util.Abort("Incompatible arguments")
279 282
280 283 if reset:
281 284 p = repo.join("bisect.state")
282 285 if os.path.exists(p):
283 286 os.unlink(p)
284 287 return
285 288
286 289 # load state
287 290 state = {'good': [], 'bad': [], 'skip': []}
288 291 if os.path.exists(repo.join("bisect.state")):
289 292 for l in repo.opener("bisect.state"):
290 293 kind, node = l[:-1].split()
291 294 node = repo.lookup(node)
292 295 if kind not in state:
293 296 raise util.Abort(_("unknown bisect kind %s") % kind)
294 297 state[kind].append(node)
295 298
296 299 # update state
297 300 node = repo.lookup(rev or '.')
298 301 if good:
299 302 state['good'].append(node)
300 303 elif bad:
301 304 state['bad'].append(node)
302 305 elif skip:
303 306 state['skip'].append(node)
304 307
305 308 # save state
306 309 f = repo.opener("bisect.state", "w", atomictemp=True)
307 310 wlock = repo.wlock()
308 311 try:
309 312 for kind in state:
310 313 for node in state[kind]:
311 314 f.write("%s %s\n" % (kind, hg.hex(node)))
312 315 f.rename()
313 316 finally:
314 317 del wlock
315 318
316 319 if not state['good'] or not state['bad']:
317 320 return
318 321
319 322 # actually bisect
320 323 node, changesets, good = hbisect.bisect(repo.changelog, state)
321 324 if changesets == 0:
322 325 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
323 326 displayer = cmdutil.show_changeset(ui, repo, {})
324 327 displayer.show(changenode=node)
325 328 elif node is not None:
326 329 # compute the approximate number of remaining tests
327 330 tests, size = 0, 2
328 331 while size <= changesets:
329 332 tests, size = tests + 1, size * 2
330 333 rev = repo.changelog.rev(node)
331 334 ui.write(_("Testing changeset %s:%s "
332 335 "(%s changesets remaining, ~%s tests)\n")
333 336 % (rev, hg.short(node), changesets, tests))
334 337 if not noupdate:
335 338 cmdutil.bail_if_changed(repo)
336 339 return hg.clean(repo, node)
337 340
338 341 def branch(ui, repo, label=None, **opts):
339 342 """set or show the current branch name
340 343
341 344 With no argument, show the current branch name. With one argument,
342 345 set the working directory branch name (the branch does not exist in
343 346 the repository until the next commit).
344 347
345 348 Unless --force is specified, branch will not let you set a
346 349 branch name that shadows an existing branch.
347 350
348 351 Use the command 'hg update' to switch to an existing branch.
349 352 """
350 353
351 354 if label:
352 355 if not opts.get('force') and label in repo.branchtags():
353 356 if label not in [p.branch() for p in repo.workingctx().parents()]:
354 357 raise util.Abort(_('a branch of the same name already exists'
355 358 ' (use --force to override)'))
356 359 repo.dirstate.setbranch(util.fromlocal(label))
357 360 ui.status(_('marked working directory as branch %s\n') % label)
358 361 else:
359 362 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
360 363
361 364 def branches(ui, repo, active=False):
362 365 """list repository named branches
363 366
364 367 List the repository's named branches, indicating which ones are
365 368 inactive. If active is specified, only show active branches.
366 369
367 370 A branch is considered active if it contains unmerged heads.
368 371
369 372 Use the command 'hg update' to switch to an existing branch.
370 373 """
371 374 b = repo.branchtags()
372 375 heads = dict.fromkeys(repo.heads(), 1)
373 376 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
374 377 l.sort()
375 378 l.reverse()
376 379 for ishead, r, n, t in l:
377 380 if active and not ishead:
378 381 # If we're only displaying active branches, abort the loop on
379 382 # encountering the first inactive head
380 383 break
381 384 else:
382 385 hexfunc = ui.debugflag and hex or short
383 386 if ui.quiet:
384 387 ui.write("%s\n" % t)
385 388 else:
386 389 spaces = " " * (30 - util.locallen(t))
387 390 # The code only gets here if inactive branches are being
388 391 # displayed or the branch is active.
389 392 isinactive = ((not ishead) and " (inactive)") or ''
390 393 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
391 394
392 395 def bundle(ui, repo, fname, dest=None, **opts):
393 396 """create a changegroup file
394 397
395 398 Generate a compressed changegroup file collecting changesets not
396 399 found in the other repository.
397 400
398 401 If no destination repository is specified the destination is assumed
399 402 to have all the nodes specified by one or more --base parameters.
400 403 To create a bundle containing all changesets, use --base null.
401 404
402 405 The bundle file can then be transferred using conventional means and
403 406 applied to another repository with the unbundle or pull command.
404 407 This is useful when direct push and pull are not available or when
405 408 exporting an entire repository is undesirable.
406 409
407 410 Applying bundles preserves all changeset contents including
408 411 permissions, copy/rename information, and revision history.
409 412 """
410 413 revs = opts.get('rev') or None
411 414 if revs:
412 415 revs = [repo.lookup(rev) for rev in revs]
413 416 base = opts.get('base')
414 417 if base:
415 418 if dest:
416 419 raise util.Abort(_("--base is incompatible with specifiying "
417 420 "a destination"))
418 421 base = [repo.lookup(rev) for rev in base]
419 422 # create the right base
420 423 # XXX: nodesbetween / changegroup* should be "fixed" instead
421 424 o = []
422 425 has = {nullid: None}
423 426 for n in base:
424 427 has.update(repo.changelog.reachable(n))
425 428 if revs:
426 429 visit = list(revs)
427 430 else:
428 431 visit = repo.changelog.heads()
429 432 seen = {}
430 433 while visit:
431 434 n = visit.pop(0)
432 435 parents = [p for p in repo.changelog.parents(n) if p not in has]
433 436 if len(parents) == 0:
434 437 o.insert(0, n)
435 438 else:
436 439 for p in parents:
437 440 if p not in seen:
438 441 seen[p] = 1
439 442 visit.append(p)
440 443 else:
441 444 cmdutil.setremoteconfig(ui, opts)
442 445 dest, revs, checkout = hg.parseurl(
443 446 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
444 447 other = hg.repository(ui, dest)
445 448 o = repo.findoutgoing(other, force=opts['force'])
446 449
447 450 if revs:
448 451 cg = repo.changegroupsubset(o, revs, 'bundle')
449 452 else:
450 453 cg = repo.changegroup(o, 'bundle')
451 454 changegroup.writebundle(cg, fname, "HG10BZ")
452 455
453 456 def cat(ui, repo, file1, *pats, **opts):
454 457 """output the current or given revision of files
455 458
456 459 Print the specified files as they were at the given revision.
457 460 If no revision is given, the parent of the working directory is used,
458 461 or tip if no revision is checked out.
459 462
460 463 Output may be to a file, in which case the name of the file is
461 464 given using a format string. The formatting rules are the same as
462 465 for the export command, with the following additions:
463 466
464 467 %s basename of file being printed
465 468 %d dirname of file being printed, or '.' if in repo root
466 469 %p root-relative path name of file being printed
467 470 """
468 471 ctx = repo.changectx(opts['rev'])
469 472 err = 1
470 473 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
471 474 ctx.node()):
472 475 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
473 476 data = ctx.filectx(abs).data()
474 477 if opts.get('decode'):
475 478 data = repo.wwritedata(abs, data)
476 479 fp.write(data)
477 480 err = 0
478 481 return err
479 482
480 483 def clone(ui, source, dest=None, **opts):
481 484 """make a copy of an existing repository
482 485
483 486 Create a copy of an existing repository in a new directory.
484 487
485 488 If no destination directory name is specified, it defaults to the
486 489 basename of the source.
487 490
488 491 The location of the source is added to the new repository's
489 492 .hg/hgrc file, as the default to be used for future pulls.
490 493
491 494 For efficiency, hardlinks are used for cloning whenever the source
492 495 and destination are on the same filesystem (note this applies only
493 496 to the repository data, not to the checked out files). Some
494 497 filesystems, such as AFS, implement hardlinking incorrectly, but
495 498 do not report errors. In these cases, use the --pull option to
496 499 avoid hardlinking.
497 500
498 501 You can safely clone repositories and checked out files using full
499 502 hardlinks with
500 503
501 504 $ cp -al REPO REPOCLONE
502 505
503 506 which is the fastest way to clone. However, the operation is not
504 507 atomic (making sure REPO is not modified during the operation is
505 508 up to you) and you have to make sure your editor breaks hardlinks
506 509 (Emacs and most Linux Kernel tools do so).
507 510
508 511 If you use the -r option to clone up to a specific revision, no
509 512 subsequent revisions will be present in the cloned repository.
510 513 This option implies --pull, even on local repositories.
511 514
512 515 See pull for valid source format details.
513 516
514 517 It is possible to specify an ssh:// URL as the destination, but no
515 518 .hg/hgrc and working directory will be created on the remote side.
516 519 Look at the help text for the pull command for important details
517 520 about ssh:// URLs.
518 521 """
519 522 cmdutil.setremoteconfig(ui, opts)
520 523 hg.clone(ui, source, dest,
521 524 pull=opts['pull'],
522 525 stream=opts['uncompressed'],
523 526 rev=opts['rev'],
524 527 update=not opts['noupdate'])
525 528
526 529 def commit(ui, repo, *pats, **opts):
527 530 """commit the specified files or all outstanding changes
528 531
529 532 Commit changes to the given files into the repository.
530 533
531 534 If a list of files is omitted, all changes reported by "hg status"
532 535 will be committed.
533 536
534 537 If no commit message is specified, the configured editor is started to
535 538 enter a message.
539
540 See 'hg help dates' for a list of formats valid for -d/--date.
536 541 """
537 542 def commitfunc(ui, repo, files, message, match, opts):
538 543 return repo.commit(files, message, opts['user'], opts['date'], match,
539 544 force_editor=opts.get('force_editor'))
540 545 cmdutil.commit(ui, repo, commitfunc, pats, opts)
541 546
542 547 def copy(ui, repo, *pats, **opts):
543 548 """mark files as copied for the next commit
544 549
545 550 Mark dest as having copies of source files. If dest is a
546 551 directory, copies are put in that directory. If dest is a file,
547 552 there can only be one source.
548 553
549 554 By default, this command copies the contents of files as they
550 555 stand in the working directory. If invoked with --after, the
551 556 operation is recorded, but no copying is performed.
552 557
553 558 This command takes effect in the next commit. To undo a copy
554 559 before that, see hg revert.
555 560 """
556 561 wlock = repo.wlock(False)
557 562 try:
558 563 return cmdutil.copy(ui, repo, pats, opts)
559 564 finally:
560 565 del wlock
561 566
562 567 def debugancestor(ui, index, rev1, rev2):
563 568 """find the ancestor revision of two revisions in a given index"""
564 569 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
565 570 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
566 571 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
567 572
568 573 def debugcomplete(ui, cmd='', **opts):
569 574 """returns the completion list associated with the given command"""
570 575
571 576 if opts['options']:
572 577 options = []
573 578 otables = [globalopts]
574 579 if cmd:
575 580 aliases, entry = cmdutil.findcmd(ui, cmd, table)
576 581 otables.append(entry[1])
577 582 for t in otables:
578 583 for o in t:
579 584 if o[0]:
580 585 options.append('-%s' % o[0])
581 586 options.append('--%s' % o[1])
582 587 ui.write("%s\n" % "\n".join(options))
583 588 return
584 589
585 590 clist = cmdutil.findpossible(ui, cmd, table).keys()
586 591 clist.sort()
587 592 ui.write("%s\n" % "\n".join(clist))
588 593
589 594 def debugfsinfo(ui, path = "."):
590 595 file('.debugfsinfo', 'w').write('')
591 596 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
592 597 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
593 598 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
594 599 and 'yes' or 'no'))
595 600 os.unlink('.debugfsinfo')
596 601
597 602 def debugrebuildstate(ui, repo, rev=""):
598 603 """rebuild the dirstate as it would look like for the given revision"""
599 604 if rev == "":
600 605 rev = repo.changelog.tip()
601 606 ctx = repo.changectx(rev)
602 607 files = ctx.manifest()
603 608 wlock = repo.wlock()
604 609 try:
605 610 repo.dirstate.rebuild(rev, files)
606 611 finally:
607 612 del wlock
608 613
609 614 def debugcheckstate(ui, repo):
610 615 """validate the correctness of the current dirstate"""
611 616 parent1, parent2 = repo.dirstate.parents()
612 617 m1 = repo.changectx(parent1).manifest()
613 618 m2 = repo.changectx(parent2).manifest()
614 619 errors = 0
615 620 for f in repo.dirstate:
616 621 state = repo.dirstate[f]
617 622 if state in "nr" and f not in m1:
618 623 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
619 624 errors += 1
620 625 if state in "a" and f in m1:
621 626 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
622 627 errors += 1
623 628 if state in "m" and f not in m1 and f not in m2:
624 629 ui.warn(_("%s in state %s, but not in either manifest\n") %
625 630 (f, state))
626 631 errors += 1
627 632 for f in m1:
628 633 state = repo.dirstate[f]
629 634 if state not in "nrm":
630 635 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
631 636 errors += 1
632 637 if errors:
633 638 error = _(".hg/dirstate inconsistent with current parent's manifest")
634 639 raise util.Abort(error)
635 640
636 641 def showconfig(ui, repo, *values, **opts):
637 642 """show combined config settings from all hgrc files
638 643
639 644 With no args, print names and values of all config items.
640 645
641 646 With one arg of the form section.name, print just the value of
642 647 that config item.
643 648
644 649 With multiple args, print names and values of all config items
645 650 with matching section names."""
646 651
647 652 untrusted = bool(opts.get('untrusted'))
648 653 if values:
649 654 if len([v for v in values if '.' in v]) > 1:
650 655 raise util.Abort(_('only one config item permitted'))
651 656 for section, name, value in ui.walkconfig(untrusted=untrusted):
652 657 sectname = section + '.' + name
653 658 if values:
654 659 for v in values:
655 660 if v == section:
656 661 ui.write('%s=%s\n' % (sectname, value))
657 662 elif v == sectname:
658 663 ui.write(value, '\n')
659 664 else:
660 665 ui.write('%s=%s\n' % (sectname, value))
661 666
662 667 def debugsetparents(ui, repo, rev1, rev2=None):
663 668 """manually set the parents of the current working directory
664 669
665 670 This is useful for writing repository conversion tools, but should
666 671 be used with care.
667 672 """
668 673
669 674 if not rev2:
670 675 rev2 = hex(nullid)
671 676
672 677 wlock = repo.wlock()
673 678 try:
674 679 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
675 680 finally:
676 681 del wlock
677 682
678 683 def debugstate(ui, repo):
679 684 """show the contents of the current dirstate"""
680 685 k = repo.dirstate._map.items()
681 686 k.sort()
682 687 for file_, ent in k:
683 688 if ent[3] == -1:
684 689 # Pad or slice to locale representation
685 690 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(0)))
686 691 timestr = 'unset'
687 692 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
688 693 else:
689 694 timestr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ent[3]))
690 695 if ent[1] & 020000:
691 696 mode = 'lnk'
692 697 else:
693 698 mode = '%3o' % (ent[1] & 0777)
694 699 ui.write("%c %s %10d %s %s\n" % (ent[0], mode, ent[2], timestr, file_))
695 700 for f in repo.dirstate.copies():
696 701 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
697 702
698 703 def debugdata(ui, file_, rev):
699 704 """dump the contents of a data file revision"""
700 705 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
701 706 try:
702 707 ui.write(r.revision(r.lookup(rev)))
703 708 except KeyError:
704 709 raise util.Abort(_('invalid revision identifier %s') % rev)
705 710
706 711 def debugdate(ui, date, range=None, **opts):
707 712 """parse and display a date"""
708 713 if opts["extended"]:
709 714 d = util.parsedate(date, util.extendeddateformats)
710 715 else:
711 716 d = util.parsedate(date)
712 717 ui.write("internal: %s %s\n" % d)
713 718 ui.write("standard: %s\n" % util.datestr(d))
714 719 if range:
715 720 m = util.matchdate(range)
716 721 ui.write("match: %s\n" % m(d[0]))
717 722
718 723 def debugindex(ui, file_):
719 724 """dump the contents of an index file"""
720 725 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
721 726 ui.write(" rev offset length base linkrev" +
722 727 " nodeid p1 p2\n")
723 728 for i in xrange(r.count()):
724 729 node = r.node(i)
725 730 try:
726 731 pp = r.parents(node)
727 732 except:
728 733 pp = [nullid, nullid]
729 734 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
730 735 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
731 736 short(node), short(pp[0]), short(pp[1])))
732 737
733 738 def debugindexdot(ui, file_):
734 739 """dump an index DAG as a .dot file"""
735 740 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
736 741 ui.write("digraph G {\n")
737 742 for i in xrange(r.count()):
738 743 node = r.node(i)
739 744 pp = r.parents(node)
740 745 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
741 746 if pp[1] != nullid:
742 747 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
743 748 ui.write("}\n")
744 749
745 750 def debuginstall(ui):
746 751 '''test Mercurial installation'''
747 752
748 753 def writetemp(contents):
749 754 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
750 755 f = os.fdopen(fd, "wb")
751 756 f.write(contents)
752 757 f.close()
753 758 return name
754 759
755 760 problems = 0
756 761
757 762 # encoding
758 763 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
759 764 try:
760 765 util.fromlocal("test")
761 766 except util.Abort, inst:
762 767 ui.write(" %s\n" % inst)
763 768 ui.write(_(" (check that your locale is properly set)\n"))
764 769 problems += 1
765 770
766 771 # compiled modules
767 772 ui.status(_("Checking extensions...\n"))
768 773 try:
769 774 import bdiff, mpatch, base85
770 775 except Exception, inst:
771 776 ui.write(" %s\n" % inst)
772 777 ui.write(_(" One or more extensions could not be found"))
773 778 ui.write(_(" (check that you compiled the extensions)\n"))
774 779 problems += 1
775 780
776 781 # templates
777 782 ui.status(_("Checking templates...\n"))
778 783 try:
779 784 import templater
780 785 t = templater.templater(templater.templatepath("map-cmdline.default"))
781 786 except Exception, inst:
782 787 ui.write(" %s\n" % inst)
783 788 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
784 789 problems += 1
785 790
786 791 # patch
787 792 ui.status(_("Checking patch...\n"))
788 793 patchproblems = 0
789 794 a = "1\n2\n3\n4\n"
790 795 b = "1\n2\n3\ninsert\n4\n"
791 796 fa = writetemp(a)
792 797 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
793 798 os.path.basename(fa))
794 799 fd = writetemp(d)
795 800
796 801 files = {}
797 802 try:
798 803 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
799 804 except util.Abort, e:
800 805 ui.write(_(" patch call failed:\n"))
801 806 ui.write(" " + str(e) + "\n")
802 807 patchproblems += 1
803 808 else:
804 809 if list(files) != [os.path.basename(fa)]:
805 810 ui.write(_(" unexpected patch output!\n"))
806 811 patchproblems += 1
807 812 a = file(fa).read()
808 813 if a != b:
809 814 ui.write(_(" patch test failed!\n"))
810 815 patchproblems += 1
811 816
812 817 if patchproblems:
813 818 if ui.config('ui', 'patch'):
814 819 ui.write(_(" (Current patch tool may be incompatible with patch,"
815 820 " or misconfigured. Please check your .hgrc file)\n"))
816 821 else:
817 822 ui.write(_(" Internal patcher failure, please report this error"
818 823 " to http://www.selenic.com/mercurial/bts\n"))
819 824 problems += patchproblems
820 825
821 826 os.unlink(fa)
822 827 os.unlink(fd)
823 828
824 829 # editor
825 830 ui.status(_("Checking commit editor...\n"))
826 831 editor = ui.geteditor()
827 832 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
828 833 if not cmdpath:
829 834 if editor == 'vi':
830 835 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
831 836 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
832 837 else:
833 838 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
834 839 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
835 840 problems += 1
836 841
837 842 # check username
838 843 ui.status(_("Checking username...\n"))
839 844 user = os.environ.get("HGUSER")
840 845 if user is None:
841 846 user = ui.config("ui", "username")
842 847 if user is None:
843 848 user = os.environ.get("EMAIL")
844 849 if not user:
845 850 ui.warn(" ")
846 851 ui.username()
847 852 ui.write(_(" (specify a username in your .hgrc file)\n"))
848 853
849 854 if not problems:
850 855 ui.status(_("No problems detected\n"))
851 856 else:
852 857 ui.write(_("%s problems detected,"
853 858 " please check your install!\n") % problems)
854 859
855 860 return problems
856 861
857 862 def debugrename(ui, repo, file1, *pats, **opts):
858 863 """dump rename information"""
859 864
860 865 ctx = repo.changectx(opts.get('rev', 'tip'))
861 866 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
862 867 ctx.node()):
863 868 fctx = ctx.filectx(abs)
864 869 m = fctx.filelog().renamed(fctx.filenode())
865 870 if m:
866 871 ui.write(_("%s renamed from %s:%s\n") % (rel, m[0], hex(m[1])))
867 872 else:
868 873 ui.write(_("%s not renamed\n") % rel)
869 874
870 875 def debugwalk(ui, repo, *pats, **opts):
871 876 """show how files match on given patterns"""
872 877 items = list(cmdutil.walk(repo, pats, opts))
873 878 if not items:
874 879 return
875 880 fmt = '%%s %%-%ds %%-%ds %%s' % (
876 881 max([len(abs) for (src, abs, rel, exact) in items]),
877 882 max([len(rel) for (src, abs, rel, exact) in items]))
878 883 for src, abs, rel, exact in items:
879 884 line = fmt % (src, abs, rel, exact and 'exact' or '')
880 885 ui.write("%s\n" % line.rstrip())
881 886
882 887 def diff(ui, repo, *pats, **opts):
883 888 """diff repository (or selected files)
884 889
885 890 Show differences between revisions for the specified files.
886 891
887 892 Differences between files are shown using the unified diff format.
888 893
889 894 NOTE: diff may generate unexpected results for merges, as it will
890 895 default to comparing against the working directory's first parent
891 896 changeset if no revisions are specified.
892 897
893 898 When two revision arguments are given, then changes are shown
894 899 between those revisions. If only one revision is specified then
895 900 that revision is compared to the working directory, and, when no
896 901 revisions are specified, the working directory files are compared
897 902 to its parent.
898 903
899 904 Without the -a option, diff will avoid generating diffs of files
900 905 it detects as binary. With -a, diff will generate a diff anyway,
901 906 probably with undesirable results.
902 907 """
903 908 node1, node2 = cmdutil.revpair(repo, opts['rev'])
904 909
905 910 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
906 911
907 912 patch.diff(repo, node1, node2, fns, match=matchfn,
908 913 opts=patch.diffopts(ui, opts))
909 914
910 915 def export(ui, repo, *changesets, **opts):
911 916 """dump the header and diffs for one or more changesets
912 917
913 918 Print the changeset header and diffs for one or more revisions.
914 919
915 920 The information shown in the changeset header is: author,
916 921 changeset hash, parent(s) and commit comment.
917 922
918 923 NOTE: export may generate unexpected diff output for merge changesets,
919 924 as it will compare the merge changeset against its first parent only.
920 925
921 926 Output may be to a file, in which case the name of the file is
922 927 given using a format string. The formatting rules are as follows:
923 928
924 929 %% literal "%" character
925 930 %H changeset hash (40 bytes of hexadecimal)
926 931 %N number of patches being generated
927 932 %R changeset revision number
928 933 %b basename of the exporting repository
929 934 %h short-form changeset hash (12 bytes of hexadecimal)
930 935 %n zero-padded sequence number, starting at 1
931 936 %r zero-padded changeset revision number
932 937
933 938 Without the -a option, export will avoid generating diffs of files
934 939 it detects as binary. With -a, export will generate a diff anyway,
935 940 probably with undesirable results.
936 941
937 942 With the --switch-parent option, the diff will be against the second
938 943 parent. It can be useful to review a merge.
939 944 """
940 945 if not changesets:
941 946 raise util.Abort(_("export requires at least one changeset"))
942 947 revs = cmdutil.revrange(repo, changesets)
943 948 if len(revs) > 1:
944 949 ui.note(_('exporting patches:\n'))
945 950 else:
946 951 ui.note(_('exporting patch:\n'))
947 952 patch.export(repo, revs, template=opts['output'],
948 953 switch_parent=opts['switch_parent'],
949 954 opts=patch.diffopts(ui, opts))
950 955
951 956 def grep(ui, repo, pattern, *pats, **opts):
952 957 """search for a pattern in specified files and revisions
953 958
954 959 Search revisions of files for a regular expression.
955 960
956 961 This command behaves differently than Unix grep. It only accepts
957 962 Python/Perl regexps. It searches repository history, not the
958 963 working directory. It always prints the revision number in which
959 964 a match appears.
960 965
961 966 By default, grep only prints output for the first revision of a
962 967 file in which it finds a match. To get it to print every revision
963 968 that contains a change in match status ("-" for a match that
964 969 becomes a non-match, or "+" for a non-match that becomes a match),
965 970 use the --all flag.
966 971 """
967 972 reflags = 0
968 973 if opts['ignore_case']:
969 974 reflags |= re.I
970 975 try:
971 976 regexp = re.compile(pattern, reflags)
972 977 except Exception, inst:
973 978 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
974 979 return None
975 980 sep, eol = ':', '\n'
976 981 if opts['print0']:
977 982 sep = eol = '\0'
978 983
979 984 fcache = {}
980 985 def getfile(fn):
981 986 if fn not in fcache:
982 987 fcache[fn] = repo.file(fn)
983 988 return fcache[fn]
984 989
985 990 def matchlines(body):
986 991 begin = 0
987 992 linenum = 0
988 993 while True:
989 994 match = regexp.search(body, begin)
990 995 if not match:
991 996 break
992 997 mstart, mend = match.span()
993 998 linenum += body.count('\n', begin, mstart) + 1
994 999 lstart = body.rfind('\n', begin, mstart) + 1 or begin
995 1000 lend = body.find('\n', mend)
996 1001 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
997 1002 begin = lend + 1
998 1003
999 1004 class linestate(object):
1000 1005 def __init__(self, line, linenum, colstart, colend):
1001 1006 self.line = line
1002 1007 self.linenum = linenum
1003 1008 self.colstart = colstart
1004 1009 self.colend = colend
1005 1010
1006 1011 def __eq__(self, other):
1007 1012 return self.line == other.line
1008 1013
1009 1014 matches = {}
1010 1015 copies = {}
1011 1016 def grepbody(fn, rev, body):
1012 1017 matches[rev].setdefault(fn, [])
1013 1018 m = matches[rev][fn]
1014 1019 for lnum, cstart, cend, line in matchlines(body):
1015 1020 s = linestate(line, lnum, cstart, cend)
1016 1021 m.append(s)
1017 1022
1018 1023 def difflinestates(a, b):
1019 1024 sm = difflib.SequenceMatcher(None, a, b)
1020 1025 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1021 1026 if tag == 'insert':
1022 1027 for i in xrange(blo, bhi):
1023 1028 yield ('+', b[i])
1024 1029 elif tag == 'delete':
1025 1030 for i in xrange(alo, ahi):
1026 1031 yield ('-', a[i])
1027 1032 elif tag == 'replace':
1028 1033 for i in xrange(alo, ahi):
1029 1034 yield ('-', a[i])
1030 1035 for i in xrange(blo, bhi):
1031 1036 yield ('+', b[i])
1032 1037
1033 1038 prev = {}
1034 1039 def display(fn, rev, states, prevstates):
1035 1040 datefunc = ui.quiet and util.shortdate or util.datestr
1036 1041 found = False
1037 1042 filerevmatches = {}
1038 1043 r = prev.get(fn, -1)
1039 1044 if opts['all']:
1040 1045 iter = difflinestates(states, prevstates)
1041 1046 else:
1042 1047 iter = [('', l) for l in prevstates]
1043 1048 for change, l in iter:
1044 1049 cols = [fn, str(r)]
1045 1050 if opts['line_number']:
1046 1051 cols.append(str(l.linenum))
1047 1052 if opts['all']:
1048 1053 cols.append(change)
1049 1054 if opts['user']:
1050 1055 cols.append(ui.shortuser(get(r)[1]))
1051 1056 if opts.get('date'):
1052 1057 cols.append(datefunc(get(r)[2]))
1053 1058 if opts['files_with_matches']:
1054 1059 c = (fn, r)
1055 1060 if c in filerevmatches:
1056 1061 continue
1057 1062 filerevmatches[c] = 1
1058 1063 else:
1059 1064 cols.append(l.line)
1060 1065 ui.write(sep.join(cols), eol)
1061 1066 found = True
1062 1067 return found
1063 1068
1064 1069 fstate = {}
1065 1070 skip = {}
1066 1071 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1067 1072 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1068 1073 found = False
1069 1074 follow = opts.get('follow')
1070 1075 for st, rev, fns in changeiter:
1071 1076 if st == 'window':
1072 1077 matches.clear()
1073 1078 elif st == 'add':
1074 1079 ctx = repo.changectx(rev)
1075 1080 matches[rev] = {}
1076 1081 for fn in fns:
1077 1082 if fn in skip:
1078 1083 continue
1079 1084 try:
1080 1085 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1081 1086 fstate.setdefault(fn, [])
1082 1087 if follow:
1083 1088 copied = getfile(fn).renamed(ctx.filenode(fn))
1084 1089 if copied:
1085 1090 copies.setdefault(rev, {})[fn] = copied[0]
1086 1091 except revlog.LookupError:
1087 1092 pass
1088 1093 elif st == 'iter':
1089 1094 states = matches[rev].items()
1090 1095 states.sort()
1091 1096 for fn, m in states:
1092 1097 copy = copies.get(rev, {}).get(fn)
1093 1098 if fn in skip:
1094 1099 if copy:
1095 1100 skip[copy] = True
1096 1101 continue
1097 1102 if fn in prev or fstate[fn]:
1098 1103 r = display(fn, rev, m, fstate[fn])
1099 1104 found = found or r
1100 1105 if r and not opts['all']:
1101 1106 skip[fn] = True
1102 1107 if copy:
1103 1108 skip[copy] = True
1104 1109 fstate[fn] = m
1105 1110 if copy:
1106 1111 fstate[copy] = m
1107 1112 prev[fn] = rev
1108 1113
1109 1114 fstate = fstate.items()
1110 1115 fstate.sort()
1111 1116 for fn, state in fstate:
1112 1117 if fn in skip:
1113 1118 continue
1114 1119 if fn not in copies.get(prev[fn], {}):
1115 1120 found = display(fn, rev, {}, state) or found
1116 1121 return (not found and 1) or 0
1117 1122
1118 1123 def heads(ui, repo, *branchrevs, **opts):
1119 1124 """show current repository heads or show branch heads
1120 1125
1121 1126 With no arguments, show all repository head changesets.
1122 1127
1123 1128 If branch or revisions names are given this will show the heads of
1124 1129 the specified branches or the branches those revisions are tagged
1125 1130 with.
1126 1131
1127 1132 Repository "heads" are changesets that don't have child
1128 1133 changesets. They are where development generally takes place and
1129 1134 are the usual targets for update and merge operations.
1130 1135
1131 1136 Branch heads are changesets that have a given branch tag, but have
1132 1137 no child changesets with that tag. They are usually where
1133 1138 development on the given branch takes place.
1134 1139 """
1135 1140 if opts['rev']:
1136 1141 start = repo.lookup(opts['rev'])
1137 1142 else:
1138 1143 start = None
1139 1144 if not branchrevs:
1140 1145 # Assume we're looking repo-wide heads if no revs were specified.
1141 1146 heads = repo.heads(start)
1142 1147 else:
1143 1148 heads = []
1144 1149 visitedset = util.set()
1145 1150 for branchrev in branchrevs:
1146 1151 branch = repo.changectx(branchrev).branch()
1147 1152 if branch in visitedset:
1148 1153 continue
1149 1154 visitedset.add(branch)
1150 1155 bheads = repo.branchheads(branch, start)
1151 1156 if not bheads:
1152 1157 if branch != branchrev:
1153 1158 ui.warn(_("no changes on branch %s containing %s are "
1154 1159 "reachable from %s\n")
1155 1160 % (branch, branchrev, opts['rev']))
1156 1161 else:
1157 1162 ui.warn(_("no changes on branch %s are reachable from %s\n")
1158 1163 % (branch, opts['rev']))
1159 1164 heads.extend(bheads)
1160 1165 if not heads:
1161 1166 return 1
1162 1167 displayer = cmdutil.show_changeset(ui, repo, opts)
1163 1168 for n in heads:
1164 1169 displayer.show(changenode=n)
1165 1170
1166 1171 def help_(ui, name=None, with_version=False):
1167 1172 """show help for a command, extension, or list of commands
1168 1173
1169 1174 With no arguments, print a list of commands and short help.
1170 1175
1171 1176 Given a command name, print help for that command.
1172 1177
1173 1178 Given an extension name, print help for that extension, and the
1174 1179 commands it provides."""
1175 1180 option_lists = []
1176 1181
1177 1182 def addglobalopts(aliases):
1178 1183 if ui.verbose:
1179 1184 option_lists.append((_("global options:"), globalopts))
1180 1185 if name == 'shortlist':
1181 1186 option_lists.append((_('use "hg help" for the full list '
1182 1187 'of commands'), ()))
1183 1188 else:
1184 1189 if name == 'shortlist':
1185 1190 msg = _('use "hg help" for the full list of commands '
1186 1191 'or "hg -v" for details')
1187 1192 elif aliases:
1188 1193 msg = _('use "hg -v help%s" to show aliases and '
1189 1194 'global options') % (name and " " + name or "")
1190 1195 else:
1191 1196 msg = _('use "hg -v help %s" to show global options') % name
1192 1197 option_lists.append((msg, ()))
1193 1198
1194 1199 def helpcmd(name):
1195 1200 if with_version:
1196 1201 version_(ui)
1197 1202 ui.write('\n')
1198 1203 aliases, i = cmdutil.findcmd(ui, name, table)
1199 1204 # synopsis
1200 1205 ui.write("%s\n" % i[2])
1201 1206
1202 1207 # aliases
1203 1208 if not ui.quiet and len(aliases) > 1:
1204 1209 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1205 1210
1206 1211 # description
1207 1212 doc = i[0].__doc__
1208 1213 if not doc:
1209 1214 doc = _("(No help text available)")
1210 1215 if ui.quiet:
1211 1216 doc = doc.splitlines(0)[0]
1212 1217 ui.write("\n%s\n" % doc.rstrip())
1213 1218
1214 1219 if not ui.quiet:
1215 1220 # options
1216 1221 if i[1]:
1217 1222 option_lists.append((_("options:\n"), i[1]))
1218 1223
1219 1224 addglobalopts(False)
1220 1225
1221 1226 def helplist(header, select=None):
1222 1227 h = {}
1223 1228 cmds = {}
1224 1229 for c, e in table.items():
1225 1230 f = c.split("|", 1)[0]
1226 1231 if select and not select(f):
1227 1232 continue
1228 1233 if name == "shortlist" and not f.startswith("^"):
1229 1234 continue
1230 1235 f = f.lstrip("^")
1231 1236 if not ui.debugflag and f.startswith("debug"):
1232 1237 continue
1233 1238 doc = e[0].__doc__
1234 1239 if not doc:
1235 1240 doc = _("(No help text available)")
1236 1241 h[f] = doc.splitlines(0)[0].rstrip()
1237 1242 cmds[f] = c.lstrip("^")
1238 1243
1239 1244 if not h:
1240 1245 ui.status(_('no commands defined\n'))
1241 1246 return
1242 1247
1243 1248 ui.status(header)
1244 1249 fns = h.keys()
1245 1250 fns.sort()
1246 1251 m = max(map(len, fns))
1247 1252 for f in fns:
1248 1253 if ui.verbose:
1249 1254 commands = cmds[f].replace("|",", ")
1250 1255 ui.write(" %s:\n %s\n"%(commands, h[f]))
1251 1256 else:
1252 1257 ui.write(' %-*s %s\n' % (m, f, h[f]))
1253 1258
1254 1259 if not ui.quiet:
1255 1260 addglobalopts(True)
1256 1261
1257 1262 def helptopic(name):
1258 1263 v = None
1259 1264 for i in help.helptable:
1260 1265 l = i.split('|')
1261 1266 if name in l:
1262 1267 v = i
1263 1268 header = l[-1]
1264 1269 if not v:
1265 1270 raise cmdutil.UnknownCommand(name)
1266 1271
1267 1272 # description
1268 1273 doc = help.helptable[v]
1269 1274 if not doc:
1270 1275 doc = _("(No help text available)")
1271 1276 if callable(doc):
1272 1277 doc = doc()
1273 1278
1274 1279 ui.write("%s\n" % header)
1275 1280 ui.write("%s\n" % doc.rstrip())
1276 1281
1277 1282 def helpext(name):
1278 1283 try:
1279 1284 mod = extensions.find(name)
1280 1285 except KeyError:
1281 1286 raise cmdutil.UnknownCommand(name)
1282 1287
1283 1288 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1284 1289 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1285 1290 for d in doc[1:]:
1286 1291 ui.write(d, '\n')
1287 1292
1288 1293 ui.status('\n')
1289 1294
1290 1295 try:
1291 1296 ct = mod.cmdtable
1292 1297 except AttributeError:
1293 1298 ct = {}
1294 1299
1295 1300 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1296 1301 helplist(_('list of commands:\n\n'), modcmds.has_key)
1297 1302
1298 1303 if name and name != 'shortlist':
1299 1304 i = None
1300 1305 for f in (helpcmd, helptopic, helpext):
1301 1306 try:
1302 1307 f(name)
1303 1308 i = None
1304 1309 break
1305 1310 except cmdutil.UnknownCommand, inst:
1306 1311 i = inst
1307 1312 if i:
1308 1313 raise i
1309 1314
1310 1315 else:
1311 1316 # program name
1312 1317 if ui.verbose or with_version:
1313 1318 version_(ui)
1314 1319 else:
1315 1320 ui.status(_("Mercurial Distributed SCM\n"))
1316 1321 ui.status('\n')
1317 1322
1318 1323 # list of commands
1319 1324 if name == "shortlist":
1320 1325 header = _('basic commands:\n\n')
1321 1326 else:
1322 1327 header = _('list of commands:\n\n')
1323 1328
1324 1329 helplist(header)
1325 1330
1326 1331 # list all option lists
1327 1332 opt_output = []
1328 1333 for title, options in option_lists:
1329 1334 opt_output.append(("\n%s" % title, None))
1330 1335 for shortopt, longopt, default, desc in options:
1331 1336 if "DEPRECATED" in desc and not ui.verbose: continue
1332 1337 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1333 1338 longopt and " --%s" % longopt),
1334 1339 "%s%s" % (desc,
1335 1340 default
1336 1341 and _(" (default: %s)") % default
1337 1342 or "")))
1338 1343
1339 1344 if opt_output:
1340 1345 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1341 1346 for first, second in opt_output:
1342 1347 if second:
1343 1348 ui.write(" %-*s %s\n" % (opts_len, first, second))
1344 1349 else:
1345 1350 ui.write("%s\n" % first)
1346 1351
1347 1352 def identify(ui, repo, source=None,
1348 1353 rev=None, num=None, id=None, branch=None, tags=None):
1349 1354 """identify the working copy or specified revision
1350 1355
1351 1356 With no revision, print a summary of the current state of the repo.
1352 1357
1353 1358 With a path, do a lookup in another repository.
1354 1359
1355 1360 This summary identifies the repository state using one or two parent
1356 1361 hash identifiers, followed by a "+" if there are uncommitted changes
1357 1362 in the working directory, a list of tags for this revision and a branch
1358 1363 name for non-default branches.
1359 1364 """
1360 1365
1361 1366 if not repo and not source:
1362 1367 raise util.Abort(_("There is no Mercurial repository here "
1363 1368 "(.hg not found)"))
1364 1369
1365 1370 hexfunc = ui.debugflag and hex or short
1366 1371 default = not (num or id or branch or tags)
1367 1372 output = []
1368 1373
1369 1374 if source:
1370 1375 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1371 1376 srepo = hg.repository(ui, source)
1372 1377 if not rev and revs:
1373 1378 rev = revs[0]
1374 1379 if not rev:
1375 1380 rev = "tip"
1376 1381 if num or branch or tags:
1377 1382 raise util.Abort(
1378 1383 "can't query remote revision number, branch, or tags")
1379 1384 output = [hexfunc(srepo.lookup(rev))]
1380 1385 elif not rev:
1381 1386 ctx = repo.workingctx()
1382 1387 parents = ctx.parents()
1383 1388 changed = False
1384 1389 if default or id or num:
1385 1390 changed = ctx.files() + ctx.deleted()
1386 1391 if default or id:
1387 1392 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1388 1393 (changed) and "+" or "")]
1389 1394 if num:
1390 1395 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1391 1396 (changed) and "+" or ""))
1392 1397 else:
1393 1398 ctx = repo.changectx(rev)
1394 1399 if default or id:
1395 1400 output = [hexfunc(ctx.node())]
1396 1401 if num:
1397 1402 output.append(str(ctx.rev()))
1398 1403
1399 1404 if not source and default and not ui.quiet:
1400 1405 b = util.tolocal(ctx.branch())
1401 1406 if b != 'default':
1402 1407 output.append("(%s)" % b)
1403 1408
1404 1409 # multiple tags for a single parent separated by '/'
1405 1410 t = "/".join(ctx.tags())
1406 1411 if t:
1407 1412 output.append(t)
1408 1413
1409 1414 if branch:
1410 1415 output.append(util.tolocal(ctx.branch()))
1411 1416
1412 1417 if tags:
1413 1418 output.extend(ctx.tags())
1414 1419
1415 1420 ui.write("%s\n" % ' '.join(output))
1416 1421
1417 1422 def import_(ui, repo, patch1, *patches, **opts):
1418 1423 """import an ordered set of patches
1419 1424
1420 1425 Import a list of patches and commit them individually.
1421 1426
1422 1427 If there are outstanding changes in the working directory, import
1423 1428 will abort unless given the -f flag.
1424 1429
1425 1430 You can import a patch straight from a mail message. Even patches
1426 1431 as attachments work (body part must be type text/plain or
1427 1432 text/x-patch to be used). From and Subject headers of email
1428 1433 message are used as default committer and commit message. All
1429 1434 text/plain body parts before first diff are added to commit
1430 1435 message.
1431 1436
1432 1437 If the imported patch was generated by hg export, user and description
1433 1438 from patch override values from message headers and body. Values
1434 1439 given on command line with -m and -u override these.
1435 1440
1436 1441 If --exact is specified, import will set the working directory
1437 1442 to the parent of each patch before applying it, and will abort
1438 1443 if the resulting changeset has a different ID than the one
1439 1444 recorded in the patch. This may happen due to character set
1440 1445 problems or other deficiencies in the text patch format.
1441 1446
1442 1447 To read a patch from standard input, use patch name "-".
1448 See 'hg help dates' for a list of formats valid for -d/--date.
1443 1449 """
1444 1450 patches = (patch1,) + patches
1445 1451
1446 1452 date = opts.get('date')
1447 1453 if date:
1448 1454 opts['date'] = util.parsedate(date)
1449 1455
1450 1456 if opts.get('exact') or not opts['force']:
1451 1457 cmdutil.bail_if_changed(repo)
1452 1458
1453 1459 d = opts["base"]
1454 1460 strip = opts["strip"]
1455 1461 wlock = lock = None
1456 1462 try:
1457 1463 wlock = repo.wlock()
1458 1464 lock = repo.lock()
1459 1465 for p in patches:
1460 1466 pf = os.path.join(d, p)
1461 1467
1462 1468 if pf == '-':
1463 1469 ui.status(_("applying patch from stdin\n"))
1464 1470 data = patch.extract(ui, sys.stdin)
1465 1471 else:
1466 1472 ui.status(_("applying %s\n") % p)
1467 1473 if os.path.exists(pf):
1468 1474 data = patch.extract(ui, file(pf, 'rb'))
1469 1475 else:
1470 1476 data = patch.extract(ui, urllib.urlopen(pf))
1471 1477 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1472 1478
1473 1479 if tmpname is None:
1474 1480 raise util.Abort(_('no diffs found'))
1475 1481
1476 1482 try:
1477 1483 cmdline_message = cmdutil.logmessage(opts)
1478 1484 if cmdline_message:
1479 1485 # pickup the cmdline msg
1480 1486 message = cmdline_message
1481 1487 elif message:
1482 1488 # pickup the patch msg
1483 1489 message = message.strip()
1484 1490 else:
1485 1491 # launch the editor
1486 1492 message = None
1487 1493 ui.debug(_('message:\n%s\n') % message)
1488 1494
1489 1495 wp = repo.workingctx().parents()
1490 1496 if opts.get('exact'):
1491 1497 if not nodeid or not p1:
1492 1498 raise util.Abort(_('not a mercurial patch'))
1493 1499 p1 = repo.lookup(p1)
1494 1500 p2 = repo.lookup(p2 or hex(nullid))
1495 1501
1496 1502 if p1 != wp[0].node():
1497 1503 hg.clean(repo, p1)
1498 1504 repo.dirstate.setparents(p1, p2)
1499 1505 elif p2:
1500 1506 try:
1501 1507 p1 = repo.lookup(p1)
1502 1508 p2 = repo.lookup(p2)
1503 1509 if p1 == wp[0].node():
1504 1510 repo.dirstate.setparents(p1, p2)
1505 1511 except hg.RepoError:
1506 1512 pass
1507 1513 if opts.get('exact') or opts.get('import_branch'):
1508 1514 repo.dirstate.setbranch(branch or 'default')
1509 1515
1510 1516 files = {}
1511 1517 try:
1512 1518 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1513 1519 files=files)
1514 1520 finally:
1515 1521 files = patch.updatedir(ui, repo, files)
1516 1522 if not opts.get('no_commit'):
1517 1523 n = repo.commit(files, message, opts.get('user') or user,
1518 1524 opts.get('date') or date)
1519 1525 if opts.get('exact'):
1520 1526 if hex(n) != nodeid:
1521 1527 repo.rollback()
1522 1528 raise util.Abort(_('patch is damaged'
1523 1529 ' or loses information'))
1524 1530 # Force a dirstate write so that the next transaction
1525 1531 # backups an up-do-date file.
1526 1532 repo.dirstate.write()
1527 1533 finally:
1528 1534 os.unlink(tmpname)
1529 1535 finally:
1530 1536 del lock, wlock
1531 1537
1532 1538 def incoming(ui, repo, source="default", **opts):
1533 1539 """show new changesets found in source
1534 1540
1535 1541 Show new changesets found in the specified path/URL or the default
1536 1542 pull location. These are the changesets that would be pulled if a pull
1537 1543 was requested.
1538 1544
1539 1545 For remote repository, using --bundle avoids downloading the changesets
1540 1546 twice if the incoming is followed by a pull.
1541 1547
1542 1548 See pull for valid source format details.
1543 1549 """
1544 1550 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1545 1551 cmdutil.setremoteconfig(ui, opts)
1546 1552
1547 1553 other = hg.repository(ui, source)
1548 1554 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1549 1555 if revs:
1550 1556 revs = [other.lookup(rev) for rev in revs]
1551 1557 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1552 1558 if not incoming:
1553 1559 try:
1554 1560 os.unlink(opts["bundle"])
1555 1561 except:
1556 1562 pass
1557 1563 ui.status(_("no changes found\n"))
1558 1564 return 1
1559 1565
1560 1566 cleanup = None
1561 1567 try:
1562 1568 fname = opts["bundle"]
1563 1569 if fname or not other.local():
1564 1570 # create a bundle (uncompressed if other repo is not local)
1565 1571 if revs is None:
1566 1572 cg = other.changegroup(incoming, "incoming")
1567 1573 else:
1568 1574 cg = other.changegroupsubset(incoming, revs, 'incoming')
1569 1575 bundletype = other.local() and "HG10BZ" or "HG10UN"
1570 1576 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1571 1577 # keep written bundle?
1572 1578 if opts["bundle"]:
1573 1579 cleanup = None
1574 1580 if not other.local():
1575 1581 # use the created uncompressed bundlerepo
1576 1582 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1577 1583
1578 1584 o = other.changelog.nodesbetween(incoming, revs)[0]
1579 1585 if opts['newest_first']:
1580 1586 o.reverse()
1581 1587 displayer = cmdutil.show_changeset(ui, other, opts)
1582 1588 for n in o:
1583 1589 parents = [p for p in other.changelog.parents(n) if p != nullid]
1584 1590 if opts['no_merges'] and len(parents) == 2:
1585 1591 continue
1586 1592 displayer.show(changenode=n)
1587 1593 finally:
1588 1594 if hasattr(other, 'close'):
1589 1595 other.close()
1590 1596 if cleanup:
1591 1597 os.unlink(cleanup)
1592 1598
1593 1599 def init(ui, dest=".", **opts):
1594 1600 """create a new repository in the given directory
1595 1601
1596 1602 Initialize a new repository in the given directory. If the given
1597 1603 directory does not exist, it is created.
1598 1604
1599 1605 If no directory is given, the current directory is used.
1600 1606
1601 1607 It is possible to specify an ssh:// URL as the destination.
1602 1608 Look at the help text for the pull command for important details
1603 1609 about ssh:// URLs.
1604 1610 """
1605 1611 cmdutil.setremoteconfig(ui, opts)
1606 1612 hg.repository(ui, dest, create=1)
1607 1613
1608 1614 def locate(ui, repo, *pats, **opts):
1609 1615 """locate files matching specific patterns
1610 1616
1611 1617 Print all files under Mercurial control whose names match the
1612 1618 given patterns.
1613 1619
1614 1620 This command searches the entire repository by default. To search
1615 1621 just the current directory and its subdirectories, use
1616 1622 "--include .".
1617 1623
1618 1624 If no patterns are given to match, this command prints all file
1619 1625 names.
1620 1626
1621 1627 If you want to feed the output of this command into the "xargs"
1622 1628 command, use the "-0" option to both this command and "xargs".
1623 1629 This will avoid the problem of "xargs" treating single filenames
1624 1630 that contain white space as multiple filenames.
1625 1631 """
1626 1632 end = opts['print0'] and '\0' or '\n'
1627 1633 rev = opts['rev']
1628 1634 if rev:
1629 1635 node = repo.lookup(rev)
1630 1636 else:
1631 1637 node = None
1632 1638
1633 1639 ret = 1
1634 1640 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1635 1641 badmatch=util.always,
1636 1642 default='relglob'):
1637 1643 if src == 'b':
1638 1644 continue
1639 1645 if not node and abs not in repo.dirstate:
1640 1646 continue
1641 1647 if opts['fullpath']:
1642 1648 ui.write(os.path.join(repo.root, abs), end)
1643 1649 else:
1644 1650 ui.write(((pats and rel) or abs), end)
1645 1651 ret = 0
1646 1652
1647 1653 return ret
1648 1654
1649 1655 def log(ui, repo, *pats, **opts):
1650 1656 """show revision history of entire repository or files
1651 1657
1652 1658 Print the revision history of the specified files or the entire
1653 1659 project.
1654 1660
1655 1661 File history is shown without following rename or copy history of
1656 1662 files. Use -f/--follow with a file name to follow history across
1657 1663 renames and copies. --follow without a file name will only show
1658 1664 ancestors or descendants of the starting revision. --follow-first
1659 1665 only follows the first parent of merge revisions.
1660 1666
1661 1667 If no revision range is specified, the default is tip:0 unless
1662 1668 --follow is set, in which case the working directory parent is
1663 1669 used as the starting revision.
1664 1670
1671 See 'hg help dates' for a list of formats valid for -d/--date.
1672
1665 1673 By default this command outputs: changeset id and hash, tags,
1666 1674 non-trivial parents, user, date and time, and a summary for each
1667 1675 commit. When the -v/--verbose switch is used, the list of changed
1668 1676 files and full commit message is shown.
1669 1677
1670 1678 NOTE: log -p may generate unexpected diff output for merge
1671 1679 changesets, as it will compare the merge changeset against its
1672 1680 first parent only. Also, the files: list will only reflect files
1673 1681 that are different from BOTH parents.
1674 1682
1675 1683 """
1676 1684
1677 1685 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1678 1686 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1679 1687
1680 1688 if opts['limit']:
1681 1689 try:
1682 1690 limit = int(opts['limit'])
1683 1691 except ValueError:
1684 1692 raise util.Abort(_('limit must be a positive integer'))
1685 1693 if limit <= 0: raise util.Abort(_('limit must be positive'))
1686 1694 else:
1687 1695 limit = sys.maxint
1688 1696 count = 0
1689 1697
1690 1698 if opts['copies'] and opts['rev']:
1691 1699 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1692 1700 else:
1693 1701 endrev = repo.changelog.count()
1694 1702 rcache = {}
1695 1703 ncache = {}
1696 1704 def getrenamed(fn, rev):
1697 1705 '''looks up all renames for a file (up to endrev) the first
1698 1706 time the file is given. It indexes on the changerev and only
1699 1707 parses the manifest if linkrev != changerev.
1700 1708 Returns rename info for fn at changerev rev.'''
1701 1709 if fn not in rcache:
1702 1710 rcache[fn] = {}
1703 1711 ncache[fn] = {}
1704 1712 fl = repo.file(fn)
1705 1713 for i in xrange(fl.count()):
1706 1714 node = fl.node(i)
1707 1715 lr = fl.linkrev(node)
1708 1716 renamed = fl.renamed(node)
1709 1717 rcache[fn][lr] = renamed
1710 1718 if renamed:
1711 1719 ncache[fn][node] = renamed
1712 1720 if lr >= endrev:
1713 1721 break
1714 1722 if rev in rcache[fn]:
1715 1723 return rcache[fn][rev]
1716 1724
1717 1725 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1718 1726 # filectx logic.
1719 1727
1720 1728 try:
1721 1729 return repo.changectx(rev).filectx(fn).renamed()
1722 1730 except revlog.LookupError:
1723 1731 pass
1724 1732 return None
1725 1733
1726 1734 df = False
1727 1735 if opts["date"]:
1728 1736 df = util.matchdate(opts["date"])
1729 1737
1730 1738 only_branches = opts['only_branch']
1731 1739
1732 1740 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1733 1741 for st, rev, fns in changeiter:
1734 1742 if st == 'add':
1735 1743 changenode = repo.changelog.node(rev)
1736 1744 parents = [p for p in repo.changelog.parentrevs(rev)
1737 1745 if p != nullrev]
1738 1746 if opts['no_merges'] and len(parents) == 2:
1739 1747 continue
1740 1748 if opts['only_merges'] and len(parents) != 2:
1741 1749 continue
1742 1750
1743 1751 if only_branches:
1744 1752 revbranch = get(rev)[5]['branch']
1745 1753 if revbranch not in only_branches:
1746 1754 continue
1747 1755
1748 1756 if df:
1749 1757 changes = get(rev)
1750 1758 if not df(changes[2][0]):
1751 1759 continue
1752 1760
1753 1761 if opts['keyword']:
1754 1762 changes = get(rev)
1755 1763 miss = 0
1756 1764 for k in [kw.lower() for kw in opts['keyword']]:
1757 1765 if not (k in changes[1].lower() or
1758 1766 k in changes[4].lower() or
1759 1767 k in " ".join(changes[3]).lower()):
1760 1768 miss = 1
1761 1769 break
1762 1770 if miss:
1763 1771 continue
1764 1772
1765 1773 copies = []
1766 1774 if opts.get('copies') and rev:
1767 1775 for fn in get(rev)[3]:
1768 1776 rename = getrenamed(fn, rev)
1769 1777 if rename:
1770 1778 copies.append((fn, rename[0]))
1771 1779 displayer.show(rev, changenode, copies=copies)
1772 1780 elif st == 'iter':
1773 1781 if count == limit: break
1774 1782 if displayer.flush(rev):
1775 1783 count += 1
1776 1784
1777 1785 def manifest(ui, repo, node=None, rev=None):
1778 1786 """output the current or given revision of the project manifest
1779 1787
1780 1788 Print a list of version controlled files for the given revision.
1781 1789 If no revision is given, the parent of the working directory is used,
1782 1790 or tip if no revision is checked out.
1783 1791
1784 1792 The manifest is the list of files being version controlled. If no revision
1785 1793 is given then the first parent of the working directory is used.
1786 1794
1787 1795 With -v flag, print file permissions, symlink and executable bits. With
1788 1796 --debug flag, print file revision hashes.
1789 1797 """
1790 1798
1791 1799 if rev and node:
1792 1800 raise util.Abort(_("please specify just one revision"))
1793 1801
1794 1802 if not node:
1795 1803 node = rev
1796 1804
1797 1805 m = repo.changectx(node).manifest()
1798 1806 files = m.keys()
1799 1807 files.sort()
1800 1808
1801 1809 for f in files:
1802 1810 if ui.debugflag:
1803 1811 ui.write("%40s " % hex(m[f]))
1804 1812 if ui.verbose:
1805 1813 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1806 1814 perm = m.execf(f) and "755" or "644"
1807 1815 ui.write("%3s %1s " % (perm, type))
1808 1816 ui.write("%s\n" % f)
1809 1817
1810 1818 def merge(ui, repo, node=None, force=None, rev=None):
1811 1819 """merge working directory with another revision
1812 1820
1813 1821 Merge the contents of the current working directory and the
1814 1822 requested revision. Files that changed between either parent are
1815 1823 marked as changed for the next commit and a commit must be
1816 1824 performed before any further updates are allowed.
1817 1825
1818 1826 If no revision is specified, the working directory's parent is a
1819 1827 head revision, and the repository contains exactly one other head,
1820 1828 the other head is merged with by default. Otherwise, an explicit
1821 1829 revision to merge with must be provided.
1822 1830 """
1823 1831
1824 1832 if rev and node:
1825 1833 raise util.Abort(_("please specify just one revision"))
1826 1834 if not node:
1827 1835 node = rev
1828 1836
1829 1837 if not node:
1830 1838 heads = repo.heads()
1831 1839 if len(heads) > 2:
1832 1840 raise util.Abort(_('repo has %d heads - '
1833 1841 'please merge with an explicit rev') %
1834 1842 len(heads))
1835 1843 parent = repo.dirstate.parents()[0]
1836 1844 if len(heads) == 1:
1837 1845 msg = _('there is nothing to merge')
1838 1846 if parent != repo.lookup(repo.workingctx().branch()):
1839 1847 msg = _('%s - use "hg update" instead') % msg
1840 1848 raise util.Abort(msg)
1841 1849
1842 1850 if parent not in heads:
1843 1851 raise util.Abort(_('working dir not at a head rev - '
1844 1852 'use "hg update" or merge with an explicit rev'))
1845 1853 node = parent == heads[0] and heads[-1] or heads[0]
1846 1854 return hg.merge(repo, node, force=force)
1847 1855
1848 1856 def outgoing(ui, repo, dest=None, **opts):
1849 1857 """show changesets not found in destination
1850 1858
1851 1859 Show changesets not found in the specified destination repository or
1852 1860 the default push location. These are the changesets that would be pushed
1853 1861 if a push was requested.
1854 1862
1855 1863 See pull for valid destination format details.
1856 1864 """
1857 1865 dest, revs, checkout = hg.parseurl(
1858 1866 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1859 1867 cmdutil.setremoteconfig(ui, opts)
1860 1868 if revs:
1861 1869 revs = [repo.lookup(rev) for rev in revs]
1862 1870
1863 1871 other = hg.repository(ui, dest)
1864 1872 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1865 1873 o = repo.findoutgoing(other, force=opts['force'])
1866 1874 if not o:
1867 1875 ui.status(_("no changes found\n"))
1868 1876 return 1
1869 1877 o = repo.changelog.nodesbetween(o, revs)[0]
1870 1878 if opts['newest_first']:
1871 1879 o.reverse()
1872 1880 displayer = cmdutil.show_changeset(ui, repo, opts)
1873 1881 for n in o:
1874 1882 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1875 1883 if opts['no_merges'] and len(parents) == 2:
1876 1884 continue
1877 1885 displayer.show(changenode=n)
1878 1886
1879 1887 def parents(ui, repo, file_=None, **opts):
1880 1888 """show the parents of the working dir or revision
1881 1889
1882 1890 Print the working directory's parent revisions. If a
1883 1891 revision is given via --rev, the parent of that revision
1884 1892 will be printed. If a file argument is given, revision in
1885 1893 which the file was last changed (before the working directory
1886 1894 revision or the argument to --rev if given) is printed.
1887 1895 """
1888 1896 rev = opts.get('rev')
1889 1897 if rev:
1890 1898 ctx = repo.changectx(rev)
1891 1899 else:
1892 1900 ctx = repo.workingctx()
1893 1901
1894 1902 if file_:
1895 1903 files, match, anypats = cmdutil.matchpats(repo, (file_,), opts)
1896 1904 if anypats or len(files) != 1:
1897 1905 raise util.Abort(_('can only specify an explicit file name'))
1898 1906 file_ = files[0]
1899 1907 filenodes = []
1900 1908 for cp in ctx.parents():
1901 1909 if not cp:
1902 1910 continue
1903 1911 try:
1904 1912 filenodes.append(cp.filenode(file_))
1905 1913 except revlog.LookupError:
1906 1914 pass
1907 1915 if not filenodes:
1908 1916 raise util.Abort(_("'%s' not found in manifest!") % file_)
1909 1917 fl = repo.file(file_)
1910 1918 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1911 1919 else:
1912 1920 p = [cp.node() for cp in ctx.parents()]
1913 1921
1914 1922 displayer = cmdutil.show_changeset(ui, repo, opts)
1915 1923 for n in p:
1916 1924 if n != nullid:
1917 1925 displayer.show(changenode=n)
1918 1926
1919 1927 def paths(ui, repo, search=None):
1920 1928 """show definition of symbolic path names
1921 1929
1922 1930 Show definition of symbolic path name NAME. If no name is given, show
1923 1931 definition of available names.
1924 1932
1925 1933 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1926 1934 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1927 1935 """
1928 1936 if search:
1929 1937 for name, path in ui.configitems("paths"):
1930 1938 if name == search:
1931 1939 ui.write("%s\n" % path)
1932 1940 return
1933 1941 ui.warn(_("not found!\n"))
1934 1942 return 1
1935 1943 else:
1936 1944 for name, path in ui.configitems("paths"):
1937 1945 ui.write("%s = %s\n" % (name, path))
1938 1946
1939 1947 def postincoming(ui, repo, modheads, optupdate, checkout):
1940 1948 if modheads == 0:
1941 1949 return
1942 1950 if optupdate:
1943 1951 if modheads <= 1 or checkout:
1944 1952 return hg.update(repo, checkout)
1945 1953 else:
1946 1954 ui.status(_("not updating, since new heads added\n"))
1947 1955 if modheads > 1:
1948 1956 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1949 1957 else:
1950 1958 ui.status(_("(run 'hg update' to get a working copy)\n"))
1951 1959
1952 1960 def pull(ui, repo, source="default", **opts):
1953 1961 """pull changes from the specified source
1954 1962
1955 1963 Pull changes from a remote repository to a local one.
1956 1964
1957 1965 This finds all changes from the repository at the specified path
1958 1966 or URL and adds them to the local repository. By default, this
1959 1967 does not update the copy of the project in the working directory.
1960 1968
1961 1969 Valid URLs are of the form:
1962 1970
1963 1971 local/filesystem/path (or file://local/filesystem/path)
1964 1972 http://[user@]host[:port]/[path]
1965 1973 https://[user@]host[:port]/[path]
1966 1974 ssh://[user@]host[:port]/[path]
1967 1975 static-http://host[:port]/[path]
1968 1976
1969 1977 Paths in the local filesystem can either point to Mercurial
1970 1978 repositories or to bundle files (as created by 'hg bundle' or
1971 1979 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1972 1980 allows access to a Mercurial repository where you simply use a web
1973 1981 server to publish the .hg directory as static content.
1974 1982
1975 1983 An optional identifier after # indicates a particular branch, tag,
1976 1984 or changeset to pull.
1977 1985
1978 1986 Some notes about using SSH with Mercurial:
1979 1987 - SSH requires an accessible shell account on the destination machine
1980 1988 and a copy of hg in the remote path or specified with as remotecmd.
1981 1989 - path is relative to the remote user's home directory by default.
1982 1990 Use an extra slash at the start of a path to specify an absolute path:
1983 1991 ssh://example.com//tmp/repository
1984 1992 - Mercurial doesn't use its own compression via SSH; the right thing
1985 1993 to do is to configure it in your ~/.ssh/config, e.g.:
1986 1994 Host *.mylocalnetwork.example.com
1987 1995 Compression no
1988 1996 Host *
1989 1997 Compression yes
1990 1998 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1991 1999 with the --ssh command line option.
1992 2000 """
1993 2001 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1994 2002 cmdutil.setremoteconfig(ui, opts)
1995 2003
1996 2004 other = hg.repository(ui, source)
1997 2005 ui.status(_('pulling from %s\n') % util.hidepassword(source))
1998 2006 if revs:
1999 2007 try:
2000 2008 revs = [other.lookup(rev) for rev in revs]
2001 2009 except repo.NoCapability:
2002 2010 error = _("Other repository doesn't support revision lookup, "
2003 2011 "so a rev cannot be specified.")
2004 2012 raise util.Abort(error)
2005 2013
2006 2014 modheads = repo.pull(other, heads=revs, force=opts['force'])
2007 2015 return postincoming(ui, repo, modheads, opts['update'], checkout)
2008 2016
2009 2017 def push(ui, repo, dest=None, **opts):
2010 2018 """push changes to the specified destination
2011 2019
2012 2020 Push changes from the local repository to the given destination.
2013 2021
2014 2022 This is the symmetrical operation for pull. It helps to move
2015 2023 changes from the current repository to a different one. If the
2016 2024 destination is local this is identical to a pull in that directory
2017 2025 from the current one.
2018 2026
2019 2027 By default, push will refuse to run if it detects the result would
2020 2028 increase the number of remote heads. This generally indicates the
2021 2029 the client has forgotten to sync and merge before pushing.
2022 2030
2023 2031 Valid URLs are of the form:
2024 2032
2025 2033 local/filesystem/path (or file://local/filesystem/path)
2026 2034 ssh://[user@]host[:port]/[path]
2027 2035 http://[user@]host[:port]/[path]
2028 2036 https://[user@]host[:port]/[path]
2029 2037
2030 2038 An optional identifier after # indicates a particular branch, tag,
2031 2039 or changeset to push.
2032 2040
2033 2041 Look at the help text for the pull command for important details
2034 2042 about ssh:// URLs.
2035 2043
2036 2044 Pushing to http:// and https:// URLs is only possible, if this
2037 2045 feature is explicitly enabled on the remote Mercurial server.
2038 2046 """
2039 2047 dest, revs, checkout = hg.parseurl(
2040 2048 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2041 2049 cmdutil.setremoteconfig(ui, opts)
2042 2050
2043 2051 other = hg.repository(ui, dest)
2044 2052 ui.status('pushing to %s\n' % util.hidepassword(dest))
2045 2053 if revs:
2046 2054 revs = [repo.lookup(rev) for rev in revs]
2047 2055 r = repo.push(other, opts['force'], revs=revs)
2048 2056 return r == 0
2049 2057
2050 2058 def rawcommit(ui, repo, *pats, **opts):
2051 2059 """raw commit interface (DEPRECATED)
2052 2060
2053 2061 (DEPRECATED)
2054 2062 Lowlevel commit, for use in helper scripts.
2055 2063
2056 2064 This command is not intended to be used by normal users, as it is
2057 2065 primarily useful for importing from other SCMs.
2058 2066
2059 2067 This command is now deprecated and will be removed in a future
2060 2068 release, please use debugsetparents and commit instead.
2061 2069 """
2062 2070
2063 2071 ui.warn(_("(the rawcommit command is deprecated)\n"))
2064 2072
2065 2073 message = cmdutil.logmessage(opts)
2066 2074
2067 2075 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
2068 2076 if opts['files']:
2069 2077 files += open(opts['files']).read().splitlines()
2070 2078
2071 2079 parents = [repo.lookup(p) for p in opts['parent']]
2072 2080
2073 2081 try:
2074 2082 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2075 2083 except ValueError, inst:
2076 2084 raise util.Abort(str(inst))
2077 2085
2078 2086 def recover(ui, repo):
2079 2087 """roll back an interrupted transaction
2080 2088
2081 2089 Recover from an interrupted commit or pull.
2082 2090
2083 2091 This command tries to fix the repository status after an interrupted
2084 2092 operation. It should only be necessary when Mercurial suggests it.
2085 2093 """
2086 2094 if repo.recover():
2087 2095 return hg.verify(repo)
2088 2096 return 1
2089 2097
2090 2098 def remove(ui, repo, *pats, **opts):
2091 2099 """remove the specified files on the next commit
2092 2100
2093 2101 Schedule the indicated files for removal from the repository.
2094 2102
2095 2103 This only removes files from the current branch, not from the
2096 2104 entire project history. If the files still exist in the working
2097 2105 directory, they will be deleted from it. If invoked with --after,
2098 2106 files are marked as removed, but not actually unlinked unless --force
2099 2107 is also given. Without exact file names, --after will only mark
2100 2108 files as removed if they are no longer in the working directory.
2101 2109
2102 2110 This command schedules the files to be removed at the next commit.
2103 2111 To undo a remove before that, see hg revert.
2104 2112
2105 2113 Modified files and added files are not removed by default. To
2106 2114 remove them, use the -f/--force option.
2107 2115 """
2108 2116 if not opts['after'] and not pats:
2109 2117 raise util.Abort(_('no files specified'))
2110 2118 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2111 2119 exact = dict.fromkeys(files)
2112 2120 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2113 2121 modified, added, removed, deleted, unknown = mardu
2114 2122 remove, forget = [], []
2115 2123 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2116 2124 reason = None
2117 2125 if abs in modified and not opts['force']:
2118 2126 reason = _('is modified (use -f to force removal)')
2119 2127 elif abs in added:
2120 2128 if opts['force']:
2121 2129 forget.append(abs)
2122 2130 continue
2123 2131 reason = _('has been marked for add (use -f to force removal)')
2124 2132 exact = 1 # force the message
2125 2133 elif abs not in repo.dirstate:
2126 2134 reason = _('is not managed')
2127 2135 elif opts['after'] and not exact and abs not in deleted:
2128 2136 continue
2129 2137 elif abs in removed:
2130 2138 continue
2131 2139 if reason:
2132 2140 if exact:
2133 2141 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2134 2142 else:
2135 2143 if ui.verbose or not exact:
2136 2144 ui.status(_('removing %s\n') % rel)
2137 2145 remove.append(abs)
2138 2146 repo.forget(forget)
2139 2147 repo.remove(remove, unlink=opts['force'] or not opts['after'])
2140 2148
2141 2149 def rename(ui, repo, *pats, **opts):
2142 2150 """rename files; equivalent of copy + remove
2143 2151
2144 2152 Mark dest as copies of sources; mark sources for deletion. If
2145 2153 dest is a directory, copies are put in that directory. If dest is
2146 2154 a file, there can only be one source.
2147 2155
2148 2156 By default, this command copies the contents of files as they
2149 2157 stand in the working directory. If invoked with --after, the
2150 2158 operation is recorded, but no copying is performed.
2151 2159
2152 2160 This command takes effect in the next commit. To undo a rename
2153 2161 before that, see hg revert.
2154 2162 """
2155 2163 wlock = repo.wlock(False)
2156 2164 try:
2157 2165 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2158 2166 finally:
2159 2167 del wlock
2160 2168
2161 2169 def revert(ui, repo, *pats, **opts):
2162 2170 """restore individual files or dirs to an earlier state
2163 2171
2164 2172 (use update -r to check out earlier revisions, revert does not
2165 2173 change the working dir parents)
2166 2174
2167 2175 With no revision specified, revert the named files or directories
2168 2176 to the contents they had in the parent of the working directory.
2169 2177 This restores the contents of the affected files to an unmodified
2170 2178 state and unschedules adds, removes, copies, and renames. If the
2171 2179 working directory has two parents, you must explicitly specify the
2172 2180 revision to revert to.
2173 2181
2174 2182 Using the -r option, revert the given files or directories to their
2175 2183 contents as of a specific revision. This can be helpful to "roll
2176 back" some or all of an earlier change.
2184 back" some or all of an earlier change.
2185 See 'hg help dates' for a list of formats valid for -d/--date.
2177 2186
2178 2187 Revert modifies the working directory. It does not commit any
2179 2188 changes, or change the parent of the working directory. If you
2180 2189 revert to a revision other than the parent of the working
2181 2190 directory, the reverted files will thus appear modified
2182 2191 afterwards.
2183 2192
2184 2193 If a file has been deleted, it is restored. If the executable
2185 2194 mode of a file was changed, it is reset.
2186 2195
2187 2196 If names are given, all files matching the names are reverted.
2188
2189 2197 If no arguments are given, no files are reverted.
2190 2198
2191 2199 Modified files are saved with a .orig suffix before reverting.
2192 2200 To disable these backups, use --no-backup.
2193 2201 """
2194 2202
2195 2203 if opts["date"]:
2196 2204 if opts["rev"]:
2197 2205 raise util.Abort(_("you can't specify a revision and a date"))
2198 2206 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2199 2207
2200 2208 if not pats and not opts['all']:
2201 2209 raise util.Abort(_('no files or directories specified; '
2202 2210 'use --all to revert the whole repo'))
2203 2211
2204 2212 parent, p2 = repo.dirstate.parents()
2205 2213 if not opts['rev'] and p2 != nullid:
2206 2214 raise util.Abort(_('uncommitted merge - please provide a '
2207 2215 'specific revision'))
2208 2216 ctx = repo.changectx(opts['rev'])
2209 2217 node = ctx.node()
2210 2218 mf = ctx.manifest()
2211 2219 if node == parent:
2212 2220 pmf = mf
2213 2221 else:
2214 2222 pmf = None
2215 2223
2216 2224 # need all matching names in dirstate and manifest of target rev,
2217 2225 # so have to walk both. do not print errors if files exist in one
2218 2226 # but not other.
2219 2227
2220 2228 names = {}
2221 2229
2222 2230 wlock = repo.wlock()
2223 2231 try:
2224 2232 # walk dirstate.
2225 2233 files = []
2226 2234 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2227 2235 badmatch=mf.has_key):
2228 2236 names[abs] = (rel, exact)
2229 2237 if src != 'b':
2230 2238 files.append(abs)
2231 2239
2232 2240 # walk target manifest.
2233 2241
2234 2242 def badmatch(path):
2235 2243 if path in names:
2236 2244 return True
2237 2245 path_ = path + '/'
2238 2246 for f in names:
2239 2247 if f.startswith(path_):
2240 2248 return True
2241 2249 return False
2242 2250
2243 2251 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2244 2252 badmatch=badmatch):
2245 2253 if abs in names or src == 'b':
2246 2254 continue
2247 2255 names[abs] = (rel, exact)
2248 2256
2249 2257 changes = repo.status(files=files, match=names.has_key)[:4]
2250 2258 modified, added, removed, deleted = map(dict.fromkeys, changes)
2251 2259
2252 2260 # if f is a rename, also revert the source
2253 2261 cwd = repo.getcwd()
2254 2262 for f in added:
2255 2263 src = repo.dirstate.copied(f)
2256 2264 if src and src not in names and repo.dirstate[src] == 'r':
2257 2265 removed[src] = None
2258 2266 names[src] = (repo.pathto(src, cwd), True)
2259 2267
2260 2268 def removeforget(abs):
2261 2269 if repo.dirstate[abs] == 'a':
2262 2270 return _('forgetting %s\n')
2263 2271 return _('removing %s\n')
2264 2272
2265 2273 revert = ([], _('reverting %s\n'))
2266 2274 add = ([], _('adding %s\n'))
2267 2275 remove = ([], removeforget)
2268 2276 undelete = ([], _('undeleting %s\n'))
2269 2277
2270 2278 disptable = (
2271 2279 # dispatch table:
2272 2280 # file state
2273 2281 # action if in target manifest
2274 2282 # action if not in target manifest
2275 2283 # make backup if in target manifest
2276 2284 # make backup if not in target manifest
2277 2285 (modified, revert, remove, True, True),
2278 2286 (added, revert, remove, True, False),
2279 2287 (removed, undelete, None, False, False),
2280 2288 (deleted, revert, remove, False, False),
2281 2289 )
2282 2290
2283 2291 entries = names.items()
2284 2292 entries.sort()
2285 2293
2286 2294 for abs, (rel, exact) in entries:
2287 2295 mfentry = mf.get(abs)
2288 2296 target = repo.wjoin(abs)
2289 2297 def handle(xlist, dobackup):
2290 2298 xlist[0].append(abs)
2291 2299 if dobackup and not opts['no_backup'] and util.lexists(target):
2292 2300 bakname = "%s.orig" % rel
2293 2301 ui.note(_('saving current version of %s as %s\n') %
2294 2302 (rel, bakname))
2295 2303 if not opts.get('dry_run'):
2296 2304 util.copyfile(target, bakname)
2297 2305 if ui.verbose or not exact:
2298 2306 msg = xlist[1]
2299 2307 if not isinstance(msg, basestring):
2300 2308 msg = msg(abs)
2301 2309 ui.status(msg % rel)
2302 2310 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2303 2311 if abs not in table: continue
2304 2312 # file has changed in dirstate
2305 2313 if mfentry:
2306 2314 handle(hitlist, backuphit)
2307 2315 elif misslist is not None:
2308 2316 handle(misslist, backupmiss)
2309 2317 break
2310 2318 else:
2311 2319 if abs not in repo.dirstate:
2312 2320 if mfentry:
2313 2321 handle(add, True)
2314 2322 elif exact:
2315 2323 ui.warn(_('file not managed: %s\n') % rel)
2316 2324 continue
2317 2325 # file has not changed in dirstate
2318 2326 if node == parent:
2319 2327 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2320 2328 continue
2321 2329 if pmf is None:
2322 2330 # only need parent manifest in this unlikely case,
2323 2331 # so do not read by default
2324 2332 pmf = repo.changectx(parent).manifest()
2325 2333 if abs in pmf:
2326 2334 if mfentry:
2327 2335 # if version of file is same in parent and target
2328 2336 # manifests, do nothing
2329 2337 if (pmf[abs] != mfentry or
2330 2338 pmf.flags(abs) != mf.flags(abs)):
2331 2339 handle(revert, False)
2332 2340 else:
2333 2341 handle(remove, False)
2334 2342
2335 2343 if not opts.get('dry_run'):
2336 2344 def checkout(f):
2337 2345 fc = ctx[f]
2338 2346 repo.wwrite(f, fc.data(), fc.fileflags())
2339 2347
2340 2348 audit_path = util.path_auditor(repo.root)
2341 2349 for f in remove[0]:
2342 2350 if repo.dirstate[f] == 'a':
2343 2351 repo.dirstate.forget(f)
2344 2352 continue
2345 2353 audit_path(f)
2346 2354 try:
2347 2355 util.unlink(repo.wjoin(f))
2348 2356 except OSError:
2349 2357 pass
2350 2358 repo.dirstate.remove(f)
2351 2359
2352 2360 for f in revert[0]:
2353 2361 checkout(f)
2354 2362
2355 2363 for f in add[0]:
2356 2364 checkout(f)
2357 2365 repo.dirstate.add(f)
2358 2366
2359 2367 normal = repo.dirstate.normallookup
2360 2368 if node == parent and p2 == nullid:
2361 2369 normal = repo.dirstate.normal
2362 2370 for f in undelete[0]:
2363 2371 checkout(f)
2364 2372 normal(f)
2365 2373
2366 2374 finally:
2367 2375 del wlock
2368 2376
2369 2377 def rollback(ui, repo):
2370 2378 """roll back the last transaction
2371 2379
2372 2380 This command should be used with care. There is only one level of
2373 2381 rollback, and there is no way to undo a rollback. It will also
2374 2382 restore the dirstate at the time of the last transaction, losing
2375 2383 any dirstate changes since that time.
2376 2384
2377 2385 Transactions are used to encapsulate the effects of all commands
2378 2386 that create new changesets or propagate existing changesets into a
2379 2387 repository. For example, the following commands are transactional,
2380 2388 and their effects can be rolled back:
2381 2389
2382 2390 commit
2383 2391 import
2384 2392 pull
2385 2393 push (with this repository as destination)
2386 2394 unbundle
2387 2395
2388 2396 This command is not intended for use on public repositories. Once
2389 2397 changes are visible for pull by other users, rolling a transaction
2390 2398 back locally is ineffective (someone else may already have pulled
2391 2399 the changes). Furthermore, a race is possible with readers of the
2392 2400 repository; for example an in-progress pull from the repository
2393 2401 may fail if a rollback is performed.
2394 2402 """
2395 2403 repo.rollback()
2396 2404
2397 2405 def root(ui, repo):
2398 2406 """print the root (top) of the current working dir
2399 2407
2400 2408 Print the root directory of the current repository.
2401 2409 """
2402 2410 ui.write(repo.root + "\n")
2403 2411
2404 2412 def serve(ui, repo, **opts):
2405 2413 """export the repository via HTTP
2406 2414
2407 2415 Start a local HTTP repository browser and pull server.
2408 2416
2409 2417 By default, the server logs accesses to stdout and errors to
2410 2418 stderr. Use the "-A" and "-E" options to log to files.
2411 2419 """
2412 2420
2413 2421 if opts["stdio"]:
2414 2422 if repo is None:
2415 2423 raise hg.RepoError(_("There is no Mercurial repository here"
2416 2424 " (.hg not found)"))
2417 2425 s = sshserver.sshserver(ui, repo)
2418 2426 s.serve_forever()
2419 2427
2420 2428 parentui = ui.parentui or ui
2421 2429 optlist = ("name templates style address port prefix ipv6"
2422 2430 " accesslog errorlog webdir_conf certificate")
2423 2431 for o in optlist.split():
2424 2432 if opts[o]:
2425 2433 parentui.setconfig("web", o, str(opts[o]))
2426 2434 if (repo is not None) and (repo.ui != parentui):
2427 2435 repo.ui.setconfig("web", o, str(opts[o]))
2428 2436
2429 2437 if repo is None and not ui.config("web", "webdir_conf"):
2430 2438 raise hg.RepoError(_("There is no Mercurial repository here"
2431 2439 " (.hg not found)"))
2432 2440
2433 2441 class service:
2434 2442 def init(self):
2435 2443 util.set_signal_handler()
2436 2444 try:
2437 2445 self.httpd = hgweb.server.create_server(parentui, repo)
2438 2446 except socket.error, inst:
2439 2447 raise util.Abort(_('cannot start server: ') + inst.args[1])
2440 2448
2441 2449 if not ui.verbose: return
2442 2450
2443 2451 if self.httpd.prefix:
2444 2452 prefix = self.httpd.prefix.strip('/') + '/'
2445 2453 else:
2446 2454 prefix = ''
2447 2455
2448 2456 if self.httpd.port != 80:
2449 2457 ui.status(_('listening at http://%s:%d/%s\n') %
2450 2458 (self.httpd.addr, self.httpd.port, prefix))
2451 2459 else:
2452 2460 ui.status(_('listening at http://%s/%s\n') %
2453 2461 (self.httpd.addr, prefix))
2454 2462
2455 2463 def run(self):
2456 2464 self.httpd.serve_forever()
2457 2465
2458 2466 service = service()
2459 2467
2460 2468 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2461 2469
2462 2470 def status(ui, repo, *pats, **opts):
2463 2471 """show changed files in the working directory
2464 2472
2465 2473 Show status of files in the repository. If names are given, only
2466 2474 files that match are shown. Files that are clean or ignored or
2467 2475 source of a copy/move operation, are not listed unless -c (clean),
2468 2476 -i (ignored), -C (copies) or -A is given. Unless options described
2469 2477 with "show only ..." are given, the options -mardu are used.
2470 2478
2471 2479 NOTE: status may appear to disagree with diff if permissions have
2472 2480 changed or a merge has occurred. The standard diff format does not
2473 2481 report permission changes and diff only reports changes relative
2474 2482 to one merge parent.
2475 2483
2476 2484 If one revision is given, it is used as the base revision.
2477 2485 If two revisions are given, the difference between them is shown.
2478 2486
2479 2487 The codes used to show the status of files are:
2480 2488 M = modified
2481 2489 A = added
2482 2490 R = removed
2483 2491 C = clean
2484 2492 ! = deleted, but still tracked
2485 2493 ? = not tracked
2486 2494 I = ignored
2487 2495 = the previous added file was copied from here
2488 2496 """
2489 2497
2490 2498 all = opts['all']
2491 2499 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2492 2500
2493 2501 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2494 2502 cwd = (pats and repo.getcwd()) or ''
2495 2503 modified, added, removed, deleted, unknown, ignored, clean = [
2496 2504 n for n in repo.status(node1=node1, node2=node2, files=files,
2497 2505 match=matchfn,
2498 2506 list_ignored=all or opts['ignored'],
2499 2507 list_clean=all or opts['clean'])]
2500 2508
2501 2509 changetypes = (('modified', 'M', modified),
2502 2510 ('added', 'A', added),
2503 2511 ('removed', 'R', removed),
2504 2512 ('deleted', '!', deleted),
2505 2513 ('unknown', '?', unknown),
2506 2514 ('ignored', 'I', ignored))
2507 2515
2508 2516 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2509 2517
2510 2518 end = opts['print0'] and '\0' or '\n'
2511 2519
2512 2520 for opt, char, changes in ([ct for ct in explicit_changetypes
2513 2521 if all or opts[ct[0]]]
2514 2522 or changetypes):
2515 2523 if opts['no_status']:
2516 2524 format = "%%s%s" % end
2517 2525 else:
2518 2526 format = "%s %%s%s" % (char, end)
2519 2527
2520 2528 for f in changes:
2521 2529 ui.write(format % repo.pathto(f, cwd))
2522 2530 if ((all or opts.get('copies')) and not opts.get('no_status')):
2523 2531 copied = repo.dirstate.copied(f)
2524 2532 if copied:
2525 2533 ui.write(' %s%s' % (repo.pathto(copied, cwd), end))
2526 2534
2527 2535 def tag(ui, repo, name, rev_=None, **opts):
2528 2536 """add a tag for the current or given revision
2529 2537
2530 2538 Name a particular revision using <name>.
2531 2539
2532 2540 Tags are used to name particular revisions of the repository and are
2533 2541 very useful to compare different revision, to go back to significant
2534 2542 earlier versions or to mark branch points as releases, etc.
2535 2543
2536 2544 If no revision is given, the parent of the working directory is used,
2537 2545 or tip if no revision is checked out.
2538 2546
2539 2547 To facilitate version control, distribution, and merging of tags,
2540 2548 they are stored as a file named ".hgtags" which is managed
2541 2549 similarly to other project files and can be hand-edited if
2542 2550 necessary. The file '.hg/localtags' is used for local tags (not
2543 2551 shared among repositories).
2552
2553 See 'hg help dates' for a list of formats valid for -d/--date.
2544 2554 """
2545 2555 if name in ['tip', '.', 'null']:
2546 2556 raise util.Abort(_("the name '%s' is reserved") % name)
2547 2557 if rev_ is not None:
2548 2558 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2549 2559 "please use 'hg tag [-r REV] NAME' instead\n"))
2550 2560 if opts['rev']:
2551 2561 raise util.Abort(_("use only one form to specify the revision"))
2552 2562 if opts['rev'] and opts['remove']:
2553 2563 raise util.Abort(_("--rev and --remove are incompatible"))
2554 2564 if opts['rev']:
2555 2565 rev_ = opts['rev']
2556 2566 message = opts['message']
2557 2567 if opts['remove']:
2558 2568 tagtype = repo.tagtype(name)
2559 2569
2560 2570 if not tagtype:
2561 2571 raise util.Abort(_('tag %s does not exist') % name)
2562 2572 if opts['local'] and tagtype == 'global':
2563 2573 raise util.Abort(_('%s tag is global') % name)
2564 2574 if not opts['local'] and tagtype == 'local':
2565 2575 raise util.Abort(_('%s tag is local') % name)
2566 2576
2567 2577 rev_ = nullid
2568 2578 if not message:
2569 2579 message = _('Removed tag %s') % name
2570 2580 elif name in repo.tags() and not opts['force']:
2571 2581 raise util.Abort(_('a tag named %s already exists (use -f to force)')
2572 2582 % name)
2573 2583 if not rev_ and repo.dirstate.parents()[1] != nullid:
2574 2584 raise util.Abort(_('uncommitted merge - please provide a '
2575 2585 'specific revision'))
2576 2586 r = repo.changectx(rev_).node()
2577 2587
2578 2588 if not message:
2579 2589 message = _('Added tag %s for changeset %s') % (name, short(r))
2580 2590
2581 2591 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2582 2592
2583 2593 def tags(ui, repo):
2584 2594 """list repository tags
2585 2595
2586 2596 List the repository tags.
2587 2597
2588 2598 This lists both regular and local tags. When the -v/--verbose switch
2589 2599 is used, a third column "local" is printed for local tags.
2590 2600 """
2591 2601
2592 2602 l = repo.tagslist()
2593 2603 l.reverse()
2594 2604 hexfunc = ui.debugflag and hex or short
2595 2605 tagtype = ""
2596 2606
2597 2607 for t, n in l:
2598 2608 if ui.quiet:
2599 2609 ui.write("%s\n" % t)
2600 2610 continue
2601 2611
2602 2612 try:
2603 2613 hn = hexfunc(n)
2604 2614 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2605 2615 except revlog.LookupError:
2606 2616 r = " ?:%s" % hn
2607 2617 else:
2608 2618 spaces = " " * (30 - util.locallen(t))
2609 2619 if ui.verbose:
2610 2620 if repo.tagtype(t) == 'local':
2611 2621 tagtype = " local"
2612 2622 else:
2613 2623 tagtype = ""
2614 2624 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2615 2625
2616 2626 def tip(ui, repo, **opts):
2617 2627 """show the tip revision
2618 2628
2619 2629 Show the tip revision.
2620 2630 """
2621 2631 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2622 2632
2623 2633 def unbundle(ui, repo, fname1, *fnames, **opts):
2624 2634 """apply one or more changegroup files
2625 2635
2626 2636 Apply one or more compressed changegroup files generated by the
2627 2637 bundle command.
2628 2638 """
2629 2639 fnames = (fname1,) + fnames
2630 2640 for fname in fnames:
2631 2641 if os.path.exists(fname):
2632 2642 f = open(fname, "rb")
2633 2643 else:
2634 2644 f = urllib.urlopen(fname)
2635 2645 gen = changegroup.readbundle(f, fname)
2636 2646 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2637 2647
2638 2648 return postincoming(ui, repo, modheads, opts['update'], None)
2639 2649
2640 2650 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2641 2651 """update working directory
2642 2652
2643 2653 Update the working directory to the specified revision, or the
2644 2654 tip of the current branch if none is specified.
2655 See 'hg help dates' for a list of formats valid for -d/--date.
2645 2656
2646 2657 If there are no outstanding changes in the working directory and
2647 2658 there is a linear relationship between the current version and the
2648 2659 requested version, the result is the requested version.
2649 2660
2650 2661 To merge the working directory with another revision, use the
2651 2662 merge command.
2652 2663
2653 2664 By default, update will refuse to run if doing so would require
2654 2665 discarding local changes.
2655 2666 """
2656 2667 if rev and node:
2657 2668 raise util.Abort(_("please specify just one revision"))
2658 2669
2659 2670 if not rev:
2660 2671 rev = node
2661 2672
2662 2673 if date:
2663 2674 if rev:
2664 2675 raise util.Abort(_("you can't specify a revision and a date"))
2665 2676 rev = cmdutil.finddate(ui, repo, date)
2666 2677
2667 2678 if clean:
2668 2679 return hg.clean(repo, rev)
2669 2680 else:
2670 2681 return hg.update(repo, rev)
2671 2682
2672 2683 def verify(ui, repo):
2673 2684 """verify the integrity of the repository
2674 2685
2675 2686 Verify the integrity of the current repository.
2676 2687
2677 2688 This will perform an extensive check of the repository's
2678 2689 integrity, validating the hashes and checksums of each entry in
2679 2690 the changelog, manifest, and tracked files, as well as the
2680 2691 integrity of their crosslinks and indices.
2681 2692 """
2682 2693 return hg.verify(repo)
2683 2694
2684 2695 def version_(ui):
2685 2696 """output version and copyright information"""
2686 2697 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2687 2698 % version.get_version())
2688 2699 ui.status(_(
2689 2700 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2690 2701 "This is free software; see the source for copying conditions. "
2691 2702 "There is NO\nwarranty; "
2692 2703 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2693 2704 ))
2694 2705
2695 2706 # Command options and aliases are listed here, alphabetically
2696 2707
2697 2708 globalopts = [
2698 2709 ('R', 'repository', '',
2699 2710 _('repository root directory or symbolic path name')),
2700 2711 ('', 'cwd', '', _('change working directory')),
2701 2712 ('y', 'noninteractive', None,
2702 2713 _('do not prompt, assume \'yes\' for any required answers')),
2703 2714 ('q', 'quiet', None, _('suppress output')),
2704 2715 ('v', 'verbose', None, _('enable additional output')),
2705 2716 ('', 'config', [], _('set/override config option')),
2706 2717 ('', 'debug', None, _('enable debugging output')),
2707 2718 ('', 'debugger', None, _('start debugger')),
2708 2719 ('', 'encoding', util._encoding, _('set the charset encoding')),
2709 2720 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2710 2721 ('', 'lsprof', None, _('print improved command execution profile')),
2711 2722 ('', 'traceback', None, _('print traceback on exception')),
2712 2723 ('', 'time', None, _('time how long the command takes')),
2713 2724 ('', 'profile', None, _('print command execution profile')),
2714 2725 ('', 'version', None, _('output version information and exit')),
2715 2726 ('h', 'help', None, _('display help and exit')),
2716 2727 ]
2717 2728
2718 2729 dryrunopts = [('n', 'dry-run', None,
2719 2730 _('do not perform actions, just print output'))]
2720 2731
2721 2732 remoteopts = [
2722 2733 ('e', 'ssh', '', _('specify ssh command to use')),
2723 2734 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2724 2735 ]
2725 2736
2726 2737 walkopts = [
2727 2738 ('I', 'include', [], _('include names matching the given patterns')),
2728 2739 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2729 2740 ]
2730 2741
2731 2742 commitopts = [
2732 2743 ('m', 'message', '', _('use <text> as commit message')),
2733 2744 ('l', 'logfile', '', _('read commit message from <file>')),
2734 2745 ]
2735 2746
2736 2747 commitopts2 = [
2737 2748 ('d', 'date', '', _('record datecode as commit date')),
2738 2749 ('u', 'user', '', _('record user as committer')),
2739 2750 ]
2740 2751
2741 2752 table = {
2742 2753 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2743 2754 "addremove":
2744 2755 (addremove,
2745 2756 [('s', 'similarity', '',
2746 2757 _('guess renamed files by similarity (0<=s<=100)')),
2747 2758 ] + walkopts + dryrunopts,
2748 2759 _('hg addremove [OPTION]... [FILE]...')),
2749 2760 "^annotate":
2750 2761 (annotate,
2751 2762 [('r', 'rev', '', _('annotate the specified revision')),
2752 2763 ('f', 'follow', None, _('follow file copies and renames')),
2753 2764 ('a', 'text', None, _('treat all files as text')),
2754 2765 ('u', 'user', None, _('list the author (long with -v)')),
2755 2766 ('d', 'date', None, _('list the date (short with -q)')),
2756 2767 ('n', 'number', None, _('list the revision number (default)')),
2757 2768 ('c', 'changeset', None, _('list the changeset')),
2758 2769 ('l', 'line-number', None,
2759 2770 _('show line number at the first appearance'))
2760 2771 ] + walkopts,
2761 2772 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2762 2773 "archive":
2763 2774 (archive,
2764 2775 [('', 'no-decode', None, _('do not pass files through decoders')),
2765 2776 ('p', 'prefix', '', _('directory prefix for files in archive')),
2766 2777 ('r', 'rev', '', _('revision to distribute')),
2767 2778 ('t', 'type', '', _('type of distribution to create')),
2768 2779 ] + walkopts,
2769 2780 _('hg archive [OPTION]... DEST')),
2770 2781 "backout":
2771 2782 (backout,
2772 2783 [('', 'merge', None,
2773 2784 _('merge with old dirstate parent after backout')),
2774 2785 ('', 'parent', '', _('parent to choose when backing out merge')),
2775 2786 ('r', 'rev', '', _('revision to backout')),
2776 2787 ] + walkopts + commitopts + commitopts2,
2777 2788 _('hg backout [OPTION]... [-r] REV')),
2778 2789 "bisect":
2779 2790 (bisect,
2780 2791 [('r', 'reset', False, _('reset bisect state')),
2781 2792 ('g', 'good', False, _('mark changeset good')),
2782 2793 ('b', 'bad', False, _('mark changeset bad')),
2783 2794 ('s', 'skip', False, _('skip testing changeset')),
2784 2795 ('U', 'noupdate', False, _('do not update to target'))],
2785 2796 _("hg bisect [-gbsr] [REV]")),
2786 2797 "branch":
2787 2798 (branch,
2788 2799 [('f', 'force', None,
2789 2800 _('set branch name even if it shadows an existing branch'))],
2790 2801 _('hg branch [-f] [NAME]')),
2791 2802 "branches":
2792 2803 (branches,
2793 2804 [('a', 'active', False,
2794 2805 _('show only branches that have unmerged heads'))],
2795 2806 _('hg branches [-a]')),
2796 2807 "bundle":
2797 2808 (bundle,
2798 2809 [('f', 'force', None,
2799 2810 _('run even when remote repository is unrelated')),
2800 2811 ('r', 'rev', [],
2801 2812 _('a changeset you would like to bundle')),
2802 2813 ('', 'base', [],
2803 2814 _('a base changeset to specify instead of a destination')),
2804 2815 ] + remoteopts,
2805 2816 _('hg bundle [-f] [-r REV]... [--base REV]... FILE [DEST]')),
2806 2817 "cat":
2807 2818 (cat,
2808 2819 [('o', 'output', '', _('print output to file with formatted name')),
2809 2820 ('r', 'rev', '', _('print the given revision')),
2810 2821 ('', 'decode', None, _('apply any matching decode filter')),
2811 2822 ] + walkopts,
2812 2823 _('hg cat [OPTION]... FILE...')),
2813 2824 "^clone":
2814 2825 (clone,
2815 2826 [('U', 'noupdate', None, _('do not update the new working directory')),
2816 2827 ('r', 'rev', [],
2817 2828 _('a changeset you would like to have after cloning')),
2818 2829 ('', 'pull', None, _('use pull protocol to copy metadata')),
2819 2830 ('', 'uncompressed', None,
2820 2831 _('use uncompressed transfer (fast over LAN)')),
2821 2832 ] + remoteopts,
2822 2833 _('hg clone [OPTION]... SOURCE [DEST]')),
2823 2834 "^commit|ci":
2824 2835 (commit,
2825 2836 [('A', 'addremove', None,
2826 2837 _('mark new/missing files as added/removed before committing')),
2827 2838 ] + walkopts + commitopts + commitopts2,
2828 2839 _('hg commit [OPTION]... [FILE]...')),
2829 2840 "copy|cp":
2830 2841 (copy,
2831 2842 [('A', 'after', None, _('record a copy that has already occurred')),
2832 2843 ('f', 'force', None,
2833 2844 _('forcibly copy over an existing managed file')),
2834 2845 ] + walkopts + dryrunopts,
2835 2846 _('hg copy [OPTION]... [SOURCE]... DEST')),
2836 2847 "debugancestor": (debugancestor, [], _('hg debugancestor INDEX REV1 REV2')),
2837 2848 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
2838 2849 "debugcomplete":
2839 2850 (debugcomplete,
2840 2851 [('o', 'options', None, _('show the command options'))],
2841 2852 _('hg debugcomplete [-o] CMD')),
2842 2853 "debugdate":
2843 2854 (debugdate,
2844 2855 [('e', 'extended', None, _('try extended date formats'))],
2845 2856 _('hg debugdate [-e] DATE [RANGE]')),
2846 2857 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
2847 2858 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
2848 2859 "debugindex": (debugindex, [], _('hg debugindex FILE')),
2849 2860 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
2850 2861 "debuginstall": (debuginstall, [], _('hg debuginstall')),
2851 2862 "debugrawcommit|rawcommit":
2852 2863 (rawcommit,
2853 2864 [('p', 'parent', [], _('parent')),
2854 2865 ('F', 'files', '', _('file list'))
2855 2866 ] + commitopts + commitopts2,
2856 2867 _('hg debugrawcommit [OPTION]... [FILE]...')),
2857 2868 "debugrebuildstate":
2858 2869 (debugrebuildstate,
2859 2870 [('r', 'rev', '', _('revision to rebuild to'))],
2860 2871 _('hg debugrebuildstate [-r REV] [REV]')),
2861 2872 "debugrename":
2862 2873 (debugrename,
2863 2874 [('r', 'rev', '', _('revision to debug'))],
2864 2875 _('hg debugrename [-r REV] FILE')),
2865 2876 "debugsetparents":
2866 2877 (debugsetparents,
2867 2878 [],
2868 2879 _('hg debugsetparents REV1 [REV2]')),
2869 2880 "debugstate": (debugstate, [], _('hg debugstate')),
2870 2881 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
2871 2882 "^diff":
2872 2883 (diff,
2873 2884 [('r', 'rev', [], _('revision')),
2874 2885 ('a', 'text', None, _('treat all files as text')),
2875 2886 ('p', 'show-function', None,
2876 2887 _('show which function each change is in')),
2877 2888 ('g', 'git', None, _('use git extended diff format')),
2878 2889 ('', 'nodates', None, _("don't include dates in diff headers")),
2879 2890 ('w', 'ignore-all-space', None,
2880 2891 _('ignore white space when comparing lines')),
2881 2892 ('b', 'ignore-space-change', None,
2882 2893 _('ignore changes in the amount of white space')),
2883 2894 ('B', 'ignore-blank-lines', None,
2884 2895 _('ignore changes whose lines are all blank')),
2885 2896 ('U', 'unified', 3,
2886 2897 _('number of lines of context to show'))
2887 2898 ] + walkopts,
2888 2899 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
2889 2900 "^export":
2890 2901 (export,
2891 2902 [('o', 'output', '', _('print output to file with formatted name')),
2892 2903 ('a', 'text', None, _('treat all files as text')),
2893 2904 ('g', 'git', None, _('use git extended diff format')),
2894 2905 ('', 'nodates', None, _("don't include dates in diff headers")),
2895 2906 ('', 'switch-parent', None, _('diff against the second parent'))],
2896 2907 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
2897 2908 "grep":
2898 2909 (grep,
2899 2910 [('0', 'print0', None, _('end fields with NUL')),
2900 2911 ('', 'all', None, _('print all revisions that match')),
2901 2912 ('f', 'follow', None,
2902 2913 _('follow changeset history, or file history across copies and renames')),
2903 2914 ('i', 'ignore-case', None, _('ignore case when matching')),
2904 2915 ('l', 'files-with-matches', None,
2905 2916 _('print only filenames and revs that match')),
2906 2917 ('n', 'line-number', None, _('print matching line numbers')),
2907 2918 ('r', 'rev', [], _('search in given revision range')),
2908 2919 ('u', 'user', None, _('list the author (long with -v)')),
2909 2920 ('d', 'date', None, _('list the date (short with -q)')),
2910 2921 ] + walkopts,
2911 2922 _('hg grep [OPTION]... PATTERN [FILE]...')),
2912 2923 "heads":
2913 2924 (heads,
2914 2925 [('', 'style', '', _('display using template map file')),
2915 2926 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2916 2927 ('', 'template', '', _('display with template'))],
2917 2928 _('hg heads [-r REV] [REV]...')),
2918 2929 "help": (help_, [], _('hg help [COMMAND]')),
2919 2930 "identify|id":
2920 2931 (identify,
2921 2932 [('r', 'rev', '', _('identify the specified rev')),
2922 2933 ('n', 'num', None, _('show local revision number')),
2923 2934 ('i', 'id', None, _('show global revision id')),
2924 2935 ('b', 'branch', None, _('show branch')),
2925 2936 ('t', 'tags', None, _('show tags'))],
2926 2937 _('hg identify [-nibt] [-r REV] [SOURCE]')),
2927 2938 "import|patch":
2928 2939 (import_,
2929 2940 [('p', 'strip', 1,
2930 2941 _('directory strip option for patch. This has the same\n'
2931 2942 'meaning as the corresponding patch option')),
2932 2943 ('b', 'base', '', _('base path')),
2933 2944 ('f', 'force', None,
2934 2945 _('skip check for outstanding uncommitted changes')),
2935 2946 ('', 'no-commit', None, _("don't commit, just update the working directory")),
2936 2947 ('', 'exact', None,
2937 2948 _('apply patch to the nodes from which it was generated')),
2938 2949 ('', 'import-branch', None,
2939 2950 _('Use any branch information in patch (implied by --exact)'))] +
2940 2951 commitopts + commitopts2,
2941 2952 _('hg import [OPTION]... PATCH...')),
2942 2953 "incoming|in":
2943 2954 (incoming,
2944 2955 [('M', 'no-merges', None, _('do not show merges')),
2945 2956 ('f', 'force', None,
2946 2957 _('run even when remote repository is unrelated')),
2947 2958 ('', 'style', '', _('display using template map file')),
2948 2959 ('n', 'newest-first', None, _('show newest record first')),
2949 2960 ('', 'bundle', '', _('file to store the bundles into')),
2950 2961 ('p', 'patch', None, _('show patch')),
2951 2962 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2952 2963 ('', 'template', '', _('display with template')),
2953 2964 ] + remoteopts,
2954 2965 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
2955 2966 ' [--bundle FILENAME] [SOURCE]')),
2956 2967 "^init":
2957 2968 (init,
2958 2969 remoteopts,
2959 2970 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
2960 2971 "locate":
2961 2972 (locate,
2962 2973 [('r', 'rev', '', _('search the repository as it stood at rev')),
2963 2974 ('0', 'print0', None,
2964 2975 _('end filenames with NUL, for use with xargs')),
2965 2976 ('f', 'fullpath', None,
2966 2977 _('print complete paths from the filesystem root')),
2967 2978 ] + walkopts,
2968 2979 _('hg locate [OPTION]... [PATTERN]...')),
2969 2980 "^log|history":
2970 2981 (log,
2971 2982 [('f', 'follow', None,
2972 2983 _('follow changeset history, or file history across copies and renames')),
2973 2984 ('', 'follow-first', None,
2974 2985 _('only follow the first parent of merge changesets')),
2975 2986 ('d', 'date', '', _('show revs matching date spec')),
2976 2987 ('C', 'copies', None, _('show copied files')),
2977 2988 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
2978 2989 ('l', 'limit', '', _('limit number of changes displayed')),
2979 2990 ('r', 'rev', [], _('show the specified revision or range')),
2980 2991 ('', 'removed', None, _('include revs where files were removed')),
2981 2992 ('M', 'no-merges', None, _('do not show merges')),
2982 2993 ('', 'style', '', _('display using template map file')),
2983 2994 ('m', 'only-merges', None, _('show only merges')),
2984 2995 ('b', 'only-branch', [],
2985 2996 _('show only changesets within the given named branch')),
2986 2997 ('p', 'patch', None, _('show patch')),
2987 2998 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2988 2999 ('', 'template', '', _('display with template')),
2989 3000 ] + walkopts,
2990 3001 _('hg log [OPTION]... [FILE]')),
2991 3002 "manifest":
2992 3003 (manifest,
2993 3004 [('r', 'rev', '', _('revision to display'))],
2994 3005 _('hg manifest [-r REV]')),
2995 3006 "^merge":
2996 3007 (merge,
2997 3008 [('f', 'force', None, _('force a merge with outstanding changes')),
2998 3009 ('r', 'rev', '', _('revision to merge')),
2999 3010 ],
3000 3011 _('hg merge [-f] [[-r] REV]')),
3001 3012 "outgoing|out":
3002 3013 (outgoing,
3003 3014 [('M', 'no-merges', None, _('do not show merges')),
3004 3015 ('f', 'force', None,
3005 3016 _('run even when remote repository is unrelated')),
3006 3017 ('p', 'patch', None, _('show patch')),
3007 3018 ('', 'style', '', _('display using template map file')),
3008 3019 ('r', 'rev', [], _('a specific revision you would like to push')),
3009 3020 ('n', 'newest-first', None, _('show newest record first')),
3010 3021 ('', 'template', '', _('display with template')),
3011 3022 ] + remoteopts,
3012 3023 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3013 3024 "^parents":
3014 3025 (parents,
3015 3026 [('r', 'rev', '', _('show parents from the specified rev')),
3016 3027 ('', 'style', '', _('display using template map file')),
3017 3028 ('', 'template', '', _('display with template'))],
3018 3029 _('hg parents [-r REV] [FILE]')),
3019 3030 "paths": (paths, [], _('hg paths [NAME]')),
3020 3031 "^pull":
3021 3032 (pull,
3022 3033 [('u', 'update', None,
3023 3034 _('update to new tip if changesets were pulled')),
3024 3035 ('f', 'force', None,
3025 3036 _('run even when remote repository is unrelated')),
3026 3037 ('r', 'rev', [],
3027 3038 _('a specific revision up to which you would like to pull')),
3028 3039 ] + remoteopts,
3029 3040 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3030 3041 "^push":
3031 3042 (push,
3032 3043 [('f', 'force', None, _('force push')),
3033 3044 ('r', 'rev', [], _('a specific revision you would like to push')),
3034 3045 ] + remoteopts,
3035 3046 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3036 3047 "recover": (recover, [], _('hg recover')),
3037 3048 "^remove|rm":
3038 3049 (remove,
3039 3050 [('A', 'after', None, _('record remove without deleting')),
3040 3051 ('f', 'force', None, _('remove file even if modified')),
3041 3052 ] + walkopts,
3042 3053 _('hg remove [OPTION]... FILE...')),
3043 3054 "rename|mv":
3044 3055 (rename,
3045 3056 [('A', 'after', None, _('record a rename that has already occurred')),
3046 3057 ('f', 'force', None,
3047 3058 _('forcibly copy over an existing managed file')),
3048 3059 ] + walkopts + dryrunopts,
3049 3060 _('hg rename [OPTION]... SOURCE... DEST')),
3050 3061 "revert":
3051 3062 (revert,
3052 3063 [('a', 'all', None, _('revert all changes when no arguments given')),
3053 3064 ('d', 'date', '', _('tipmost revision matching date')),
3054 3065 ('r', 'rev', '', _('revision to revert to')),
3055 3066 ('', 'no-backup', None, _('do not save backup copies of files')),
3056 3067 ] + walkopts + dryrunopts,
3057 3068 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3058 3069 "rollback": (rollback, [], _('hg rollback')),
3059 3070 "root": (root, [], _('hg root')),
3060 3071 "^serve":
3061 3072 (serve,
3062 3073 [('A', 'accesslog', '', _('name of access log file to write to')),
3063 3074 ('d', 'daemon', None, _('run server in background')),
3064 3075 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3065 3076 ('E', 'errorlog', '', _('name of error log file to write to')),
3066 3077 ('p', 'port', 0, _('port to use (default: 8000)')),
3067 3078 ('a', 'address', '', _('address to use')),
3068 3079 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3069 3080 ('n', 'name', '',
3070 3081 _('name to show in web pages (default: working dir)')),
3071 3082 ('', 'webdir-conf', '', _('name of the webdir config file'
3072 3083 ' (serve more than one repo)')),
3073 3084 ('', 'pid-file', '', _('name of file to write process ID to')),
3074 3085 ('', 'stdio', None, _('for remote clients')),
3075 3086 ('t', 'templates', '', _('web templates to use')),
3076 3087 ('', 'style', '', _('template style to use')),
3077 3088 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3078 3089 ('', 'certificate', '', _('SSL certificate file'))],
3079 3090 _('hg serve [OPTION]...')),
3080 3091 "showconfig|debugconfig":
3081 3092 (showconfig,
3082 3093 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3083 3094 _('hg showconfig [-u] [NAME]...')),
3084 3095 "^status|st":
3085 3096 (status,
3086 3097 [('A', 'all', None, _('show status of all files')),
3087 3098 ('m', 'modified', None, _('show only modified files')),
3088 3099 ('a', 'added', None, _('show only added files')),
3089 3100 ('r', 'removed', None, _('show only removed files')),
3090 3101 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3091 3102 ('c', 'clean', None, _('show only files without changes')),
3092 3103 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3093 3104 ('i', 'ignored', None, _('show only ignored files')),
3094 3105 ('n', 'no-status', None, _('hide status prefix')),
3095 3106 ('C', 'copies', None, _('show source of copied files')),
3096 3107 ('0', 'print0', None,
3097 3108 _('end filenames with NUL, for use with xargs')),
3098 3109 ('', 'rev', [], _('show difference from revision')),
3099 3110 ] + walkopts,
3100 3111 _('hg status [OPTION]... [FILE]...')),
3101 3112 "tag":
3102 3113 (tag,
3103 3114 [('f', 'force', None, _('replace existing tag')),
3104 3115 ('l', 'local', None, _('make the tag local')),
3105 3116 ('r', 'rev', '', _('revision to tag')),
3106 3117 ('', 'remove', None, _('remove a tag')),
3107 3118 # -l/--local is already there, commitopts cannot be used
3108 3119 ('m', 'message', '', _('use <text> as commit message')),
3109 3120 ] + commitopts2,
3110 3121 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3111 3122 "tags": (tags, [], _('hg tags')),
3112 3123 "tip":
3113 3124 (tip,
3114 3125 [('', 'style', '', _('display using template map file')),
3115 3126 ('p', 'patch', None, _('show patch')),
3116 3127 ('', 'template', '', _('display with template'))],
3117 3128 _('hg tip [-p]')),
3118 3129 "unbundle":
3119 3130 (unbundle,
3120 3131 [('u', 'update', None,
3121 3132 _('update to new tip if changesets were unbundled'))],
3122 3133 _('hg unbundle [-u] FILE...')),
3123 3134 "^update|up|checkout|co":
3124 3135 (update,
3125 3136 [('C', 'clean', None, _('overwrite locally modified files')),
3126 3137 ('d', 'date', '', _('tipmost revision matching date')),
3127 3138 ('r', 'rev', '', _('revision'))],
3128 3139 _('hg update [-C] [-d DATE] [[-r] REV]')),
3129 3140 "verify": (verify, [], _('hg verify')),
3130 3141 "version": (version_, [], _('hg version')),
3131 3142 }
3132 3143
3133 3144 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3134 3145 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3135 3146 optionalrepo = ("identify paths serve showconfig")
@@ -1,154 +1,164
1 1 # help.py - help data for mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 helptable = {
9 9 "dates|Date Formats":
10 10 r'''
11 Some commands (backout, commit, tag) allow the user to specify a date.
12 Many date formats are acceptible. Here are some examples:
11 Some commands allow the user to specify a date:
12 backout, commit, import, tag: Specify the commit date.
13 log, revert, update: Select revision(s) by date.
14
15 Many date formats are valid. Here are some examples:
13 16
14 17 "Wed Dec 6 13:18:29 2006" (local timezone assumed)
15 18 "Dec 6 13:18 -0600" (year assumed, time offset provided)
16 19 "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
17 20 "Dec 6" (midnight)
18 21 "13:18" (today assumed)
19 22 "3:39" (3:39AM assumed)
20 23 "3:39pm" (15:39)
21 24 "2006-12-6 13:18:29" (ISO 8601 format)
22 25 "2006-12-6 13:18"
23 26 "2006-12-6"
24 27 "12-6"
25 28 "12/6"
26 29 "12/6/6" (Dec 6 2006)
27 30
28 31 Lastly, there is Mercurial's internal format:
29 32
30 33 "1165432709 0" (Wed Dec 6 13:18:29 2006 UTC)
31 34
32 35 This is the internal representation format for dates. unixtime is
33 36 the number of seconds since the epoch (1970-01-01 00:00 UTC). offset
34 37 is the offset of the local timezone, in seconds west of UTC (negative
35 38 if the timezone is east of UTC).
39
40 The log command also accepts date ranges:
41
42 "<{date}" - on or before a given date
43 ">{date}" - on or after a given date
44 "{date} to {date}" - a date range, inclusive
45 "-{days}" - within a given number of days of today
36 46 ''',
37 47
38 48 'environment|env|Environment Variables':
39 49 r'''
40 50 HG::
41 51 Path to the 'hg' executable, automatically passed when running hooks,
42 52 extensions or external tools. If unset or empty, an executable named
43 53 'hg' (with com/exe/bat/cmd extension on Windows) is searched.
44 54
45 55 HGEDITOR::
46 56 This is the name of the editor to use when committing. See EDITOR.
47 57
48 58 (deprecated, use .hgrc)
49 59
50 60 HGENCODING::
51 61 This overrides the default locale setting detected by Mercurial.
52 62 This setting is used to convert data including usernames,
53 63 changeset descriptions, tag names, and branches. This setting can
54 64 be overridden with the --encoding command-line option.
55 65
56 66 HGENCODINGMODE::
57 67 This sets Mercurial's behavior for handling unknown characters
58 68 while transcoding user inputs. The default is "strict", which
59 69 causes Mercurial to abort if it can't translate a character. Other
60 70 settings include "replace", which replaces unknown characters, and
61 71 "ignore", which drops them. This setting can be overridden with
62 72 the --encodingmode command-line option.
63 73
64 74 HGMERGE::
65 75 An executable to use for resolving merge conflicts. The program
66 76 will be executed with three arguments: local file, remote file,
67 77 ancestor file.
68 78
69 79 (deprecated, use .hgrc)
70 80
71 81 HGRCPATH::
72 82 A list of files or directories to search for hgrc files. Item
73 83 separator is ":" on Unix, ";" on Windows. If HGRCPATH is not set,
74 84 platform default search path is used. If empty, only .hg/hgrc of
75 85 current repository is read.
76 86
77 87 For each element in path, if a directory, all entries in directory
78 88 ending with ".rc" are added to path. Else, element itself is
79 89 added to path.
80 90
81 91 HGUSER::
82 92 This is the string used for the author of a commit.
83 93
84 94 (deprecated, use .hgrc)
85 95
86 96 EMAIL::
87 97 If HGUSER is not set, this will be used as the author for a commit.
88 98
89 99 LOGNAME::
90 100 If neither HGUSER nor EMAIL is set, LOGNAME will be used (with
91 101 '@hostname' appended) as the author value for a commit.
92 102
93 103 VISUAL::
94 104 This is the name of the editor to use when committing. See EDITOR.
95 105
96 106 EDITOR::
97 107 Sometimes Mercurial needs to open a text file in an editor
98 108 for a user to modify, for example when writing commit messages.
99 109 The editor it uses is determined by looking at the environment
100 110 variables HGEDITOR, VISUAL and EDITOR, in that order. The first
101 111 non-empty one is chosen. If all of them are empty, the editor
102 112 defaults to 'vi'.
103 113
104 114 PYTHONPATH::
105 115 This is used by Python to find imported modules and may need to be set
106 116 appropriately if Mercurial is not installed system-wide.
107 117 ''',
108 118
109 119 "patterns|File Name Patterns": r'''
110 120 Mercurial accepts several notations for identifying one or more
111 121 files at a time.
112 122
113 123 By default, Mercurial treats filenames as shell-style extended
114 124 glob patterns.
115 125
116 126 Alternate pattern notations must be specified explicitly.
117 127
118 128 To use a plain path name without any pattern matching, start a
119 129 name with "path:". These path names must match completely, from
120 130 the root of the current repository.
121 131
122 132 To use an extended glob, start a name with "glob:". Globs are
123 133 rooted at the current directory; a glob such as "*.c" will match
124 134 files ending in ".c" in the current directory only.
125 135
126 136 The supported glob syntax extensions are "**" to match any string
127 137 across path separators, and "{a,b}" to mean "a or b".
128 138
129 139 To use a Perl/Python regular expression, start a name with "re:".
130 140 Regexp pattern matching is anchored at the root of the repository.
131 141
132 142 Plain examples:
133 143
134 144 path:foo/bar a name bar in a directory named foo in the root of
135 145 the repository
136 146 path:path:name a file or directory named "path:name"
137 147
138 148 Glob examples:
139 149
140 150 glob:*.c any name ending in ".c" in the current directory
141 151 *.c any name ending in ".c" in the current directory
142 152 **.c any name ending in ".c" in the current directory, or
143 153 any subdirectory
144 154 foo/*.c any name ending in ".c" in the directory foo
145 155 foo/**.c any name ending in ".c" in the directory foo, or any
146 156 subdirectory
147 157
148 158 Regexp examples:
149 159
150 160 re:.*\.c$ any name ending in ".c", anywhere in the repository
151 161
152 162 ''',
153 163 }
154 164
@@ -1,493 +1,495
1 1 % help
2 2 hg record [OPTION]... [FILE]...
3 3
4 4 interactively select changes to commit
5 5
6 6 If a list of files is omitted, all changes reported by "hg status"
7 7 will be candidates for recording.
8 8
9 See 'hg help dates' for a list of formats valid for -d/--date.
10
9 11 You will be prompted for whether to record changes to each
10 12 modified file, and for files with multiple changes, for each
11 13 change to use. For each query, the following responses are
12 14 possible:
13 15
14 16 y - record this change
15 17 n - skip this change
16 18
17 19 s - skip remaining changes to this file
18 20 f - record remaining changes to this file
19 21
20 22 d - done, skip remaining changes and files
21 23 a - record all changes to all remaining files
22 24 q - quit, recording no changes
23 25
24 26 ? - display help
25 27
26 28 options:
27 29
28 30 -A --addremove mark new/missing files as added/removed before committing
29 31 -I --include include names matching the given patterns
30 32 -X --exclude exclude names matching the given patterns
31 33 -m --message use <text> as commit message
32 34 -l --logfile read commit message from <file>
33 35 -d --date record datecode as commit date
34 36 -u --user record user as committer
35 37
36 38 use "hg -v help record" to show global options
37 39 % select no files
38 40 diff --git a/empty-rw b/empty-rw
39 41 new file mode 100644
40 42 examine changes to 'empty-rw'? [Ynsfdaq?] no changes to record
41 43
42 44 changeset: -1:000000000000
43 45 tag: tip
44 46 user:
45 47 date: Thu Jan 01 00:00:00 1970 +0000
46 48
47 49
48 50 % select files but no hunks
49 51 diff --git a/empty-rw b/empty-rw
50 52 new file mode 100644
51 53 examine changes to 'empty-rw'? [Ynsfdaq?] transaction abort!
52 54 rollback completed
53 55 abort: empty commit message
54 56
55 57 changeset: -1:000000000000
56 58 tag: tip
57 59 user:
58 60 date: Thu Jan 01 00:00:00 1970 +0000
59 61
60 62
61 63 % record empty file
62 64 diff --git a/empty-rw b/empty-rw
63 65 new file mode 100644
64 66 examine changes to 'empty-rw'? [Ynsfdaq?]
65 67 changeset: 0:c0708cf4e46e
66 68 tag: tip
67 69 user: test
68 70 date: Thu Jan 01 00:00:00 1970 +0000
69 71 summary: empty
70 72
71 73
72 74 % rename empty file
73 75 diff --git a/empty-rw b/empty-rename
74 76 rename from empty-rw
75 77 rename to empty-rename
76 78 examine changes to 'empty-rw' and 'empty-rename'? [Ynsfdaq?]
77 79 changeset: 1:df251d174da3
78 80 tag: tip
79 81 user: test
80 82 date: Thu Jan 01 00:00:01 1970 +0000
81 83 summary: rename
82 84
83 85
84 86 % copy empty file
85 87 diff --git a/empty-rename b/empty-copy
86 88 copy from empty-rename
87 89 copy to empty-copy
88 90 examine changes to 'empty-rename' and 'empty-copy'? [Ynsfdaq?]
89 91 changeset: 2:b63ea3939f8d
90 92 tag: tip
91 93 user: test
92 94 date: Thu Jan 01 00:00:02 1970 +0000
93 95 summary: copy
94 96
95 97
96 98 % delete empty file
97 99 diff --git a/empty-copy b/empty-copy
98 100 deleted file mode 100644
99 101 examine changes to 'empty-copy'? [Ynsfdaq?]
100 102 changeset: 3:a2546574bce9
101 103 tag: tip
102 104 user: test
103 105 date: Thu Jan 01 00:00:03 1970 +0000
104 106 summary: delete
105 107
106 108
107 109 % add binary file
108 110 1 changesets found
109 111 diff --git a/tip.bundle b/tip.bundle
110 112 new file mode 100644
111 113 this is a binary file
112 114 examine changes to 'tip.bundle'? [Ynsfdaq?]
113 115 changeset: 4:9e998a545a8b
114 116 tag: tip
115 117 user: test
116 118 date: Thu Jan 01 00:00:04 1970 +0000
117 119 summary: binary
118 120
119 121 diff -r a2546574bce9 -r 9e998a545a8b tip.bundle
120 122 Binary file tip.bundle has changed
121 123
122 124 % change binary file
123 125 1 changesets found
124 126 diff --git a/tip.bundle b/tip.bundle
125 127 this modifies a binary file (all or nothing)
126 128 examine changes to 'tip.bundle'? [Ynsfdaq?]
127 129 changeset: 5:93d05561507d
128 130 tag: tip
129 131 user: test
130 132 date: Thu Jan 01 00:00:05 1970 +0000
131 133 summary: binary-change
132 134
133 135 diff -r 9e998a545a8b -r 93d05561507d tip.bundle
134 136 Binary file tip.bundle has changed
135 137
136 138 % rename and change binary file
137 139 1 changesets found
138 140 diff --git a/tip.bundle b/top.bundle
139 141 rename from tip.bundle
140 142 rename to top.bundle
141 143 this modifies a binary file (all or nothing)
142 144 examine changes to 'tip.bundle' and 'top.bundle'? [Ynsfdaq?]
143 145 changeset: 6:699cc1bea9aa
144 146 tag: tip
145 147 user: test
146 148 date: Thu Jan 01 00:00:06 1970 +0000
147 149 summary: binary-change-rename
148 150
149 151 diff -r 93d05561507d -r 699cc1bea9aa tip.bundle
150 152 Binary file tip.bundle has changed
151 153 diff -r 93d05561507d -r 699cc1bea9aa top.bundle
152 154 Binary file top.bundle has changed
153 155
154 156 % add plain file
155 157 diff --git a/plain b/plain
156 158 new file mode 100644
157 159 examine changes to 'plain'? [Ynsfdaq?]
158 160 changeset: 7:118ed744216b
159 161 tag: tip
160 162 user: test
161 163 date: Thu Jan 01 00:00:07 1970 +0000
162 164 summary: plain
163 165
164 166 diff -r 699cc1bea9aa -r 118ed744216b plain
165 167 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
166 168 +++ b/plain Thu Jan 01 00:00:07 1970 +0000
167 169 @@ -0,0 +1,10 @@
168 170 +1
169 171 +2
170 172 +3
171 173 +4
172 174 +5
173 175 +6
174 176 +7
175 177 +8
176 178 +9
177 179 +10
178 180
179 181 % modify end of plain file
180 182 diff --git a/plain b/plain
181 183 1 hunks, 1 lines changed
182 184 examine changes to 'plain'? [Ynsfdaq?] @@ -8,3 +8,4 @@
183 185 8
184 186 9
185 187 10
186 188 +11
187 189 record this change to 'plain'? [Ynsfdaq?] % modify end of plain file, no EOL
188 190 diff --git a/plain b/plain
189 191 1 hunks, 1 lines changed
190 192 examine changes to 'plain'? [Ynsfdaq?] @@ -9,3 +9,4 @@
191 193 9
192 194 10
193 195 11
194 196 +cf81a2760718a74d44c0c2eecb72f659e63a69c5
195 197 \ No newline at end of file
196 198 record this change to 'plain'? [Ynsfdaq?] % modify end of plain file, add EOL
197 199 diff --git a/plain b/plain
198 200 1 hunks, 2 lines changed
199 201 examine changes to 'plain'? [Ynsfdaq?] @@ -9,4 +9,4 @@
200 202 9
201 203 10
202 204 11
203 205 -cf81a2760718a74d44c0c2eecb72f659e63a69c5
204 206 \ No newline at end of file
205 207 +cf81a2760718a74d44c0c2eecb72f659e63a69c5
206 208 record this change to 'plain'? [Ynsfdaq?] % modify beginning, trim end, record both
207 209 diff --git a/plain b/plain
208 210 2 hunks, 4 lines changed
209 211 examine changes to 'plain'? [Ynsfdaq?] @@ -1,4 +1,4 @@
210 212 -1
211 213 +2
212 214 2
213 215 3
214 216 4
215 217 record this change to 'plain'? [Ynsfdaq?] @@ -8,5 +8,3 @@
216 218 8
217 219 9
218 220 10
219 221 -11
220 222 -cf81a2760718a74d44c0c2eecb72f659e63a69c5
221 223 record this change to 'plain'? [Ynsfdaq?]
222 224 changeset: 11:d09ab1967dab
223 225 tag: tip
224 226 user: test
225 227 date: Thu Jan 01 00:00:10 1970 +0000
226 228 summary: begin-and-end
227 229
228 230 diff -r e2ecd9b0b78d -r d09ab1967dab plain
229 231 --- a/plain Thu Jan 01 00:00:10 1970 +0000
230 232 +++ b/plain Thu Jan 01 00:00:10 1970 +0000
231 233 @@ -1,4 +1,4 @@
232 234 -1
233 235 +2
234 236 2
235 237 3
236 238 4
237 239 @@ -8,5 +8,3 @@
238 240 8
239 241 9
240 242 10
241 243 -11
242 244 -cf81a2760718a74d44c0c2eecb72f659e63a69c5
243 245
244 246 % trim beginning, modify end
245 247 % record end
246 248 diff --git a/plain b/plain
247 249 2 hunks, 5 lines changed
248 250 examine changes to 'plain'? [Ynsfdaq?] @@ -1,9 +1,6 @@
249 251 -2
250 252 -2
251 253 -3
252 254 4
253 255 5
254 256 6
255 257 7
256 258 8
257 259 9
258 260 record this change to 'plain'? [Ynsfdaq?] @@ -4,7 +1,7 @@
259 261 4
260 262 5
261 263 6
262 264 7
263 265 8
264 266 9
265 267 -10
266 268 +10.new
267 269 record this change to 'plain'? [Ynsfdaq?]
268 270 changeset: 12:44516c9708ae
269 271 tag: tip
270 272 user: test
271 273 date: Thu Jan 01 00:00:11 1970 +0000
272 274 summary: end-only
273 275
274 276 diff -r d09ab1967dab -r 44516c9708ae plain
275 277 --- a/plain Thu Jan 01 00:00:10 1970 +0000
276 278 +++ b/plain Thu Jan 01 00:00:11 1970 +0000
277 279 @@ -7,4 +7,4 @@
278 280 7
279 281 8
280 282 9
281 283 -10
282 284 +10.new
283 285
284 286 % record beginning
285 287 diff --git a/plain b/plain
286 288 1 hunks, 3 lines changed
287 289 examine changes to 'plain'? [Ynsfdaq?] @@ -1,6 +1,3 @@
288 290 -2
289 291 -2
290 292 -3
291 293 4
292 294 5
293 295 6
294 296 record this change to 'plain'? [Ynsfdaq?]
295 297 changeset: 13:3ebbace64a8d
296 298 tag: tip
297 299 user: test
298 300 date: Thu Jan 01 00:00:12 1970 +0000
299 301 summary: begin-only
300 302
301 303 diff -r 44516c9708ae -r 3ebbace64a8d plain
302 304 --- a/plain Thu Jan 01 00:00:11 1970 +0000
303 305 +++ b/plain Thu Jan 01 00:00:12 1970 +0000
304 306 @@ -1,6 +1,3 @@
305 307 -2
306 308 -2
307 309 -3
308 310 4
309 311 5
310 312 6
311 313
312 314 % add to beginning, trim from end
313 315 % record end
314 316 diff --git a/plain b/plain
315 317 2 hunks, 4 lines changed
316 318 examine changes to 'plain'? [Ynsfdaq?] @@ -1,6 +1,9 @@
317 319 +1
318 320 +2
319 321 +3
320 322 4
321 323 5
322 324 6
323 325 7
324 326 8
325 327 9
326 328 record this change to 'plain'? [Ynsfdaq?] @@ -1,7 +4,6 @@
327 329 4
328 330 5
329 331 6
330 332 7
331 333 8
332 334 9
333 335 -10.new
334 336 record this change to 'plain'? [Ynsfdaq?] % add to beginning, middle, end
335 337 % record beginning, middle
336 338 diff --git a/plain b/plain
337 339 3 hunks, 7 lines changed
338 340 examine changes to 'plain'? [Ynsfdaq?] @@ -1,2 +1,5 @@
339 341 +1
340 342 +2
341 343 +3
342 344 4
343 345 5
344 346 record this change to 'plain'? [Ynsfdaq?] @@ -1,6 +4,8 @@
345 347 4
346 348 5
347 349 +5.new
348 350 +5.reallynew
349 351 6
350 352 7
351 353 8
352 354 9
353 355 record this change to 'plain'? [Ynsfdaq?] @@ -3,4 +8,6 @@
354 356 6
355 357 7
356 358 8
357 359 9
358 360 +10
359 361 +11
360 362 record this change to 'plain'? [Ynsfdaq?]
361 363 changeset: 15:c1c639d8b268
362 364 tag: tip
363 365 user: test
364 366 date: Thu Jan 01 00:00:14 1970 +0000
365 367 summary: middle-only
366 368
367 369 diff -r efc0dad7bd9f -r c1c639d8b268 plain
368 370 --- a/plain Thu Jan 01 00:00:13 1970 +0000
369 371 +++ b/plain Thu Jan 01 00:00:14 1970 +0000
370 372 @@ -1,5 +1,10 @@
371 373 +1
372 374 +2
373 375 +3
374 376 4
375 377 5
376 378 +5.new
377 379 +5.reallynew
378 380 6
379 381 7
380 382 8
381 383
382 384 % record end
383 385 diff --git a/plain b/plain
384 386 1 hunks, 2 lines changed
385 387 examine changes to 'plain'? [Ynsfdaq?] @@ -9,3 +9,5 @@
386 388 7
387 389 8
388 390 9
389 391 +10
390 392 +11
391 393 record this change to 'plain'? [Ynsfdaq?]
392 394 changeset: 16:80b74bbc7808
393 395 tag: tip
394 396 user: test
395 397 date: Thu Jan 01 00:00:15 1970 +0000
396 398 summary: end-only
397 399
398 400 diff -r c1c639d8b268 -r 80b74bbc7808 plain
399 401 --- a/plain Thu Jan 01 00:00:14 1970 +0000
400 402 +++ b/plain Thu Jan 01 00:00:15 1970 +0000
401 403 @@ -9,3 +9,5 @@
402 404 7
403 405 8
404 406 9
405 407 +10
406 408 +11
407 409
408 410 adding subdir/a
409 411 diff --git a/subdir/a b/subdir/a
410 412 1 hunks, 1 lines changed
411 413 examine changes to 'subdir/a'? [Ynsfdaq?] @@ -1,1 +1,2 @@
412 414 a
413 415 +a
414 416 record this change to 'subdir/a'? [Ynsfdaq?]
415 417 changeset: 18:33ff5c4fb017
416 418 tag: tip
417 419 user: test
418 420 date: Thu Jan 01 00:00:16 1970 +0000
419 421 summary: subdir-change
420 422
421 423 diff -r aecf2b2ea83c -r 33ff5c4fb017 subdir/a
422 424 --- a/subdir/a Thu Jan 01 00:00:16 1970 +0000
423 425 +++ b/subdir/a Thu Jan 01 00:00:16 1970 +0000
424 426 @@ -1,1 +1,2 @@
425 427 a
426 428 +a
427 429
428 430 % help, quit
429 431 diff --git a/subdir/f1 b/subdir/f1
430 432 1 hunks, 1 lines changed
431 433 examine changes to 'subdir/f1'? [Ynsfdaq?] y - record this change
432 434 n - skip this change
433 435 s - skip remaining changes to this file
434 436 f - record remaining changes to this file
435 437 d - done, skip remaining changes and files
436 438 a - record all changes to all remaining files
437 439 q - quit, recording no changes
438 440 ? - display help
439 441 examine changes to 'subdir/f1'? [Ynsfdaq?] abort: user quit
440 442 % skip
441 443 diff --git a/subdir/f1 b/subdir/f1
442 444 1 hunks, 1 lines changed
443 445 examine changes to 'subdir/f1'? [Ynsfdaq?] diff --git a/subdir/f2 b/subdir/f2
444 446 1 hunks, 1 lines changed
445 447 examine changes to 'subdir/f2'? [Ynsfdaq?] abort: response expected
446 448 % no
447 449 diff --git a/subdir/f1 b/subdir/f1
448 450 1 hunks, 1 lines changed
449 451 examine changes to 'subdir/f1'? [Ynsfdaq?] diff --git a/subdir/f2 b/subdir/f2
450 452 1 hunks, 1 lines changed
451 453 examine changes to 'subdir/f2'? [Ynsfdaq?] abort: response expected
452 454 % f, quit
453 455 diff --git a/subdir/f1 b/subdir/f1
454 456 1 hunks, 1 lines changed
455 457 examine changes to 'subdir/f1'? [Ynsfdaq?] diff --git a/subdir/f2 b/subdir/f2
456 458 1 hunks, 1 lines changed
457 459 examine changes to 'subdir/f2'? [Ynsfdaq?] abort: user quit
458 460 % s, all
459 461 diff --git a/subdir/f1 b/subdir/f1
460 462 1 hunks, 1 lines changed
461 463 examine changes to 'subdir/f1'? [Ynsfdaq?] diff --git a/subdir/f2 b/subdir/f2
462 464 1 hunks, 1 lines changed
463 465 examine changes to 'subdir/f2'? [Ynsfdaq?]
464 466 changeset: 20:094183e04b7c
465 467 tag: tip
466 468 user: test
467 469 date: Thu Jan 01 00:00:18 1970 +0000
468 470 summary: x
469 471
470 472 diff -r f9e855cd9374 -r 094183e04b7c subdir/f2
471 473 --- a/subdir/f2 Thu Jan 01 00:00:17 1970 +0000
472 474 +++ b/subdir/f2 Thu Jan 01 00:00:18 1970 +0000
473 475 @@ -1,1 +1,2 @@
474 476 b
475 477 +b
476 478
477 479 % f
478 480 diff --git a/subdir/f1 b/subdir/f1
479 481 1 hunks, 1 lines changed
480 482 examine changes to 'subdir/f1'? [Ynsfdaq?]
481 483 changeset: 21:38164785b0ef
482 484 tag: tip
483 485 user: test
484 486 date: Thu Jan 01 00:00:19 1970 +0000
485 487 summary: y
486 488
487 489 diff -r 094183e04b7c -r 38164785b0ef subdir/f1
488 490 --- a/subdir/f1 Thu Jan 01 00:00:18 1970 +0000
489 491 +++ b/subdir/f1 Thu Jan 01 00:00:19 1970 +0000
490 492 @@ -1,1 +1,2 @@
491 493 a
492 494 +a
493 495
General Comments 0
You need to be logged in to leave comments. Login now