##// END OF EJS Templates
generalize copy/rename to handle more than one source directory
Robin Farine -
r1512:53ad6ee6 default
parent child Browse files
Show More
@@ -0,0 +1,60 b''
1 #!/bin/sh
2
3 hg init
4 mkdir d1 d1/d11 d2
5 echo d1/a > d1/a
6 echo d1/ba > d1/ba
7 echo d1/a1 > d1/d11/a1
8 echo d1/b > d1/b
9 echo d2/b > d2/b
10 hg add d1/a d1/b d1/ba d1/d11/a1 d2/b
11 hg commit -m "1" -d "0 0"
12
13 echo "# rename a single file"
14 hg rename d1/d11/a1 d2/c
15 hg status
16 hg update -C
17
18 echo "# move a single file to an existing directory"
19 hg rename d1/d11/a1 d2
20 hg status
21 hg update -C
22
23 echo "# rename directory d1 as d3"
24 hg rename d1 d3
25 hg status
26 hg update -C
27
28 echo "# move directory d1/d11 to an existing directory d2 (removes empty d1)"
29 hg rename d1/d11 d2
30 hg status
31 hg update -C
32
33 echo "# move directories d1 and d2 to a new directory d3"
34 mkdir d3
35 hg rename d1 d2 d3
36 hg status
37 hg update -C
38
39 echo "# move everything under directory d1 to existing directory d2, do not"
40 echo "# overwrite existing files (d2/b)"
41 hg rename d1/* d2
42 hg status
43 diff d1/b d2/b
44 hg update -C
45
46 echo "# attempt to move potentially more than one file into a non-existent"
47 echo "# directory"
48 hg rename 'glob:d1/**' dx
49
50 echo "# move every file under d1 to d2/d21 (glob)"
51 mkdir d2/d21
52 hg rename 'glob:d1/**' d2/d21
53 hg status
54 hg update -C
55
56 echo "# move every file under d1 starting with an 'a' to d2/d21 (regexp)"
57 mkdir d2/d21
58 hg rename 're:d1/([^a][^/]*/)*a.*' d2/d21
59 hg status
60 hg update -C
@@ -0,0 +1,93 b''
1 # rename a single file
2 A d2/c
3 R d1/d11/a1
4 # move a single file to an existing directory
5 A d2/a1
6 R d1/d11/a1
7 # rename directory d1 as d3
8 copying d1/a to d3/a
9 copying d1/b to d3/b
10 copying d1/ba to d3/ba
11 copying d1/d11/a1 to d3/d11/a1
12 removing d1/a
13 removing d1/b
14 removing d1/ba
15 removing d1/d11/a1
16 A d3/a
17 A d3/b
18 A d3/ba
19 A d3/d11/a1
20 R d1/a
21 R d1/b
22 R d1/ba
23 R d1/d11/a1
24 # move directory d1/d11 to an existing directory d2 (removes empty d1)
25 copying d1/d11/a1 to d2/d11/a1
26 removing d1/d11/a1
27 A d2/d11/a1
28 R d1/d11/a1
29 # move directories d1 and d2 to a new directory d3
30 copying d1/a to d3/d1/a
31 copying d1/b to d3/d1/b
32 copying d1/ba to d3/d1/ba
33 copying d1/d11/a1 to d3/d1/d11/a1
34 copying d2/b to d3/d2/b
35 removing d1/a
36 removing d1/b
37 removing d1/ba
38 removing d1/d11/a1
39 removing d2/b
40 A d3/d1/a
41 A d3/d1/b
42 A d3/d1/ba
43 A d3/d1/d11/a1
44 A d3/d2/b
45 R d1/a
46 R d1/b
47 R d1/ba
48 R d1/d11/a1
49 R d2/b
50 # move everything under directory d1 to existing directory d2, do not
51 # overwrite existing files (d2/b)
52 d2/b: not overwriting - file already managed
53 copying d1/d11/a1 to d2/d11/a1
54 removing d1/d11/a1
55 A d2/a
56 A d2/ba
57 A d2/d11/a1
58 R d1/a
59 R d1/ba
60 R d1/d11/a1
61 1c1
62 < d1/b
63 ---
64 > d2/b
65 # attempt to move potentially more than one file into a non-existent
66 # directory
67 abort: with multiple sources, destination must be an existing directory
68 # move every file under d1 to d2/d21 (glob)
69 copying d1/a to d2/d21/a
70 copying d1/b to d2/d21/b
71 copying d1/ba to d2/d21/ba
72 copying d1/d11/a1 to d2/d21/a1
73 removing d1/a
74 removing d1/b
75 removing d1/ba
76 removing d1/d11/a1
77 A d2/d21/a
78 A d2/d21/a1
79 A d2/d21/b
80 A d2/d21/ba
81 R d1/a
82 R d1/b
83 R d1/ba
84 R d1/d11/a1
85 # move every file under d1 starting with an 'a' to d2/d21 (regexp)
86 copying d1/a to d2/d21/a
87 copying d1/d11/a1 to d2/d21/a1
88 removing d1/a
89 removing d1/d11/a1
90 A d2/d21/a
91 A d2/d21/a1
92 R d1/a
93 R d1/d11/a1
@@ -1,2634 +1,2623 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18
18
19 def filterfiles(filters, files):
19 def filterfiles(filters, files):
20 l = [x for x in files if x in filters]
20 l = [x for x in files if x in filters]
21
21
22 for t in filters:
22 for t in filters:
23 if t and t[-1] != "/":
23 if t and t[-1] != "/":
24 t += "/"
24 t += "/"
25 l += [x for x in files if x.startswith(t)]
25 l += [x for x in files if x.startswith(t)]
26 return l
26 return l
27
27
28 def relpath(repo, args):
28 def relpath(repo, args):
29 cwd = repo.getcwd()
29 cwd = repo.getcwd()
30 if cwd:
30 if cwd:
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 return args
32 return args
33
33
34 def matchpats(repo, cwd, pats=[], opts={}, head=''):
34 def matchpats(repo, cwd, pats=[], opts={}, head=''):
35 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
35 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
36 opts.get('exclude'), head)
36 opts.get('exclude'), head)
37
37
38 def makewalk(repo, pats, opts, head=''):
38 def makewalk(repo, pats, opts, head=''):
39 cwd = repo.getcwd()
39 cwd = repo.getcwd()
40 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
40 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
41 exact = dict(zip(files, files))
41 exact = dict(zip(files, files))
42 def walk():
42 def walk():
43 for src, fn in repo.walk(files=files, match=matchfn):
43 for src, fn in repo.walk(files=files, match=matchfn):
44 yield src, fn, util.pathto(cwd, fn), fn in exact
44 yield src, fn, util.pathto(cwd, fn), fn in exact
45 return files, matchfn, walk()
45 return files, matchfn, walk()
46
46
47 def walk(repo, pats, opts, head=''):
47 def walk(repo, pats, opts, head=''):
48 files, matchfn, results = makewalk(repo, pats, opts, head)
48 files, matchfn, results = makewalk(repo, pats, opts, head)
49 for r in results:
49 for r in results:
50 yield r
50 yield r
51
51
52 def walkchangerevs(ui, repo, cwd, pats, opts):
52 def walkchangerevs(ui, repo, cwd, pats, opts):
53 '''Iterate over files and the revs they changed in.
53 '''Iterate over files and the revs they changed in.
54
54
55 Callers most commonly need to iterate backwards over the history
55 Callers most commonly need to iterate backwards over the history
56 it is interested in. Doing so has awful (quadratic-looking)
56 it is interested in. Doing so has awful (quadratic-looking)
57 performance, so we use iterators in a "windowed" way.
57 performance, so we use iterators in a "windowed" way.
58
58
59 We walk a window of revisions in the desired order. Within the
59 We walk a window of revisions in the desired order. Within the
60 window, we first walk forwards to gather data, then in the desired
60 window, we first walk forwards to gather data, then in the desired
61 order (usually backwards) to display it.
61 order (usually backwards) to display it.
62
62
63 This function returns an (iterator, getchange) pair. The
63 This function returns an (iterator, getchange) pair. The
64 getchange function returns the changelog entry for a numeric
64 getchange function returns the changelog entry for a numeric
65 revision. The iterator yields 3-tuples. They will be of one of
65 revision. The iterator yields 3-tuples. They will be of one of
66 the following forms:
66 the following forms:
67
67
68 "window", incrementing, lastrev: stepping through a window,
68 "window", incrementing, lastrev: stepping through a window,
69 positive if walking forwards through revs, last rev in the
69 positive if walking forwards through revs, last rev in the
70 sequence iterated over - use to reset state for the current window
70 sequence iterated over - use to reset state for the current window
71
71
72 "add", rev, fns: out-of-order traversal of the given file names
72 "add", rev, fns: out-of-order traversal of the given file names
73 fns, which changed during revision rev - use to gather data for
73 fns, which changed during revision rev - use to gather data for
74 possible display
74 possible display
75
75
76 "iter", rev, None: in-order traversal of the revs earlier iterated
76 "iter", rev, None: in-order traversal of the revs earlier iterated
77 over with "add" - use to display data'''
77 over with "add" - use to display data'''
78
78
79 if repo.changelog.count() == 0:
79 if repo.changelog.count() == 0:
80 return [], False
80 return [], False
81
81
82 cwd = repo.getcwd()
82 cwd = repo.getcwd()
83 if not pats and cwd:
83 if not pats and cwd:
84 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
84 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
85 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
85 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
86 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
86 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
87 pats, opts)
87 pats, opts)
88 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
88 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
89 wanted = {}
89 wanted = {}
90 slowpath = anypats
90 slowpath = anypats
91 window = 300
91 window = 300
92 fncache = {}
92 fncache = {}
93
93
94 chcache = {}
94 chcache = {}
95 def getchange(rev):
95 def getchange(rev):
96 ch = chcache.get(rev)
96 ch = chcache.get(rev)
97 if ch is None:
97 if ch is None:
98 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
98 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
99 return ch
99 return ch
100
100
101 if not slowpath and not files:
101 if not slowpath and not files:
102 # No files, no patterns. Display all revs.
102 # No files, no patterns. Display all revs.
103 wanted = dict(zip(revs, revs))
103 wanted = dict(zip(revs, revs))
104 if not slowpath:
104 if not slowpath:
105 # Only files, no patterns. Check the history of each file.
105 # Only files, no patterns. Check the history of each file.
106 def filerevgen(filelog):
106 def filerevgen(filelog):
107 for i in xrange(filelog.count() - 1, -1, -window):
107 for i in xrange(filelog.count() - 1, -1, -window):
108 revs = []
108 revs = []
109 for j in xrange(max(0, i - window), i + 1):
109 for j in xrange(max(0, i - window), i + 1):
110 revs.append(filelog.linkrev(filelog.node(j)))
110 revs.append(filelog.linkrev(filelog.node(j)))
111 revs.reverse()
111 revs.reverse()
112 for rev in revs:
112 for rev in revs:
113 yield rev
113 yield rev
114
114
115 minrev, maxrev = min(revs), max(revs)
115 minrev, maxrev = min(revs), max(revs)
116 for file in files:
116 for file in files:
117 filelog = repo.file(file)
117 filelog = repo.file(file)
118 # A zero count may be a directory or deleted file, so
118 # A zero count may be a directory or deleted file, so
119 # try to find matching entries on the slow path.
119 # try to find matching entries on the slow path.
120 if filelog.count() == 0:
120 if filelog.count() == 0:
121 slowpath = True
121 slowpath = True
122 break
122 break
123 for rev in filerevgen(filelog):
123 for rev in filerevgen(filelog):
124 if rev <= maxrev:
124 if rev <= maxrev:
125 if rev < minrev:
125 if rev < minrev:
126 break
126 break
127 fncache.setdefault(rev, [])
127 fncache.setdefault(rev, [])
128 fncache[rev].append(file)
128 fncache[rev].append(file)
129 wanted[rev] = 1
129 wanted[rev] = 1
130 if slowpath:
130 if slowpath:
131 # The slow path checks files modified in every changeset.
131 # The slow path checks files modified in every changeset.
132 def changerevgen():
132 def changerevgen():
133 for i in xrange(repo.changelog.count() - 1, -1, -window):
133 for i in xrange(repo.changelog.count() - 1, -1, -window):
134 for j in xrange(max(0, i - window), i + 1):
134 for j in xrange(max(0, i - window), i + 1):
135 yield j, getchange(j)[3]
135 yield j, getchange(j)[3]
136
136
137 for rev, changefiles in changerevgen():
137 for rev, changefiles in changerevgen():
138 matches = filter(matchfn, changefiles)
138 matches = filter(matchfn, changefiles)
139 if matches:
139 if matches:
140 fncache[rev] = matches
140 fncache[rev] = matches
141 wanted[rev] = 1
141 wanted[rev] = 1
142
142
143 def iterate():
143 def iterate():
144 for i in xrange(0, len(revs), window):
144 for i in xrange(0, len(revs), window):
145 yield 'window', revs[0] < revs[-1], revs[-1]
145 yield 'window', revs[0] < revs[-1], revs[-1]
146 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
146 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
147 if rev in wanted]
147 if rev in wanted]
148 srevs = list(nrevs)
148 srevs = list(nrevs)
149 srevs.sort()
149 srevs.sort()
150 for rev in srevs:
150 for rev in srevs:
151 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
151 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
152 yield 'add', rev, fns
152 yield 'add', rev, fns
153 for rev in nrevs:
153 for rev in nrevs:
154 yield 'iter', rev, None
154 yield 'iter', rev, None
155 return iterate(), getchange
155 return iterate(), getchange
156
156
157 revrangesep = ':'
157 revrangesep = ':'
158
158
159 def revrange(ui, repo, revs, revlog=None):
159 def revrange(ui, repo, revs, revlog=None):
160 """Yield revision as strings from a list of revision specifications."""
160 """Yield revision as strings from a list of revision specifications."""
161 if revlog is None:
161 if revlog is None:
162 revlog = repo.changelog
162 revlog = repo.changelog
163 revcount = revlog.count()
163 revcount = revlog.count()
164 def fix(val, defval):
164 def fix(val, defval):
165 if not val:
165 if not val:
166 return defval
166 return defval
167 try:
167 try:
168 num = int(val)
168 num = int(val)
169 if str(num) != val:
169 if str(num) != val:
170 raise ValueError
170 raise ValueError
171 if num < 0: num += revcount
171 if num < 0: num += revcount
172 if num < 0: num = 0
172 if num < 0: num = 0
173 elif num >= revcount:
173 elif num >= revcount:
174 raise ValueError
174 raise ValueError
175 except ValueError:
175 except ValueError:
176 try:
176 try:
177 num = repo.changelog.rev(repo.lookup(val))
177 num = repo.changelog.rev(repo.lookup(val))
178 except KeyError:
178 except KeyError:
179 try:
179 try:
180 num = revlog.rev(revlog.lookup(val))
180 num = revlog.rev(revlog.lookup(val))
181 except KeyError:
181 except KeyError:
182 raise util.Abort(_('invalid revision identifier %s'), val)
182 raise util.Abort(_('invalid revision identifier %s'), val)
183 return num
183 return num
184 seen = {}
184 seen = {}
185 for spec in revs:
185 for spec in revs:
186 if spec.find(revrangesep) >= 0:
186 if spec.find(revrangesep) >= 0:
187 start, end = spec.split(revrangesep, 1)
187 start, end = spec.split(revrangesep, 1)
188 start = fix(start, 0)
188 start = fix(start, 0)
189 end = fix(end, revcount - 1)
189 end = fix(end, revcount - 1)
190 step = start > end and -1 or 1
190 step = start > end and -1 or 1
191 for rev in xrange(start, end+step, step):
191 for rev in xrange(start, end+step, step):
192 if rev in seen: continue
192 if rev in seen: continue
193 seen[rev] = 1
193 seen[rev] = 1
194 yield str(rev)
194 yield str(rev)
195 else:
195 else:
196 rev = fix(spec, None)
196 rev = fix(spec, None)
197 if rev in seen: continue
197 if rev in seen: continue
198 seen[rev] = 1
198 seen[rev] = 1
199 yield str(rev)
199 yield str(rev)
200
200
201 def make_filename(repo, r, pat, node=None,
201 def make_filename(repo, r, pat, node=None,
202 total=None, seqno=None, revwidth=None, pathname=None):
202 total=None, seqno=None, revwidth=None, pathname=None):
203 node_expander = {
203 node_expander = {
204 'H': lambda: hex(node),
204 'H': lambda: hex(node),
205 'R': lambda: str(r.rev(node)),
205 'R': lambda: str(r.rev(node)),
206 'h': lambda: short(node),
206 'h': lambda: short(node),
207 }
207 }
208 expander = {
208 expander = {
209 '%': lambda: '%',
209 '%': lambda: '%',
210 'b': lambda: os.path.basename(repo.root),
210 'b': lambda: os.path.basename(repo.root),
211 }
211 }
212
212
213 try:
213 try:
214 if node:
214 if node:
215 expander.update(node_expander)
215 expander.update(node_expander)
216 if node and revwidth is not None:
216 if node and revwidth is not None:
217 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
217 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
218 if total is not None:
218 if total is not None:
219 expander['N'] = lambda: str(total)
219 expander['N'] = lambda: str(total)
220 if seqno is not None:
220 if seqno is not None:
221 expander['n'] = lambda: str(seqno)
221 expander['n'] = lambda: str(seqno)
222 if total is not None and seqno is not None:
222 if total is not None and seqno is not None:
223 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
223 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
224 if pathname is not None:
224 if pathname is not None:
225 expander['s'] = lambda: os.path.basename(pathname)
225 expander['s'] = lambda: os.path.basename(pathname)
226 expander['d'] = lambda: os.path.dirname(pathname) or '.'
226 expander['d'] = lambda: os.path.dirname(pathname) or '.'
227 expander['p'] = lambda: pathname
227 expander['p'] = lambda: pathname
228
228
229 newname = []
229 newname = []
230 patlen = len(pat)
230 patlen = len(pat)
231 i = 0
231 i = 0
232 while i < patlen:
232 while i < patlen:
233 c = pat[i]
233 c = pat[i]
234 if c == '%':
234 if c == '%':
235 i += 1
235 i += 1
236 c = pat[i]
236 c = pat[i]
237 c = expander[c]()
237 c = expander[c]()
238 newname.append(c)
238 newname.append(c)
239 i += 1
239 i += 1
240 return ''.join(newname)
240 return ''.join(newname)
241 except KeyError, inst:
241 except KeyError, inst:
242 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
242 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
243 inst.args[0])
243 inst.args[0])
244
244
245 def make_file(repo, r, pat, node=None,
245 def make_file(repo, r, pat, node=None,
246 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
246 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
247 if not pat or pat == '-':
247 if not pat or pat == '-':
248 return 'w' in mode and sys.stdout or sys.stdin
248 return 'w' in mode and sys.stdout or sys.stdin
249 if hasattr(pat, 'write') and 'w' in mode:
249 if hasattr(pat, 'write') and 'w' in mode:
250 return pat
250 return pat
251 if hasattr(pat, 'read') and 'r' in mode:
251 if hasattr(pat, 'read') and 'r' in mode:
252 return pat
252 return pat
253 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
253 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
254 pathname),
254 pathname),
255 mode)
255 mode)
256
256
257 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
257 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
258 changes=None, text=False):
258 changes=None, text=False):
259 if not changes:
259 if not changes:
260 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
260 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
261 else:
261 else:
262 (c, a, d, u) = changes
262 (c, a, d, u) = changes
263 if files:
263 if files:
264 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
264 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
265
265
266 if not c and not a and not d:
266 if not c and not a and not d:
267 return
267 return
268
268
269 if node2:
269 if node2:
270 change = repo.changelog.read(node2)
270 change = repo.changelog.read(node2)
271 mmap2 = repo.manifest.read(change[0])
271 mmap2 = repo.manifest.read(change[0])
272 date2 = util.datestr(change[2])
272 date2 = util.datestr(change[2])
273 def read(f):
273 def read(f):
274 return repo.file(f).read(mmap2[f])
274 return repo.file(f).read(mmap2[f])
275 else:
275 else:
276 date2 = util.datestr()
276 date2 = util.datestr()
277 if not node1:
277 if not node1:
278 node1 = repo.dirstate.parents()[0]
278 node1 = repo.dirstate.parents()[0]
279 def read(f):
279 def read(f):
280 return repo.wfile(f).read()
280 return repo.wfile(f).read()
281
281
282 if ui.quiet:
282 if ui.quiet:
283 r = None
283 r = None
284 else:
284 else:
285 hexfunc = ui.verbose and hex or short
285 hexfunc = ui.verbose and hex or short
286 r = [hexfunc(node) for node in [node1, node2] if node]
286 r = [hexfunc(node) for node in [node1, node2] if node]
287
287
288 change = repo.changelog.read(node1)
288 change = repo.changelog.read(node1)
289 mmap = repo.manifest.read(change[0])
289 mmap = repo.manifest.read(change[0])
290 date1 = util.datestr(change[2])
290 date1 = util.datestr(change[2])
291
291
292 for f in c:
292 for f in c:
293 to = None
293 to = None
294 if f in mmap:
294 if f in mmap:
295 to = repo.file(f).read(mmap[f])
295 to = repo.file(f).read(mmap[f])
296 tn = read(f)
296 tn = read(f)
297 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
297 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
298 for f in a:
298 for f in a:
299 to = None
299 to = None
300 tn = read(f)
300 tn = read(f)
301 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
301 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
302 for f in d:
302 for f in d:
303 to = repo.file(f).read(mmap[f])
303 to = repo.file(f).read(mmap[f])
304 tn = None
304 tn = None
305 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
305 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
306
306
307 def trimuser(ui, name, rev, revcache):
307 def trimuser(ui, name, rev, revcache):
308 """trim the name of the user who committed a change"""
308 """trim the name of the user who committed a change"""
309 user = revcache.get(rev)
309 user = revcache.get(rev)
310 if user is None:
310 if user is None:
311 user = revcache[rev] = ui.shortuser(name)
311 user = revcache[rev] = ui.shortuser(name)
312 return user
312 return user
313
313
314 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
314 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
315 """show a single changeset or file revision"""
315 """show a single changeset or file revision"""
316 log = repo.changelog
316 log = repo.changelog
317 if changenode is None:
317 if changenode is None:
318 changenode = log.node(rev)
318 changenode = log.node(rev)
319 elif not rev:
319 elif not rev:
320 rev = log.rev(changenode)
320 rev = log.rev(changenode)
321
321
322 if ui.quiet:
322 if ui.quiet:
323 ui.write("%d:%s\n" % (rev, short(changenode)))
323 ui.write("%d:%s\n" % (rev, short(changenode)))
324 return
324 return
325
325
326 changes = log.read(changenode)
326 changes = log.read(changenode)
327 date = util.datestr(changes[2])
327 date = util.datestr(changes[2])
328
328
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
330 for p in log.parents(changenode)
330 for p in log.parents(changenode)
331 if ui.debugflag or p != nullid]
331 if ui.debugflag or p != nullid]
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
333 parents = []
333 parents = []
334
334
335 if ui.verbose:
335 if ui.verbose:
336 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
336 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
337 else:
337 else:
338 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
338 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
339
339
340 for tag in repo.nodetags(changenode):
340 for tag in repo.nodetags(changenode):
341 ui.status(_("tag: %s\n") % tag)
341 ui.status(_("tag: %s\n") % tag)
342 for parent in parents:
342 for parent in parents:
343 ui.write(_("parent: %d:%s\n") % parent)
343 ui.write(_("parent: %d:%s\n") % parent)
344
344
345 if brinfo and changenode in brinfo:
345 if brinfo and changenode in brinfo:
346 br = brinfo[changenode]
346 br = brinfo[changenode]
347 ui.write(_("branch: %s\n") % " ".join(br))
347 ui.write(_("branch: %s\n") % " ".join(br))
348
348
349 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
349 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
350 hex(changes[0])))
350 hex(changes[0])))
351 ui.status(_("user: %s\n") % changes[1])
351 ui.status(_("user: %s\n") % changes[1])
352 ui.status(_("date: %s\n") % date)
352 ui.status(_("date: %s\n") % date)
353
353
354 if ui.debugflag:
354 if ui.debugflag:
355 files = repo.changes(log.parents(changenode)[0], changenode)
355 files = repo.changes(log.parents(changenode)[0], changenode)
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
357 if value:
357 if value:
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
359 else:
359 else:
360 ui.note(_("files: %s\n") % " ".join(changes[3]))
360 ui.note(_("files: %s\n") % " ".join(changes[3]))
361
361
362 description = changes[4].strip()
362 description = changes[4].strip()
363 if description:
363 if description:
364 if ui.verbose:
364 if ui.verbose:
365 ui.status(_("description:\n"))
365 ui.status(_("description:\n"))
366 ui.status(description)
366 ui.status(description)
367 ui.status("\n\n")
367 ui.status("\n\n")
368 else:
368 else:
369 ui.status(_("summary: %s\n") % description.splitlines()[0])
369 ui.status(_("summary: %s\n") % description.splitlines()[0])
370 ui.status("\n")
370 ui.status("\n")
371
371
372 def show_version(ui):
372 def show_version(ui):
373 """output version and copyright information"""
373 """output version and copyright information"""
374 ui.write(_("Mercurial Distributed SCM (version %s)\n")
374 ui.write(_("Mercurial Distributed SCM (version %s)\n")
375 % version.get_version())
375 % version.get_version())
376 ui.status(_(
376 ui.status(_(
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
378 "This is free software; see the source for copying conditions. "
378 "This is free software; see the source for copying conditions. "
379 "There is NO\nwarranty; "
379 "There is NO\nwarranty; "
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
381 ))
381 ))
382
382
383 def help_(ui, cmd=None, with_version=False):
383 def help_(ui, cmd=None, with_version=False):
384 """show help for a given command or all commands"""
384 """show help for a given command or all commands"""
385 option_lists = []
385 option_lists = []
386 if cmd and cmd != 'shortlist':
386 if cmd and cmd != 'shortlist':
387 if with_version:
387 if with_version:
388 show_version(ui)
388 show_version(ui)
389 ui.write('\n')
389 ui.write('\n')
390 key, i = find(cmd)
390 key, i = find(cmd)
391 # synopsis
391 # synopsis
392 ui.write("%s\n\n" % i[2])
392 ui.write("%s\n\n" % i[2])
393
393
394 # description
394 # description
395 doc = i[0].__doc__
395 doc = i[0].__doc__
396 if ui.quiet:
396 if ui.quiet:
397 doc = doc.splitlines(0)[0]
397 doc = doc.splitlines(0)[0]
398 ui.write("%s\n" % doc.rstrip())
398 ui.write("%s\n" % doc.rstrip())
399
399
400 if not ui.quiet:
400 if not ui.quiet:
401 # aliases
401 # aliases
402 aliases = ', '.join(key.split('|')[1:])
402 aliases = ', '.join(key.split('|')[1:])
403 if aliases:
403 if aliases:
404 ui.write(_("\naliases: %s\n") % aliases)
404 ui.write(_("\naliases: %s\n") % aliases)
405
405
406 # options
406 # options
407 if i[1]:
407 if i[1]:
408 option_lists.append(("options", i[1]))
408 option_lists.append(("options", i[1]))
409
409
410 else:
410 else:
411 # program name
411 # program name
412 if ui.verbose or with_version:
412 if ui.verbose or with_version:
413 show_version(ui)
413 show_version(ui)
414 else:
414 else:
415 ui.status(_("Mercurial Distributed SCM\n"))
415 ui.status(_("Mercurial Distributed SCM\n"))
416 ui.status('\n')
416 ui.status('\n')
417
417
418 # list of commands
418 # list of commands
419 if cmd == "shortlist":
419 if cmd == "shortlist":
420 ui.status(_('basic commands (use "hg help" '
420 ui.status(_('basic commands (use "hg help" '
421 'for the full list or option "-v" for details):\n\n'))
421 'for the full list or option "-v" for details):\n\n'))
422 elif ui.verbose:
422 elif ui.verbose:
423 ui.status(_('list of commands:\n\n'))
423 ui.status(_('list of commands:\n\n'))
424 else:
424 else:
425 ui.status(_('list of commands (use "hg help -v" '
425 ui.status(_('list of commands (use "hg help -v" '
426 'to show aliases and global options):\n\n'))
426 'to show aliases and global options):\n\n'))
427
427
428 h = {}
428 h = {}
429 cmds = {}
429 cmds = {}
430 for c, e in table.items():
430 for c, e in table.items():
431 f = c.split("|")[0]
431 f = c.split("|")[0]
432 if cmd == "shortlist" and not f.startswith("^"):
432 if cmd == "shortlist" and not f.startswith("^"):
433 continue
433 continue
434 f = f.lstrip("^")
434 f = f.lstrip("^")
435 if not ui.debugflag and f.startswith("debug"):
435 if not ui.debugflag and f.startswith("debug"):
436 continue
436 continue
437 d = ""
437 d = ""
438 if e[0].__doc__:
438 if e[0].__doc__:
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
440 h[f] = d
440 h[f] = d
441 cmds[f]=c.lstrip("^")
441 cmds[f]=c.lstrip("^")
442
442
443 fns = h.keys()
443 fns = h.keys()
444 fns.sort()
444 fns.sort()
445 m = max(map(len, fns))
445 m = max(map(len, fns))
446 for f in fns:
446 for f in fns:
447 if ui.verbose:
447 if ui.verbose:
448 commands = cmds[f].replace("|",", ")
448 commands = cmds[f].replace("|",", ")
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
450 else:
450 else:
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
452
452
453 # global options
453 # global options
454 if ui.verbose:
454 if ui.verbose:
455 option_lists.append(("global options", globalopts))
455 option_lists.append(("global options", globalopts))
456
456
457 # list all option lists
457 # list all option lists
458 opt_output = []
458 opt_output = []
459 for title, options in option_lists:
459 for title, options in option_lists:
460 opt_output.append(("\n%s:\n" % title, None))
460 opt_output.append(("\n%s:\n" % title, None))
461 for shortopt, longopt, default, desc in options:
461 for shortopt, longopt, default, desc in options:
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
463 longopt and " --%s" % longopt),
463 longopt and " --%s" % longopt),
464 "%s%s" % (desc,
464 "%s%s" % (desc,
465 default and _(" (default: %s)") % default
465 default and _(" (default: %s)") % default
466 or "")))
466 or "")))
467
467
468 if opt_output:
468 if opt_output:
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
470 for first, second in opt_output:
470 for first, second in opt_output:
471 if second:
471 if second:
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
473 else:
473 else:
474 ui.write("%s\n" % first)
474 ui.write("%s\n" % first)
475
475
476 # Commands start here, listed alphabetically
476 # Commands start here, listed alphabetically
477
477
478 def add(ui, repo, *pats, **opts):
478 def add(ui, repo, *pats, **opts):
479 """add the specified files on the next commit
479 """add the specified files on the next commit
480
480
481 Schedule files to be version controlled and added to the repository.
481 Schedule files to be version controlled and added to the repository.
482
482
483 The files will be added to the repository at the next commit.
483 The files will be added to the repository at the next commit.
484
484
485 If no names are given, add all files in the current directory and
485 If no names are given, add all files in the current directory and
486 its subdirectories.
486 its subdirectories.
487 """
487 """
488
488
489 names = []
489 names = []
490 for src, abs, rel, exact in walk(repo, pats, opts):
490 for src, abs, rel, exact in walk(repo, pats, opts):
491 if exact:
491 if exact:
492 if ui.verbose: ui.status(_('adding %s\n') % rel)
492 if ui.verbose: ui.status(_('adding %s\n') % rel)
493 names.append(abs)
493 names.append(abs)
494 elif repo.dirstate.state(abs) == '?':
494 elif repo.dirstate.state(abs) == '?':
495 ui.status(_('adding %s\n') % rel)
495 ui.status(_('adding %s\n') % rel)
496 names.append(abs)
496 names.append(abs)
497 repo.add(names)
497 repo.add(names)
498
498
499 def addremove(ui, repo, *pats, **opts):
499 def addremove(ui, repo, *pats, **opts):
500 """add all new files, delete all missing files
500 """add all new files, delete all missing files
501
501
502 Add all new files and remove all missing files from the repository.
502 Add all new files and remove all missing files from the repository.
503
503
504 New files are ignored if they match any of the patterns in .hgignore. As
504 New files are ignored if they match any of the patterns in .hgignore. As
505 with add, these changes take effect at the next commit.
505 with add, these changes take effect at the next commit.
506 """
506 """
507 add, remove = [], []
507 add, remove = [], []
508 for src, abs, rel, exact in walk(repo, pats, opts):
508 for src, abs, rel, exact in walk(repo, pats, opts):
509 if src == 'f' and repo.dirstate.state(abs) == '?':
509 if src == 'f' and repo.dirstate.state(abs) == '?':
510 add.append(abs)
510 add.append(abs)
511 if ui.verbose or not exact:
511 if ui.verbose or not exact:
512 ui.status(_('adding %s\n') % rel)
512 ui.status(_('adding %s\n') % rel)
513 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
513 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
514 remove.append(abs)
514 remove.append(abs)
515 if ui.verbose or not exact:
515 if ui.verbose or not exact:
516 ui.status(_('removing %s\n') % rel)
516 ui.status(_('removing %s\n') % rel)
517 repo.add(add)
517 repo.add(add)
518 repo.remove(remove)
518 repo.remove(remove)
519
519
520 def annotate(ui, repo, *pats, **opts):
520 def annotate(ui, repo, *pats, **opts):
521 """show changeset information per file line
521 """show changeset information per file line
522
522
523 List changes in files, showing the revision id responsible for each line
523 List changes in files, showing the revision id responsible for each line
524
524
525 This command is useful to discover who did a change or when a change took
525 This command is useful to discover who did a change or when a change took
526 place.
526 place.
527
527
528 Without the -a option, annotate will avoid processing files it
528 Without the -a option, annotate will avoid processing files it
529 detects as binary. With -a, annotate will generate an annotation
529 detects as binary. With -a, annotate will generate an annotation
530 anyway, probably with undesirable results.
530 anyway, probably with undesirable results.
531 """
531 """
532 def getnode(rev):
532 def getnode(rev):
533 return short(repo.changelog.node(rev))
533 return short(repo.changelog.node(rev))
534
534
535 ucache = {}
535 ucache = {}
536 def getname(rev):
536 def getname(rev):
537 cl = repo.changelog.read(repo.changelog.node(rev))
537 cl = repo.changelog.read(repo.changelog.node(rev))
538 return trimuser(ui, cl[1], rev, ucache)
538 return trimuser(ui, cl[1], rev, ucache)
539
539
540 if not pats:
540 if not pats:
541 raise util.Abort(_('at least one file name or pattern required'))
541 raise util.Abort(_('at least one file name or pattern required'))
542
542
543 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
543 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
544 if not opts['user'] and not opts['changeset']:
544 if not opts['user'] and not opts['changeset']:
545 opts['number'] = 1
545 opts['number'] = 1
546
546
547 if opts['rev']:
547 if opts['rev']:
548 node = repo.changelog.lookup(opts['rev'])
548 node = repo.changelog.lookup(opts['rev'])
549 else:
549 else:
550 node = repo.dirstate.parents()[0]
550 node = repo.dirstate.parents()[0]
551 change = repo.changelog.read(node)
551 change = repo.changelog.read(node)
552 mmap = repo.manifest.read(change[0])
552 mmap = repo.manifest.read(change[0])
553
553
554 for src, abs, rel, exact in walk(repo, pats, opts):
554 for src, abs, rel, exact in walk(repo, pats, opts):
555 if abs not in mmap:
555 if abs not in mmap:
556 ui.warn(_("warning: %s is not in the repository!\n") % rel)
556 ui.warn(_("warning: %s is not in the repository!\n") % rel)
557 continue
557 continue
558
558
559 f = repo.file(abs)
559 f = repo.file(abs)
560 if not opts['text'] and util.binary(f.read(mmap[abs])):
560 if not opts['text'] and util.binary(f.read(mmap[abs])):
561 ui.write(_("%s: binary file\n") % rel)
561 ui.write(_("%s: binary file\n") % rel)
562 continue
562 continue
563
563
564 lines = f.annotate(mmap[abs])
564 lines = f.annotate(mmap[abs])
565 pieces = []
565 pieces = []
566
566
567 for o, f in opmap:
567 for o, f in opmap:
568 if opts[o]:
568 if opts[o]:
569 l = [f(n) for n, dummy in lines]
569 l = [f(n) for n, dummy in lines]
570 if l:
570 if l:
571 m = max(map(len, l))
571 m = max(map(len, l))
572 pieces.append(["%*s" % (m, x) for x in l])
572 pieces.append(["%*s" % (m, x) for x in l])
573
573
574 if pieces:
574 if pieces:
575 for p, l in zip(zip(*pieces), lines):
575 for p, l in zip(zip(*pieces), lines):
576 ui.write("%s: %s" % (" ".join(p), l[1]))
576 ui.write("%s: %s" % (" ".join(p), l[1]))
577
577
578 def bundle(ui, repo, fname, dest="default-push", **opts):
578 def bundle(ui, repo, fname, dest="default-push", **opts):
579 """create a changegroup file
579 """create a changegroup file
580
580
581 Generate a compressed changegroup file collecting all changesets
581 Generate a compressed changegroup file collecting all changesets
582 not found in the other repository.
582 not found in the other repository.
583
583
584 This file can then be transferred using conventional means and
584 This file can then be transferred using conventional means and
585 applied to another repository with the unbundle command. This is
585 applied to another repository with the unbundle command. This is
586 useful when native push and pull are not available or when
586 useful when native push and pull are not available or when
587 exporting an entire repository is undesirable. The standard file
587 exporting an entire repository is undesirable. The standard file
588 extension is ".hg".
588 extension is ".hg".
589
589
590 Unlike import/export, this exactly preserves all changeset
590 Unlike import/export, this exactly preserves all changeset
591 contents including permissions, rename data, and revision history.
591 contents including permissions, rename data, and revision history.
592 """
592 """
593 f = open(fname, "wb")
593 f = open(fname, "wb")
594 dest = ui.expandpath(dest, repo.root)
594 dest = ui.expandpath(dest, repo.root)
595 other = hg.repository(ui, dest)
595 other = hg.repository(ui, dest)
596 o = repo.findoutgoing(other)
596 o = repo.findoutgoing(other)
597 cg = repo.changegroup(o)
597 cg = repo.changegroup(o)
598
598
599 try:
599 try:
600 f.write("HG10")
600 f.write("HG10")
601 z = bz2.BZ2Compressor(9)
601 z = bz2.BZ2Compressor(9)
602 while 1:
602 while 1:
603 chunk = cg.read(4096)
603 chunk = cg.read(4096)
604 if not chunk:
604 if not chunk:
605 break
605 break
606 f.write(z.compress(chunk))
606 f.write(z.compress(chunk))
607 f.write(z.flush())
607 f.write(z.flush())
608 except:
608 except:
609 os.unlink(fname)
609 os.unlink(fname)
610 raise
610 raise
611
611
612 def cat(ui, repo, file1, *pats, **opts):
612 def cat(ui, repo, file1, *pats, **opts):
613 """output the latest or given revisions of files
613 """output the latest or given revisions of files
614
614
615 Print the specified files as they were at the given revision.
615 Print the specified files as they were at the given revision.
616 If no revision is given then the tip is used.
616 If no revision is given then the tip is used.
617
617
618 Output may be to a file, in which case the name of the file is
618 Output may be to a file, in which case the name of the file is
619 given using a format string. The formatting rules are the same as
619 given using a format string. The formatting rules are the same as
620 for the export command, with the following additions:
620 for the export command, with the following additions:
621
621
622 %s basename of file being printed
622 %s basename of file being printed
623 %d dirname of file being printed, or '.' if in repo root
623 %d dirname of file being printed, or '.' if in repo root
624 %p root-relative path name of file being printed
624 %p root-relative path name of file being printed
625 """
625 """
626 mf = {}
626 mf = {}
627 if opts['rev']:
627 if opts['rev']:
628 change = repo.changelog.read(repo.lookup(opts['rev']))
628 change = repo.changelog.read(repo.lookup(opts['rev']))
629 mf = repo.manifest.read(change[0])
629 mf = repo.manifest.read(change[0])
630 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
630 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
631 r = repo.file(abs)
631 r = repo.file(abs)
632 if opts['rev']:
632 if opts['rev']:
633 try:
633 try:
634 n = mf[abs]
634 n = mf[abs]
635 except (hg.RepoError, KeyError):
635 except (hg.RepoError, KeyError):
636 try:
636 try:
637 n = r.lookup(rev)
637 n = r.lookup(rev)
638 except KeyError, inst:
638 except KeyError, inst:
639 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
639 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
640 else:
640 else:
641 n = r.tip()
641 n = r.tip()
642 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
642 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
643 fp.write(r.read(n))
643 fp.write(r.read(n))
644
644
645 def clone(ui, source, dest=None, **opts):
645 def clone(ui, source, dest=None, **opts):
646 """make a copy of an existing repository
646 """make a copy of an existing repository
647
647
648 Create a copy of an existing repository in a new directory.
648 Create a copy of an existing repository in a new directory.
649
649
650 If no destination directory name is specified, it defaults to the
650 If no destination directory name is specified, it defaults to the
651 basename of the source.
651 basename of the source.
652
652
653 The location of the source is added to the new repository's
653 The location of the source is added to the new repository's
654 .hg/hgrc file, as the default to be used for future pulls.
654 .hg/hgrc file, as the default to be used for future pulls.
655
655
656 For efficiency, hardlinks are used for cloning whenever the source
656 For efficiency, hardlinks are used for cloning whenever the source
657 and destination are on the same filesystem. Some filesystems,
657 and destination are on the same filesystem. Some filesystems,
658 such as AFS, implement hardlinking incorrectly, but do not report
658 such as AFS, implement hardlinking incorrectly, but do not report
659 errors. In these cases, use the --pull option to avoid
659 errors. In these cases, use the --pull option to avoid
660 hardlinking.
660 hardlinking.
661 """
661 """
662 if dest is None:
662 if dest is None:
663 dest = os.path.basename(os.path.normpath(source))
663 dest = os.path.basename(os.path.normpath(source))
664
664
665 if os.path.exists(dest):
665 if os.path.exists(dest):
666 raise util.Abort(_("destination '%s' already exists"), dest)
666 raise util.Abort(_("destination '%s' already exists"), dest)
667
667
668 dest = os.path.realpath(dest)
668 dest = os.path.realpath(dest)
669
669
670 class Dircleanup:
670 class Dircleanup:
671 def __init__(self, dir_):
671 def __init__(self, dir_):
672 self.rmtree = shutil.rmtree
672 self.rmtree = shutil.rmtree
673 self.dir_ = dir_
673 self.dir_ = dir_
674 os.mkdir(dir_)
674 os.mkdir(dir_)
675 def close(self):
675 def close(self):
676 self.dir_ = None
676 self.dir_ = None
677 def __del__(self):
677 def __del__(self):
678 if self.dir_:
678 if self.dir_:
679 self.rmtree(self.dir_, True)
679 self.rmtree(self.dir_, True)
680
680
681 if opts['ssh']:
681 if opts['ssh']:
682 ui.setconfig("ui", "ssh", opts['ssh'])
682 ui.setconfig("ui", "ssh", opts['ssh'])
683 if opts['remotecmd']:
683 if opts['remotecmd']:
684 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
684 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
685
685
686 if not os.path.exists(source):
686 if not os.path.exists(source):
687 source = ui.expandpath(source)
687 source = ui.expandpath(source)
688
688
689 d = Dircleanup(dest)
689 d = Dircleanup(dest)
690 abspath = source
690 abspath = source
691 other = hg.repository(ui, source)
691 other = hg.repository(ui, source)
692
692
693 copy = False
693 copy = False
694 if other.dev() != -1:
694 if other.dev() != -1:
695 abspath = os.path.abspath(source)
695 abspath = os.path.abspath(source)
696 if not opts['pull'] and not opts['rev']:
696 if not opts['pull'] and not opts['rev']:
697 copy = True
697 copy = True
698
698
699 if copy:
699 if copy:
700 try:
700 try:
701 # we use a lock here because if we race with commit, we
701 # we use a lock here because if we race with commit, we
702 # can end up with extra data in the cloned revlogs that's
702 # can end up with extra data in the cloned revlogs that's
703 # not pointed to by changesets, thus causing verify to
703 # not pointed to by changesets, thus causing verify to
704 # fail
704 # fail
705 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
705 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
706 except OSError:
706 except OSError:
707 copy = False
707 copy = False
708
708
709 if copy:
709 if copy:
710 # we lock here to avoid premature writing to the target
710 # we lock here to avoid premature writing to the target
711 os.mkdir(os.path.join(dest, ".hg"))
711 os.mkdir(os.path.join(dest, ".hg"))
712 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
712 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
713
713
714 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
714 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
715 for f in files.split():
715 for f in files.split():
716 src = os.path.join(source, ".hg", f)
716 src = os.path.join(source, ".hg", f)
717 dst = os.path.join(dest, ".hg", f)
717 dst = os.path.join(dest, ".hg", f)
718 try:
718 try:
719 util.copyfiles(src, dst)
719 util.copyfiles(src, dst)
720 except OSError, inst:
720 except OSError, inst:
721 if inst.errno != errno.ENOENT: raise
721 if inst.errno != errno.ENOENT: raise
722
722
723 repo = hg.repository(ui, dest)
723 repo = hg.repository(ui, dest)
724
724
725 else:
725 else:
726 revs = None
726 revs = None
727 if opts['rev']:
727 if opts['rev']:
728 if not other.local():
728 if not other.local():
729 raise util.Abort("clone -r not supported yet for remote repositories.")
729 raise util.Abort("clone -r not supported yet for remote repositories.")
730 else:
730 else:
731 revs = [other.lookup(rev) for rev in opts['rev']]
731 revs = [other.lookup(rev) for rev in opts['rev']]
732 repo = hg.repository(ui, dest, create=1)
732 repo = hg.repository(ui, dest, create=1)
733 repo.pull(other, heads = revs)
733 repo.pull(other, heads = revs)
734
734
735 f = repo.opener("hgrc", "w", text=True)
735 f = repo.opener("hgrc", "w", text=True)
736 f.write("[paths]\n")
736 f.write("[paths]\n")
737 f.write("default = %s\n" % abspath)
737 f.write("default = %s\n" % abspath)
738
738
739 if not opts['noupdate']:
739 if not opts['noupdate']:
740 update(ui, repo)
740 update(ui, repo)
741
741
742 d.close()
742 d.close()
743
743
744 def commit(ui, repo, *pats, **opts):
744 def commit(ui, repo, *pats, **opts):
745 """commit the specified files or all outstanding changes
745 """commit the specified files or all outstanding changes
746
746
747 Commit changes to the given files into the repository.
747 Commit changes to the given files into the repository.
748
748
749 If a list of files is omitted, all changes reported by "hg status"
749 If a list of files is omitted, all changes reported by "hg status"
750 from the root of the repository will be commited.
750 from the root of the repository will be commited.
751
751
752 The HGEDITOR or EDITOR environment variables are used to start an
752 The HGEDITOR or EDITOR environment variables are used to start an
753 editor to add a commit comment.
753 editor to add a commit comment.
754 """
754 """
755 message = opts['message']
755 message = opts['message']
756 logfile = opts['logfile']
756 logfile = opts['logfile']
757
757
758 if message and logfile:
758 if message and logfile:
759 raise util.Abort(_('options --message and --logfile are mutually '
759 raise util.Abort(_('options --message and --logfile are mutually '
760 'exclusive'))
760 'exclusive'))
761 if not message and logfile:
761 if not message and logfile:
762 try:
762 try:
763 if logfile == '-':
763 if logfile == '-':
764 message = sys.stdin.read()
764 message = sys.stdin.read()
765 else:
765 else:
766 message = open(logfile).read()
766 message = open(logfile).read()
767 except IOError, inst:
767 except IOError, inst:
768 raise util.Abort(_("can't read commit message '%s': %s") %
768 raise util.Abort(_("can't read commit message '%s': %s") %
769 (logfile, inst.strerror))
769 (logfile, inst.strerror))
770
770
771 if opts['addremove']:
771 if opts['addremove']:
772 addremove(ui, repo, *pats, **opts)
772 addremove(ui, repo, *pats, **opts)
773 cwd = repo.getcwd()
773 cwd = repo.getcwd()
774 if not pats and cwd:
774 if not pats and cwd:
775 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
775 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
776 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
776 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
777 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
777 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
778 pats, opts)
778 pats, opts)
779 if pats:
779 if pats:
780 c, a, d, u = repo.changes(files=fns, match=match)
780 c, a, d, u = repo.changes(files=fns, match=match)
781 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
781 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
782 else:
782 else:
783 files = []
783 files = []
784 try:
784 try:
785 repo.commit(files, message, opts['user'], opts['date'], match)
785 repo.commit(files, message, opts['user'], opts['date'], match)
786 except ValueError, inst:
786 except ValueError, inst:
787 raise util.Abort(str(inst))
787 raise util.Abort(str(inst))
788
788
789 def docopy(ui, repo, pats, opts):
789 def docopy(ui, repo, pats, opts):
790 if not pats:
790 cwd = repo.getcwd()
791 raise util.Abort(_('no source or destination specified'))
791 errors = 0
792 elif len(pats) == 1:
792 copied = []
793 raise util.Abort(_('no destination specified'))
794 pats = list(pats)
795 dest = pats.pop()
796 sources = []
797 dir2dir = len(pats) == 1 and os.path.isdir(pats[0])
798
793
799 def okaytocopy(abs, rel, exact):
794 def okaytocopy(abs, rel, exact):
800 reasons = {'?': _('is not managed'),
795 reasons = {'?': _('is not managed'),
801 'a': _('has been marked for add')}
796 'a': _('has been marked for add')}
802 reason = reasons.get(repo.dirstate.state(abs))
797 reason = reasons.get(repo.dirstate.state(abs))
803 if reason:
798 if reason:
804 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
799 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
805 else:
800 else:
806 return True
801 return True
807
802
808 for src, abs, rel, exact in walk(repo, pats, opts):
803 def copy(abssrc, relsrc, target, exact):
809 if okaytocopy(abs, rel, exact):
804 abstarget = util.canonpath(repo.root, cwd, target)
810 sources.append((abs, rel, exact))
805 reltarget = util.pathto(cwd, abstarget)
811 if not sources:
806 if not opts['force'] and repo.dirstate.state(abstarget) not in 'a?':
812 raise util.Abort(_('no files to copy'))
807 ui.warn(_('%s: not overwriting - file already managed\n') %
813
808 reltarget)
814 cwd = repo.getcwd()
809 return
815 absdest = util.canonpath(repo.root, cwd, dest)
810 if ui.verbose or not exact:
816 reldest = util.pathto(cwd, absdest)
811 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
817 if os.path.exists(reldest):
818 destisfile = not os.path.isdir(reldest)
819 else:
820 destisfile = not dir2dir and (len(sources) == 1
821 or repo.dirstate.state(absdest) != '?')
822
823 if destisfile and len(sources) > 1:
824 raise util.Abort(_('with multiple sources, destination must be a '
825 'directory'))
826
827 srcpfxlen = 0
828 if dir2dir:
829 srcpfx = util.pathto(cwd, util.canonpath(repo.root, cwd, pats[0]))
830 if os.path.exists(reldest):
831 srcpfx = os.path.split(srcpfx)[0]
832 if srcpfx:
833 srcpfx += os.sep
834 srcpfxlen = len(srcpfx)
835
836 errs, copied = 0, []
837 for abs, rel, exact in sources:
838 if destisfile:
839 mydest = reldest
840 elif dir2dir:
841 mydest = os.path.join(dest, rel[srcpfxlen:])
842 else:
843 mydest = os.path.join(dest, os.path.basename(rel))
844 myabsdest = util.canonpath(repo.root, cwd, mydest)
845 myreldest = util.pathto(cwd, myabsdest)
846 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
847 ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
848 continue
849 mydestdir = os.path.dirname(myreldest) or '.'
850 if not opts['after']:
812 if not opts['after']:
813 targetdir = os.path.dirname(reltarget) or '.'
814 if not os.path.isdir(targetdir):
815 os.makedirs(targetdir)
851 try:
816 try:
852 if dir2dir: os.makedirs(mydestdir)
817 shutil.copyfile(relsrc, reltarget)
853 elif not destisfile: os.mkdir(mydestdir)
818 shutil.copymode(relsrc, reltarget)
854 except OSError, inst:
855 if inst.errno != errno.EEXIST: raise
856 if ui.verbose or not exact:
857 ui.status(_('copying %s to %s\n') % (rel, myreldest))
858 if not opts['after']:
859 try:
860 shutil.copyfile(rel, myreldest)
861 shutil.copymode(rel, myreldest)
862 except shutil.Error, inst:
819 except shutil.Error, inst:
863 raise util.Abort(str(inst))
820 raise util.Abort(str(inst))
864 except IOError, inst:
821 except IOError, inst:
865 if inst.errno == errno.ENOENT:
822 if inst.errno == errno.ENOENT:
866 ui.warn(_('%s: deleted in working copy\n') % rel)
823 ui.warn(_('%s: deleted in working copy\n') % relsrc)
867 else:
824 else:
868 ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror))
825 ui.warn(_('%s: cannot copy - %s\n') %
869 errs += 1
826 (relsrc, inst.strerror))
870 continue
827 errors += 1
871 repo.copy(abs, myabsdest)
828 return
872 copied.append((abs, rel, exact))
829 repo.copy(abssrc, abstarget)
873 if errs:
830 copied.append((abssrc, relsrc, exact))
831
832 pats = list(pats)
833 if not pats:
834 raise util.Abort(_('no source or destination specified'))
835 if len(pats) == 1:
836 raise util.Abort(_('no destination specified'))
837 dest = pats.pop()
838 destdirexists = os.path.isdir(dest)
839 if (len(pats) > 1 or not os.path.exists(pats[0])) and not destdirexists:
840 raise util.Abort(_('with multiple sources, destination must be an '
841 'existing directory'))
842
843 for pat in pats:
844 if os.path.isdir(pat):
845 if destdirexists:
846 striplen = len(os.path.split(pat)[0])
847 else:
848 striplen = len(pat)
849 if striplen:
850 striplen += len(os.sep)
851 targetpath = lambda p: os.path.join(dest, p[striplen:])
852 elif destdirexists:
853 targetpath = lambda p: os.path.join(dest, os.path.basename(p))
854 else:
855 targetpath = lambda p: dest
856 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
857 if okaytocopy(abssrc, relsrc, exact):
858 copy(abssrc, relsrc, targetpath(abssrc), exact)
859
860 if errors:
874 ui.warn(_('(consider using --after)\n'))
861 ui.warn(_('(consider using --after)\n'))
875 return errs, copied
862 if len(copied) == 0:
863 raise util.Abort(_('no files to copy'))
864 return errors, copied
876
865
877 def copy(ui, repo, *pats, **opts):
866 def copy(ui, repo, *pats, **opts):
878 """mark files as copied for the next commit
867 """mark files as copied for the next commit
879
868
880 Mark dest as having copies of source files. If dest is a
869 Mark dest as having copies of source files. If dest is a
881 directory, copies are put in that directory. If dest is a file,
870 directory, copies are put in that directory. If dest is a file,
882 there can only be one source.
871 there can only be one source.
883
872
884 By default, this command copies the contents of files as they
873 By default, this command copies the contents of files as they
885 stand in the working directory. If invoked with --after, the
874 stand in the working directory. If invoked with --after, the
886 operation is recorded, but no copying is performed.
875 operation is recorded, but no copying is performed.
887
876
888 This command takes effect in the next commit.
877 This command takes effect in the next commit.
889
878
890 NOTE: This command should be treated as experimental. While it
879 NOTE: This command should be treated as experimental. While it
891 should properly record copied files, this information is not yet
880 should properly record copied files, this information is not yet
892 fully used by merge, nor fully reported by log.
881 fully used by merge, nor fully reported by log.
893 """
882 """
894 errs, copied = docopy(ui, repo, pats, opts)
883 errs, copied = docopy(ui, repo, pats, opts)
895 return errs
884 return errs
896
885
897 def debugancestor(ui, index, rev1, rev2):
886 def debugancestor(ui, index, rev1, rev2):
898 """find the ancestor revision of two revisions in a given index"""
887 """find the ancestor revision of two revisions in a given index"""
899 r = revlog.revlog(util.opener(os.getcwd()), index, "")
888 r = revlog.revlog(util.opener(os.getcwd()), index, "")
900 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
889 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
901 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
890 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
902
891
903 def debugcheckstate(ui, repo):
892 def debugcheckstate(ui, repo):
904 """validate the correctness of the current dirstate"""
893 """validate the correctness of the current dirstate"""
905 parent1, parent2 = repo.dirstate.parents()
894 parent1, parent2 = repo.dirstate.parents()
906 repo.dirstate.read()
895 repo.dirstate.read()
907 dc = repo.dirstate.map
896 dc = repo.dirstate.map
908 keys = dc.keys()
897 keys = dc.keys()
909 keys.sort()
898 keys.sort()
910 m1n = repo.changelog.read(parent1)[0]
899 m1n = repo.changelog.read(parent1)[0]
911 m2n = repo.changelog.read(parent2)[0]
900 m2n = repo.changelog.read(parent2)[0]
912 m1 = repo.manifest.read(m1n)
901 m1 = repo.manifest.read(m1n)
913 m2 = repo.manifest.read(m2n)
902 m2 = repo.manifest.read(m2n)
914 errors = 0
903 errors = 0
915 for f in dc:
904 for f in dc:
916 state = repo.dirstate.state(f)
905 state = repo.dirstate.state(f)
917 if state in "nr" and f not in m1:
906 if state in "nr" and f not in m1:
918 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
907 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
919 errors += 1
908 errors += 1
920 if state in "a" and f in m1:
909 if state in "a" and f in m1:
921 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
910 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
922 errors += 1
911 errors += 1
923 if state in "m" and f not in m1 and f not in m2:
912 if state in "m" and f not in m1 and f not in m2:
924 ui.warn(_("%s in state %s, but not in either manifest\n") %
913 ui.warn(_("%s in state %s, but not in either manifest\n") %
925 (f, state))
914 (f, state))
926 errors += 1
915 errors += 1
927 for f in m1:
916 for f in m1:
928 state = repo.dirstate.state(f)
917 state = repo.dirstate.state(f)
929 if state not in "nrm":
918 if state not in "nrm":
930 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
919 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
931 errors += 1
920 errors += 1
932 if errors:
921 if errors:
933 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
922 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
934
923
935 def debugconfig(ui):
924 def debugconfig(ui):
936 """show combined config settings from all hgrc files"""
925 """show combined config settings from all hgrc files"""
937 try:
926 try:
938 repo = hg.repository(ui)
927 repo = hg.repository(ui)
939 except hg.RepoError:
928 except hg.RepoError:
940 pass
929 pass
941 for section, name, value in ui.walkconfig():
930 for section, name, value in ui.walkconfig():
942 ui.write('%s.%s=%s\n' % (section, name, value))
931 ui.write('%s.%s=%s\n' % (section, name, value))
943
932
944 def debugsetparents(ui, repo, rev1, rev2=None):
933 def debugsetparents(ui, repo, rev1, rev2=None):
945 """manually set the parents of the current working directory
934 """manually set the parents of the current working directory
946
935
947 This is useful for writing repository conversion tools, but should
936 This is useful for writing repository conversion tools, but should
948 be used with care.
937 be used with care.
949 """
938 """
950
939
951 if not rev2:
940 if not rev2:
952 rev2 = hex(nullid)
941 rev2 = hex(nullid)
953
942
954 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
943 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
955
944
956 def debugstate(ui, repo):
945 def debugstate(ui, repo):
957 """show the contents of the current dirstate"""
946 """show the contents of the current dirstate"""
958 repo.dirstate.read()
947 repo.dirstate.read()
959 dc = repo.dirstate.map
948 dc = repo.dirstate.map
960 keys = dc.keys()
949 keys = dc.keys()
961 keys.sort()
950 keys.sort()
962 for file_ in keys:
951 for file_ in keys:
963 ui.write("%c %3o %10d %s %s\n"
952 ui.write("%c %3o %10d %s %s\n"
964 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
953 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
965 time.strftime("%x %X",
954 time.strftime("%x %X",
966 time.localtime(dc[file_][3])), file_))
955 time.localtime(dc[file_][3])), file_))
967 for f in repo.dirstate.copies:
956 for f in repo.dirstate.copies:
968 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
957 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
969
958
970 def debugdata(ui, file_, rev):
959 def debugdata(ui, file_, rev):
971 """dump the contents of an data file revision"""
960 """dump the contents of an data file revision"""
972 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
961 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
973 try:
962 try:
974 ui.write(r.revision(r.lookup(rev)))
963 ui.write(r.revision(r.lookup(rev)))
975 except KeyError:
964 except KeyError:
976 raise util.Abort(_('invalid revision identifier %s'), rev)
965 raise util.Abort(_('invalid revision identifier %s'), rev)
977
966
978 def debugindex(ui, file_):
967 def debugindex(ui, file_):
979 """dump the contents of an index file"""
968 """dump the contents of an index file"""
980 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
969 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
981 ui.write(" rev offset length base linkrev" +
970 ui.write(" rev offset length base linkrev" +
982 " nodeid p1 p2\n")
971 " nodeid p1 p2\n")
983 for i in range(r.count()):
972 for i in range(r.count()):
984 e = r.index[i]
973 e = r.index[i]
985 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
974 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
986 i, e[0], e[1], e[2], e[3],
975 i, e[0], e[1], e[2], e[3],
987 short(e[6]), short(e[4]), short(e[5])))
976 short(e[6]), short(e[4]), short(e[5])))
988
977
989 def debugindexdot(ui, file_):
978 def debugindexdot(ui, file_):
990 """dump an index DAG as a .dot file"""
979 """dump an index DAG as a .dot file"""
991 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
980 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
992 ui.write("digraph G {\n")
981 ui.write("digraph G {\n")
993 for i in range(r.count()):
982 for i in range(r.count()):
994 e = r.index[i]
983 e = r.index[i]
995 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
984 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
996 if e[5] != nullid:
985 if e[5] != nullid:
997 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
986 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
998 ui.write("}\n")
987 ui.write("}\n")
999
988
1000 def debugrename(ui, repo, file, rev=None):
989 def debugrename(ui, repo, file, rev=None):
1001 """dump rename information"""
990 """dump rename information"""
1002 r = repo.file(relpath(repo, [file])[0])
991 r = repo.file(relpath(repo, [file])[0])
1003 if rev:
992 if rev:
1004 try:
993 try:
1005 # assume all revision numbers are for changesets
994 # assume all revision numbers are for changesets
1006 n = repo.lookup(rev)
995 n = repo.lookup(rev)
1007 change = repo.changelog.read(n)
996 change = repo.changelog.read(n)
1008 m = repo.manifest.read(change[0])
997 m = repo.manifest.read(change[0])
1009 n = m[relpath(repo, [file])[0]]
998 n = m[relpath(repo, [file])[0]]
1010 except hg.RepoError, KeyError:
999 except hg.RepoError, KeyError:
1011 n = r.lookup(rev)
1000 n = r.lookup(rev)
1012 else:
1001 else:
1013 n = r.tip()
1002 n = r.tip()
1014 m = r.renamed(n)
1003 m = r.renamed(n)
1015 if m:
1004 if m:
1016 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1005 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1017 else:
1006 else:
1018 ui.write(_("not renamed\n"))
1007 ui.write(_("not renamed\n"))
1019
1008
1020 def debugwalk(ui, repo, *pats, **opts):
1009 def debugwalk(ui, repo, *pats, **opts):
1021 """show how files match on given patterns"""
1010 """show how files match on given patterns"""
1022 items = list(walk(repo, pats, opts))
1011 items = list(walk(repo, pats, opts))
1023 if not items:
1012 if not items:
1024 return
1013 return
1025 fmt = '%%s %%-%ds %%-%ds %%s' % (
1014 fmt = '%%s %%-%ds %%-%ds %%s' % (
1026 max([len(abs) for (src, abs, rel, exact) in items]),
1015 max([len(abs) for (src, abs, rel, exact) in items]),
1027 max([len(rel) for (src, abs, rel, exact) in items]))
1016 max([len(rel) for (src, abs, rel, exact) in items]))
1028 for src, abs, rel, exact in items:
1017 for src, abs, rel, exact in items:
1029 line = fmt % (src, abs, rel, exact and 'exact' or '')
1018 line = fmt % (src, abs, rel, exact and 'exact' or '')
1030 ui.write("%s\n" % line.rstrip())
1019 ui.write("%s\n" % line.rstrip())
1031
1020
1032 def diff(ui, repo, *pats, **opts):
1021 def diff(ui, repo, *pats, **opts):
1033 """diff working directory (or selected files)
1022 """diff working directory (or selected files)
1034
1023
1035 Show differences between revisions for the specified files.
1024 Show differences between revisions for the specified files.
1036
1025
1037 Differences between files are shown using the unified diff format.
1026 Differences between files are shown using the unified diff format.
1038
1027
1039 When two revision arguments are given, then changes are shown
1028 When two revision arguments are given, then changes are shown
1040 between those revisions. If only one revision is specified then
1029 between those revisions. If only one revision is specified then
1041 that revision is compared to the working directory, and, when no
1030 that revision is compared to the working directory, and, when no
1042 revisions are specified, the working directory files are compared
1031 revisions are specified, the working directory files are compared
1043 to its parent.
1032 to its parent.
1044
1033
1045 Without the -a option, diff will avoid generating diffs of files
1034 Without the -a option, diff will avoid generating diffs of files
1046 it detects as binary. With -a, diff will generate a diff anyway,
1035 it detects as binary. With -a, diff will generate a diff anyway,
1047 probably with undesirable results.
1036 probably with undesirable results.
1048 """
1037 """
1049 node1, node2 = None, None
1038 node1, node2 = None, None
1050 revs = [repo.lookup(x) for x in opts['rev']]
1039 revs = [repo.lookup(x) for x in opts['rev']]
1051
1040
1052 if len(revs) > 0:
1041 if len(revs) > 0:
1053 node1 = revs[0]
1042 node1 = revs[0]
1054 if len(revs) > 1:
1043 if len(revs) > 1:
1055 node2 = revs[1]
1044 node2 = revs[1]
1056 if len(revs) > 2:
1045 if len(revs) > 2:
1057 raise util.Abort(_("too many revisions to diff"))
1046 raise util.Abort(_("too many revisions to diff"))
1058
1047
1059 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1048 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1060
1049
1061 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1050 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1062 text=opts['text'])
1051 text=opts['text'])
1063
1052
1064 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1053 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1065 node = repo.lookup(changeset)
1054 node = repo.lookup(changeset)
1066 prev, other = repo.changelog.parents(node)
1055 prev, other = repo.changelog.parents(node)
1067 change = repo.changelog.read(node)
1056 change = repo.changelog.read(node)
1068
1057
1069 fp = make_file(repo, repo.changelog, opts['output'],
1058 fp = make_file(repo, repo.changelog, opts['output'],
1070 node=node, total=total, seqno=seqno,
1059 node=node, total=total, seqno=seqno,
1071 revwidth=revwidth)
1060 revwidth=revwidth)
1072 if fp != sys.stdout:
1061 if fp != sys.stdout:
1073 ui.note("%s\n" % fp.name)
1062 ui.note("%s\n" % fp.name)
1074
1063
1075 fp.write("# HG changeset patch\n")
1064 fp.write("# HG changeset patch\n")
1076 fp.write("# User %s\n" % change[1])
1065 fp.write("# User %s\n" % change[1])
1077 fp.write("# Node ID %s\n" % hex(node))
1066 fp.write("# Node ID %s\n" % hex(node))
1078 fp.write("# Parent %s\n" % hex(prev))
1067 fp.write("# Parent %s\n" % hex(prev))
1079 if other != nullid:
1068 if other != nullid:
1080 fp.write("# Parent %s\n" % hex(other))
1069 fp.write("# Parent %s\n" % hex(other))
1081 fp.write(change[4].rstrip())
1070 fp.write(change[4].rstrip())
1082 fp.write("\n\n")
1071 fp.write("\n\n")
1083
1072
1084 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1073 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1085 if fp != sys.stdout:
1074 if fp != sys.stdout:
1086 fp.close()
1075 fp.close()
1087
1076
1088 def export(ui, repo, *changesets, **opts):
1077 def export(ui, repo, *changesets, **opts):
1089 """dump the header and diffs for one or more changesets
1078 """dump the header and diffs for one or more changesets
1090
1079
1091 Print the changeset header and diffs for one or more revisions.
1080 Print the changeset header and diffs for one or more revisions.
1092
1081
1093 The information shown in the changeset header is: author,
1082 The information shown in the changeset header is: author,
1094 changeset hash, parent and commit comment.
1083 changeset hash, parent and commit comment.
1095
1084
1096 Output may be to a file, in which case the name of the file is
1085 Output may be to a file, in which case the name of the file is
1097 given using a format string. The formatting rules are as follows:
1086 given using a format string. The formatting rules are as follows:
1098
1087
1099 %% literal "%" character
1088 %% literal "%" character
1100 %H changeset hash (40 bytes of hexadecimal)
1089 %H changeset hash (40 bytes of hexadecimal)
1101 %N number of patches being generated
1090 %N number of patches being generated
1102 %R changeset revision number
1091 %R changeset revision number
1103 %b basename of the exporting repository
1092 %b basename of the exporting repository
1104 %h short-form changeset hash (12 bytes of hexadecimal)
1093 %h short-form changeset hash (12 bytes of hexadecimal)
1105 %n zero-padded sequence number, starting at 1
1094 %n zero-padded sequence number, starting at 1
1106 %r zero-padded changeset revision number
1095 %r zero-padded changeset revision number
1107
1096
1108 Without the -a option, export will avoid generating diffs of files
1097 Without the -a option, export will avoid generating diffs of files
1109 it detects as binary. With -a, export will generate a diff anyway,
1098 it detects as binary. With -a, export will generate a diff anyway,
1110 probably with undesirable results.
1099 probably with undesirable results.
1111 """
1100 """
1112 if not changesets:
1101 if not changesets:
1113 raise util.Abort(_("export requires at least one changeset"))
1102 raise util.Abort(_("export requires at least one changeset"))
1114 seqno = 0
1103 seqno = 0
1115 revs = list(revrange(ui, repo, changesets))
1104 revs = list(revrange(ui, repo, changesets))
1116 total = len(revs)
1105 total = len(revs)
1117 revwidth = max(map(len, revs))
1106 revwidth = max(map(len, revs))
1118 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1107 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1119 for cset in revs:
1108 for cset in revs:
1120 seqno += 1
1109 seqno += 1
1121 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1110 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1122
1111
1123 def forget(ui, repo, *pats, **opts):
1112 def forget(ui, repo, *pats, **opts):
1124 """don't add the specified files on the next commit
1113 """don't add the specified files on the next commit
1125
1114
1126 Undo an 'hg add' scheduled for the next commit.
1115 Undo an 'hg add' scheduled for the next commit.
1127 """
1116 """
1128 forget = []
1117 forget = []
1129 for src, abs, rel, exact in walk(repo, pats, opts):
1118 for src, abs, rel, exact in walk(repo, pats, opts):
1130 if repo.dirstate.state(abs) == 'a':
1119 if repo.dirstate.state(abs) == 'a':
1131 forget.append(abs)
1120 forget.append(abs)
1132 if ui.verbose or not exact:
1121 if ui.verbose or not exact:
1133 ui.status(_('forgetting %s\n') % rel)
1122 ui.status(_('forgetting %s\n') % rel)
1134 repo.forget(forget)
1123 repo.forget(forget)
1135
1124
1136 def grep(ui, repo, pattern, *pats, **opts):
1125 def grep(ui, repo, pattern, *pats, **opts):
1137 """search for a pattern in specified files and revisions
1126 """search for a pattern in specified files and revisions
1138
1127
1139 Search revisions of files for a regular expression.
1128 Search revisions of files for a regular expression.
1140
1129
1141 This command behaves differently than Unix grep. It only accepts
1130 This command behaves differently than Unix grep. It only accepts
1142 Python/Perl regexps. It searches repository history, not the
1131 Python/Perl regexps. It searches repository history, not the
1143 working directory. It always prints the revision number in which
1132 working directory. It always prints the revision number in which
1144 a match appears.
1133 a match appears.
1145
1134
1146 By default, grep only prints output for the first revision of a
1135 By default, grep only prints output for the first revision of a
1147 file in which it finds a match. To get it to print every revision
1136 file in which it finds a match. To get it to print every revision
1148 that contains a change in match status ("-" for a match that
1137 that contains a change in match status ("-" for a match that
1149 becomes a non-match, or "+" for a non-match that becomes a match),
1138 becomes a non-match, or "+" for a non-match that becomes a match),
1150 use the --all flag.
1139 use the --all flag.
1151 """
1140 """
1152 reflags = 0
1141 reflags = 0
1153 if opts['ignore_case']:
1142 if opts['ignore_case']:
1154 reflags |= re.I
1143 reflags |= re.I
1155 regexp = re.compile(pattern, reflags)
1144 regexp = re.compile(pattern, reflags)
1156 sep, eol = ':', '\n'
1145 sep, eol = ':', '\n'
1157 if opts['print0']:
1146 if opts['print0']:
1158 sep = eol = '\0'
1147 sep = eol = '\0'
1159
1148
1160 fcache = {}
1149 fcache = {}
1161 def getfile(fn):
1150 def getfile(fn):
1162 if fn not in fcache:
1151 if fn not in fcache:
1163 fcache[fn] = repo.file(fn)
1152 fcache[fn] = repo.file(fn)
1164 return fcache[fn]
1153 return fcache[fn]
1165
1154
1166 def matchlines(body):
1155 def matchlines(body):
1167 begin = 0
1156 begin = 0
1168 linenum = 0
1157 linenum = 0
1169 while True:
1158 while True:
1170 match = regexp.search(body, begin)
1159 match = regexp.search(body, begin)
1171 if not match:
1160 if not match:
1172 break
1161 break
1173 mstart, mend = match.span()
1162 mstart, mend = match.span()
1174 linenum += body.count('\n', begin, mstart) + 1
1163 linenum += body.count('\n', begin, mstart) + 1
1175 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1164 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1176 lend = body.find('\n', mend)
1165 lend = body.find('\n', mend)
1177 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1166 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1178 begin = lend + 1
1167 begin = lend + 1
1179
1168
1180 class linestate:
1169 class linestate:
1181 def __init__(self, line, linenum, colstart, colend):
1170 def __init__(self, line, linenum, colstart, colend):
1182 self.line = line
1171 self.line = line
1183 self.linenum = linenum
1172 self.linenum = linenum
1184 self.colstart = colstart
1173 self.colstart = colstart
1185 self.colend = colend
1174 self.colend = colend
1186 def __eq__(self, other):
1175 def __eq__(self, other):
1187 return self.line == other.line
1176 return self.line == other.line
1188 def __hash__(self):
1177 def __hash__(self):
1189 return hash(self.line)
1178 return hash(self.line)
1190
1179
1191 matches = {}
1180 matches = {}
1192 def grepbody(fn, rev, body):
1181 def grepbody(fn, rev, body):
1193 matches[rev].setdefault(fn, {})
1182 matches[rev].setdefault(fn, {})
1194 m = matches[rev][fn]
1183 m = matches[rev][fn]
1195 for lnum, cstart, cend, line in matchlines(body):
1184 for lnum, cstart, cend, line in matchlines(body):
1196 s = linestate(line, lnum, cstart, cend)
1185 s = linestate(line, lnum, cstart, cend)
1197 m[s] = s
1186 m[s] = s
1198
1187
1199 prev = {}
1188 prev = {}
1200 ucache = {}
1189 ucache = {}
1201 def display(fn, rev, states, prevstates):
1190 def display(fn, rev, states, prevstates):
1202 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1191 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1203 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1192 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1204 counts = {'-': 0, '+': 0}
1193 counts = {'-': 0, '+': 0}
1205 filerevmatches = {}
1194 filerevmatches = {}
1206 for l in diff:
1195 for l in diff:
1207 if incrementing or not opts['all']:
1196 if incrementing or not opts['all']:
1208 change = ((l in prevstates) and '-') or '+'
1197 change = ((l in prevstates) and '-') or '+'
1209 r = rev
1198 r = rev
1210 else:
1199 else:
1211 change = ((l in states) and '-') or '+'
1200 change = ((l in states) and '-') or '+'
1212 r = prev[fn]
1201 r = prev[fn]
1213 cols = [fn, str(rev)]
1202 cols = [fn, str(rev)]
1214 if opts['line_number']: cols.append(str(l.linenum))
1203 if opts['line_number']: cols.append(str(l.linenum))
1215 if opts['all']: cols.append(change)
1204 if opts['all']: cols.append(change)
1216 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1205 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1217 ucache))
1206 ucache))
1218 if opts['files_with_matches']:
1207 if opts['files_with_matches']:
1219 c = (fn, rev)
1208 c = (fn, rev)
1220 if c in filerevmatches: continue
1209 if c in filerevmatches: continue
1221 filerevmatches[c] = 1
1210 filerevmatches[c] = 1
1222 else:
1211 else:
1223 cols.append(l.line)
1212 cols.append(l.line)
1224 ui.write(sep.join(cols), eol)
1213 ui.write(sep.join(cols), eol)
1225 counts[change] += 1
1214 counts[change] += 1
1226 return counts['+'], counts['-']
1215 return counts['+'], counts['-']
1227
1216
1228 fstate = {}
1217 fstate = {}
1229 skip = {}
1218 skip = {}
1230 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1219 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1231 count = 0
1220 count = 0
1232 incrementing = False
1221 incrementing = False
1233 for st, rev, fns in changeiter:
1222 for st, rev, fns in changeiter:
1234 if st == 'window':
1223 if st == 'window':
1235 incrementing = rev
1224 incrementing = rev
1236 matches.clear()
1225 matches.clear()
1237 elif st == 'add':
1226 elif st == 'add':
1238 change = repo.changelog.read(repo.lookup(str(rev)))
1227 change = repo.changelog.read(repo.lookup(str(rev)))
1239 mf = repo.manifest.read(change[0])
1228 mf = repo.manifest.read(change[0])
1240 matches[rev] = {}
1229 matches[rev] = {}
1241 for fn in fns:
1230 for fn in fns:
1242 if fn in skip: continue
1231 if fn in skip: continue
1243 fstate.setdefault(fn, {})
1232 fstate.setdefault(fn, {})
1244 try:
1233 try:
1245 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1234 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1246 except KeyError:
1235 except KeyError:
1247 pass
1236 pass
1248 elif st == 'iter':
1237 elif st == 'iter':
1249 states = matches[rev].items()
1238 states = matches[rev].items()
1250 states.sort()
1239 states.sort()
1251 for fn, m in states:
1240 for fn, m in states:
1252 if fn in skip: continue
1241 if fn in skip: continue
1253 if incrementing or not opts['all'] or fstate[fn]:
1242 if incrementing or not opts['all'] or fstate[fn]:
1254 pos, neg = display(fn, rev, m, fstate[fn])
1243 pos, neg = display(fn, rev, m, fstate[fn])
1255 count += pos + neg
1244 count += pos + neg
1256 if pos and not opts['all']:
1245 if pos and not opts['all']:
1257 skip[fn] = True
1246 skip[fn] = True
1258 fstate[fn] = m
1247 fstate[fn] = m
1259 prev[fn] = rev
1248 prev[fn] = rev
1260
1249
1261 if not incrementing:
1250 if not incrementing:
1262 fstate = fstate.items()
1251 fstate = fstate.items()
1263 fstate.sort()
1252 fstate.sort()
1264 for fn, state in fstate:
1253 for fn, state in fstate:
1265 if fn in skip: continue
1254 if fn in skip: continue
1266 display(fn, rev, {}, state)
1255 display(fn, rev, {}, state)
1267 return (count == 0 and 1) or 0
1256 return (count == 0 and 1) or 0
1268
1257
1269 def heads(ui, repo, **opts):
1258 def heads(ui, repo, **opts):
1270 """show current repository heads
1259 """show current repository heads
1271
1260
1272 Show all repository head changesets.
1261 Show all repository head changesets.
1273
1262
1274 Repository "heads" are changesets that don't have children
1263 Repository "heads" are changesets that don't have children
1275 changesets. They are where development generally takes place and
1264 changesets. They are where development generally takes place and
1276 are the usual targets for update and merge operations.
1265 are the usual targets for update and merge operations.
1277 """
1266 """
1278 heads = repo.changelog.heads()
1267 heads = repo.changelog.heads()
1279 br = None
1268 br = None
1280 if opts['branches']:
1269 if opts['branches']:
1281 br = repo.branchlookup(heads)
1270 br = repo.branchlookup(heads)
1282 for n in repo.changelog.heads():
1271 for n in repo.changelog.heads():
1283 show_changeset(ui, repo, changenode=n, brinfo=br)
1272 show_changeset(ui, repo, changenode=n, brinfo=br)
1284
1273
1285 def identify(ui, repo):
1274 def identify(ui, repo):
1286 """print information about the working copy
1275 """print information about the working copy
1287
1276
1288 Print a short summary of the current state of the repo.
1277 Print a short summary of the current state of the repo.
1289
1278
1290 This summary identifies the repository state using one or two parent
1279 This summary identifies the repository state using one or two parent
1291 hash identifiers, followed by a "+" if there are uncommitted changes
1280 hash identifiers, followed by a "+" if there are uncommitted changes
1292 in the working directory, followed by a list of tags for this revision.
1281 in the working directory, followed by a list of tags for this revision.
1293 """
1282 """
1294 parents = [p for p in repo.dirstate.parents() if p != nullid]
1283 parents = [p for p in repo.dirstate.parents() if p != nullid]
1295 if not parents:
1284 if not parents:
1296 ui.write(_("unknown\n"))
1285 ui.write(_("unknown\n"))
1297 return
1286 return
1298
1287
1299 hexfunc = ui.verbose and hex or short
1288 hexfunc = ui.verbose and hex or short
1300 (c, a, d, u) = repo.changes()
1289 (c, a, d, u) = repo.changes()
1301 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1290 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1302 (c or a or d) and "+" or "")]
1291 (c or a or d) and "+" or "")]
1303
1292
1304 if not ui.quiet:
1293 if not ui.quiet:
1305 # multiple tags for a single parent separated by '/'
1294 # multiple tags for a single parent separated by '/'
1306 parenttags = ['/'.join(tags)
1295 parenttags = ['/'.join(tags)
1307 for tags in map(repo.nodetags, parents) if tags]
1296 for tags in map(repo.nodetags, parents) if tags]
1308 # tags for multiple parents separated by ' + '
1297 # tags for multiple parents separated by ' + '
1309 if parenttags:
1298 if parenttags:
1310 output.append(' + '.join(parenttags))
1299 output.append(' + '.join(parenttags))
1311
1300
1312 ui.write("%s\n" % ' '.join(output))
1301 ui.write("%s\n" % ' '.join(output))
1313
1302
1314 def import_(ui, repo, patch1, *patches, **opts):
1303 def import_(ui, repo, patch1, *patches, **opts):
1315 """import an ordered set of patches
1304 """import an ordered set of patches
1316
1305
1317 Import a list of patches and commit them individually.
1306 Import a list of patches and commit them individually.
1318
1307
1319 If there are outstanding changes in the working directory, import
1308 If there are outstanding changes in the working directory, import
1320 will abort unless given the -f flag.
1309 will abort unless given the -f flag.
1321
1310
1322 If a patch looks like a mail message (its first line starts with
1311 If a patch looks like a mail message (its first line starts with
1323 "From " or looks like an RFC822 header), it will not be applied
1312 "From " or looks like an RFC822 header), it will not be applied
1324 unless the -f option is used. The importer neither parses nor
1313 unless the -f option is used. The importer neither parses nor
1325 discards mail headers, so use -f only to override the "mailness"
1314 discards mail headers, so use -f only to override the "mailness"
1326 safety check, not to import a real mail message.
1315 safety check, not to import a real mail message.
1327 """
1316 """
1328 patches = (patch1,) + patches
1317 patches = (patch1,) + patches
1329
1318
1330 if not opts['force']:
1319 if not opts['force']:
1331 (c, a, d, u) = repo.changes()
1320 (c, a, d, u) = repo.changes()
1332 if c or a or d:
1321 if c or a or d:
1333 raise util.Abort(_("outstanding uncommitted changes"))
1322 raise util.Abort(_("outstanding uncommitted changes"))
1334
1323
1335 d = opts["base"]
1324 d = opts["base"]
1336 strip = opts["strip"]
1325 strip = opts["strip"]
1337
1326
1338 mailre = re.compile(r'(?:From |[\w-]+:)')
1327 mailre = re.compile(r'(?:From |[\w-]+:)')
1339
1328
1340 # attempt to detect the start of a patch
1329 # attempt to detect the start of a patch
1341 # (this heuristic is borrowed from quilt)
1330 # (this heuristic is borrowed from quilt)
1342 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1331 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1343 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1332 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1344 '(---|\*\*\*)[ \t])')
1333 '(---|\*\*\*)[ \t])')
1345
1334
1346 for patch in patches:
1335 for patch in patches:
1347 ui.status(_("applying %s\n") % patch)
1336 ui.status(_("applying %s\n") % patch)
1348 pf = os.path.join(d, patch)
1337 pf = os.path.join(d, patch)
1349
1338
1350 message = []
1339 message = []
1351 user = None
1340 user = None
1352 hgpatch = False
1341 hgpatch = False
1353 for line in file(pf):
1342 for line in file(pf):
1354 line = line.rstrip()
1343 line = line.rstrip()
1355 if (not message and not hgpatch and
1344 if (not message and not hgpatch and
1356 mailre.match(line) and not opts['force']):
1345 mailre.match(line) and not opts['force']):
1357 if len(line) > 35: line = line[:32] + '...'
1346 if len(line) > 35: line = line[:32] + '...'
1358 raise util.Abort(_('first line looks like a '
1347 raise util.Abort(_('first line looks like a '
1359 'mail header: ') + line)
1348 'mail header: ') + line)
1360 if diffre.match(line):
1349 if diffre.match(line):
1361 break
1350 break
1362 elif hgpatch:
1351 elif hgpatch:
1363 # parse values when importing the result of an hg export
1352 # parse values when importing the result of an hg export
1364 if line.startswith("# User "):
1353 if line.startswith("# User "):
1365 user = line[7:]
1354 user = line[7:]
1366 ui.debug(_('User: %s\n') % user)
1355 ui.debug(_('User: %s\n') % user)
1367 elif not line.startswith("# ") and line:
1356 elif not line.startswith("# ") and line:
1368 message.append(line)
1357 message.append(line)
1369 hgpatch = False
1358 hgpatch = False
1370 elif line == '# HG changeset patch':
1359 elif line == '# HG changeset patch':
1371 hgpatch = True
1360 hgpatch = True
1372 message = [] # We may have collected garbage
1361 message = [] # We may have collected garbage
1373 else:
1362 else:
1374 message.append(line)
1363 message.append(line)
1375
1364
1376 # make sure message isn't empty
1365 # make sure message isn't empty
1377 if not message:
1366 if not message:
1378 message = _("imported patch %s\n") % patch
1367 message = _("imported patch %s\n") % patch
1379 else:
1368 else:
1380 message = "%s\n" % '\n'.join(message)
1369 message = "%s\n" % '\n'.join(message)
1381 ui.debug(_('message:\n%s\n') % message)
1370 ui.debug(_('message:\n%s\n') % message)
1382
1371
1383 files = util.patch(strip, pf, ui)
1372 files = util.patch(strip, pf, ui)
1384
1373
1385 if len(files) > 0:
1374 if len(files) > 0:
1386 addremove(ui, repo, *files)
1375 addremove(ui, repo, *files)
1387 repo.commit(files, message, user)
1376 repo.commit(files, message, user)
1388
1377
1389 def incoming(ui, repo, source="default", **opts):
1378 def incoming(ui, repo, source="default", **opts):
1390 """show new changesets found in source
1379 """show new changesets found in source
1391
1380
1392 Show new changesets found in the specified repo or the default
1381 Show new changesets found in the specified repo or the default
1393 pull repo. These are the changesets that would be pulled if a pull
1382 pull repo. These are the changesets that would be pulled if a pull
1394 was requested.
1383 was requested.
1395
1384
1396 Currently only local repositories are supported.
1385 Currently only local repositories are supported.
1397 """
1386 """
1398 source = ui.expandpath(source, repo.root)
1387 source = ui.expandpath(source, repo.root)
1399 other = hg.repository(ui, source)
1388 other = hg.repository(ui, source)
1400 if not other.local():
1389 if not other.local():
1401 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1390 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1402 o = repo.findincoming(other)
1391 o = repo.findincoming(other)
1403 if not o:
1392 if not o:
1404 return
1393 return
1405 o = other.changelog.nodesbetween(o)[0]
1394 o = other.changelog.nodesbetween(o)[0]
1406 if opts['newest_first']:
1395 if opts['newest_first']:
1407 o.reverse()
1396 o.reverse()
1408 for n in o:
1397 for n in o:
1409 parents = [p for p in other.changelog.parents(n) if p != nullid]
1398 parents = [p for p in other.changelog.parents(n) if p != nullid]
1410 if opts['no_merges'] and len(parents) == 2:
1399 if opts['no_merges'] and len(parents) == 2:
1411 continue
1400 continue
1412 show_changeset(ui, other, changenode=n)
1401 show_changeset(ui, other, changenode=n)
1413 if opts['patch']:
1402 if opts['patch']:
1414 prev = (parents and parents[0]) or nullid
1403 prev = (parents and parents[0]) or nullid
1415 dodiff(ui, ui, other, prev, n)
1404 dodiff(ui, ui, other, prev, n)
1416 ui.write("\n")
1405 ui.write("\n")
1417
1406
1418 def init(ui, dest="."):
1407 def init(ui, dest="."):
1419 """create a new repository in the given directory
1408 """create a new repository in the given directory
1420
1409
1421 Initialize a new repository in the given directory. If the given
1410 Initialize a new repository in the given directory. If the given
1422 directory does not exist, it is created.
1411 directory does not exist, it is created.
1423
1412
1424 If no directory is given, the current directory is used.
1413 If no directory is given, the current directory is used.
1425 """
1414 """
1426 if not os.path.exists(dest):
1415 if not os.path.exists(dest):
1427 os.mkdir(dest)
1416 os.mkdir(dest)
1428 hg.repository(ui, dest, create=1)
1417 hg.repository(ui, dest, create=1)
1429
1418
1430 def locate(ui, repo, *pats, **opts):
1419 def locate(ui, repo, *pats, **opts):
1431 """locate files matching specific patterns
1420 """locate files matching specific patterns
1432
1421
1433 Print all files under Mercurial control whose names match the
1422 Print all files under Mercurial control whose names match the
1434 given patterns.
1423 given patterns.
1435
1424
1436 This command searches the current directory and its
1425 This command searches the current directory and its
1437 subdirectories. To search an entire repository, move to the root
1426 subdirectories. To search an entire repository, move to the root
1438 of the repository.
1427 of the repository.
1439
1428
1440 If no patterns are given to match, this command prints all file
1429 If no patterns are given to match, this command prints all file
1441 names.
1430 names.
1442
1431
1443 If you want to feed the output of this command into the "xargs"
1432 If you want to feed the output of this command into the "xargs"
1444 command, use the "-0" option to both this command and "xargs".
1433 command, use the "-0" option to both this command and "xargs".
1445 This will avoid the problem of "xargs" treating single filenames
1434 This will avoid the problem of "xargs" treating single filenames
1446 that contain white space as multiple filenames.
1435 that contain white space as multiple filenames.
1447 """
1436 """
1448 end = opts['print0'] and '\0' or '\n'
1437 end = opts['print0'] and '\0' or '\n'
1449
1438
1450 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1439 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1451 if repo.dirstate.state(abs) == '?':
1440 if repo.dirstate.state(abs) == '?':
1452 continue
1441 continue
1453 if opts['fullpath']:
1442 if opts['fullpath']:
1454 ui.write(os.path.join(repo.root, abs), end)
1443 ui.write(os.path.join(repo.root, abs), end)
1455 else:
1444 else:
1456 ui.write(rel, end)
1445 ui.write(rel, end)
1457
1446
1458 def log(ui, repo, *pats, **opts):
1447 def log(ui, repo, *pats, **opts):
1459 """show revision history of entire repository or files
1448 """show revision history of entire repository or files
1460
1449
1461 Print the revision history of the specified files or the entire project.
1450 Print the revision history of the specified files or the entire project.
1462
1451
1463 By default this command outputs: changeset id and hash, tags,
1452 By default this command outputs: changeset id and hash, tags,
1464 parents, user, date and time, and a summary for each commit. The
1453 parents, user, date and time, and a summary for each commit. The
1465 -v switch adds some more detail, such as changed files, manifest
1454 -v switch adds some more detail, such as changed files, manifest
1466 hashes or message signatures.
1455 hashes or message signatures.
1467 """
1456 """
1468 class dui:
1457 class dui:
1469 # Implement and delegate some ui protocol. Save hunks of
1458 # Implement and delegate some ui protocol. Save hunks of
1470 # output for later display in the desired order.
1459 # output for later display in the desired order.
1471 def __init__(self, ui):
1460 def __init__(self, ui):
1472 self.ui = ui
1461 self.ui = ui
1473 self.hunk = {}
1462 self.hunk = {}
1474 def bump(self, rev):
1463 def bump(self, rev):
1475 self.rev = rev
1464 self.rev = rev
1476 self.hunk[rev] = []
1465 self.hunk[rev] = []
1477 def note(self, *args):
1466 def note(self, *args):
1478 if self.verbose:
1467 if self.verbose:
1479 self.write(*args)
1468 self.write(*args)
1480 def status(self, *args):
1469 def status(self, *args):
1481 if not self.quiet:
1470 if not self.quiet:
1482 self.write(*args)
1471 self.write(*args)
1483 def write(self, *args):
1472 def write(self, *args):
1484 self.hunk[self.rev].append(args)
1473 self.hunk[self.rev].append(args)
1485 def debug(self, *args):
1474 def debug(self, *args):
1486 if self.debugflag:
1475 if self.debugflag:
1487 self.write(*args)
1476 self.write(*args)
1488 def __getattr__(self, key):
1477 def __getattr__(self, key):
1489 return getattr(self.ui, key)
1478 return getattr(self.ui, key)
1490 cwd = repo.getcwd()
1479 cwd = repo.getcwd()
1491 if not pats and cwd:
1480 if not pats and cwd:
1492 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1481 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1493 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1482 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1494 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1483 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1495 pats, opts)
1484 pats, opts)
1496 for st, rev, fns in changeiter:
1485 for st, rev, fns in changeiter:
1497 if st == 'window':
1486 if st == 'window':
1498 du = dui(ui)
1487 du = dui(ui)
1499 elif st == 'add':
1488 elif st == 'add':
1500 du.bump(rev)
1489 du.bump(rev)
1501 changenode = repo.changelog.node(rev)
1490 changenode = repo.changelog.node(rev)
1502 parents = [p for p in repo.changelog.parents(changenode)
1491 parents = [p for p in repo.changelog.parents(changenode)
1503 if p != nullid]
1492 if p != nullid]
1504 if opts['no_merges'] and len(parents) == 2:
1493 if opts['no_merges'] and len(parents) == 2:
1505 continue
1494 continue
1506 if opts['only_merges'] and len(parents) != 2:
1495 if opts['only_merges'] and len(parents) != 2:
1507 continue
1496 continue
1508
1497
1509 br = None
1498 br = None
1510 if opts['keyword']:
1499 if opts['keyword']:
1511 changes = repo.changelog.read(repo.changelog.node(rev))
1500 changes = repo.changelog.read(repo.changelog.node(rev))
1512 miss = 0
1501 miss = 0
1513 for k in [kw.lower() for kw in opts['keyword']]:
1502 for k in [kw.lower() for kw in opts['keyword']]:
1514 if not (k in changes[1].lower() or
1503 if not (k in changes[1].lower() or
1515 k in changes[4].lower() or
1504 k in changes[4].lower() or
1516 k in " ".join(changes[3][:20]).lower()):
1505 k in " ".join(changes[3][:20]).lower()):
1517 miss = 1
1506 miss = 1
1518 break
1507 break
1519 if miss:
1508 if miss:
1520 continue
1509 continue
1521
1510
1522 if opts['branch']:
1511 if opts['branch']:
1523 br = repo.branchlookup([repo.changelog.node(rev)])
1512 br = repo.branchlookup([repo.changelog.node(rev)])
1524
1513
1525 show_changeset(du, repo, rev, brinfo=br)
1514 show_changeset(du, repo, rev, brinfo=br)
1526 if opts['patch']:
1515 if opts['patch']:
1527 prev = (parents and parents[0]) or nullid
1516 prev = (parents and parents[0]) or nullid
1528 dodiff(du, du, repo, prev, changenode, fns)
1517 dodiff(du, du, repo, prev, changenode, fns)
1529 du.write("\n\n")
1518 du.write("\n\n")
1530 elif st == 'iter':
1519 elif st == 'iter':
1531 for args in du.hunk[rev]:
1520 for args in du.hunk[rev]:
1532 ui.write(*args)
1521 ui.write(*args)
1533
1522
1534 def manifest(ui, repo, rev=None):
1523 def manifest(ui, repo, rev=None):
1535 """output the latest or given revision of the project manifest
1524 """output the latest or given revision of the project manifest
1536
1525
1537 Print a list of version controlled files for the given revision.
1526 Print a list of version controlled files for the given revision.
1538
1527
1539 The manifest is the list of files being version controlled. If no revision
1528 The manifest is the list of files being version controlled. If no revision
1540 is given then the tip is used.
1529 is given then the tip is used.
1541 """
1530 """
1542 if rev:
1531 if rev:
1543 try:
1532 try:
1544 # assume all revision numbers are for changesets
1533 # assume all revision numbers are for changesets
1545 n = repo.lookup(rev)
1534 n = repo.lookup(rev)
1546 change = repo.changelog.read(n)
1535 change = repo.changelog.read(n)
1547 n = change[0]
1536 n = change[0]
1548 except hg.RepoError:
1537 except hg.RepoError:
1549 n = repo.manifest.lookup(rev)
1538 n = repo.manifest.lookup(rev)
1550 else:
1539 else:
1551 n = repo.manifest.tip()
1540 n = repo.manifest.tip()
1552 m = repo.manifest.read(n)
1541 m = repo.manifest.read(n)
1553 mf = repo.manifest.readflags(n)
1542 mf = repo.manifest.readflags(n)
1554 files = m.keys()
1543 files = m.keys()
1555 files.sort()
1544 files.sort()
1556
1545
1557 for f in files:
1546 for f in files:
1558 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1547 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1559
1548
1560 def outgoing(ui, repo, dest="default-push", **opts):
1549 def outgoing(ui, repo, dest="default-push", **opts):
1561 """show changesets not found in destination
1550 """show changesets not found in destination
1562
1551
1563 Show changesets not found in the specified destination repo or the
1552 Show changesets not found in the specified destination repo or the
1564 default push repo. These are the changesets that would be pushed
1553 default push repo. These are the changesets that would be pushed
1565 if a push was requested.
1554 if a push was requested.
1566 """
1555 """
1567 dest = ui.expandpath(dest, repo.root)
1556 dest = ui.expandpath(dest, repo.root)
1568 other = hg.repository(ui, dest)
1557 other = hg.repository(ui, dest)
1569 o = repo.findoutgoing(other)
1558 o = repo.findoutgoing(other)
1570 o = repo.changelog.nodesbetween(o)[0]
1559 o = repo.changelog.nodesbetween(o)[0]
1571 if opts['newest_first']:
1560 if opts['newest_first']:
1572 o.reverse()
1561 o.reverse()
1573 for n in o:
1562 for n in o:
1574 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1563 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1575 if opts['no_merges'] and len(parents) == 2:
1564 if opts['no_merges'] and len(parents) == 2:
1576 continue
1565 continue
1577 show_changeset(ui, repo, changenode=n)
1566 show_changeset(ui, repo, changenode=n)
1578 if opts['patch']:
1567 if opts['patch']:
1579 prev = (parents and parents[0]) or nullid
1568 prev = (parents and parents[0]) or nullid
1580 dodiff(ui, ui, repo, prev, n)
1569 dodiff(ui, ui, repo, prev, n)
1581 ui.write("\n")
1570 ui.write("\n")
1582
1571
1583 def parents(ui, repo, rev=None):
1572 def parents(ui, repo, rev=None):
1584 """show the parents of the working dir or revision
1573 """show the parents of the working dir or revision
1585
1574
1586 Print the working directory's parent revisions.
1575 Print the working directory's parent revisions.
1587 """
1576 """
1588 if rev:
1577 if rev:
1589 p = repo.changelog.parents(repo.lookup(rev))
1578 p = repo.changelog.parents(repo.lookup(rev))
1590 else:
1579 else:
1591 p = repo.dirstate.parents()
1580 p = repo.dirstate.parents()
1592
1581
1593 for n in p:
1582 for n in p:
1594 if n != nullid:
1583 if n != nullid:
1595 show_changeset(ui, repo, changenode=n)
1584 show_changeset(ui, repo, changenode=n)
1596
1585
1597 def paths(ui, search=None):
1586 def paths(ui, search=None):
1598 """show definition of symbolic path names
1587 """show definition of symbolic path names
1599
1588
1600 Show definition of symbolic path name NAME. If no name is given, show
1589 Show definition of symbolic path name NAME. If no name is given, show
1601 definition of available names.
1590 definition of available names.
1602
1591
1603 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1592 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1604 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1593 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1605 """
1594 """
1606 try:
1595 try:
1607 repo = hg.repository(ui=ui)
1596 repo = hg.repository(ui=ui)
1608 except hg.RepoError:
1597 except hg.RepoError:
1609 pass
1598 pass
1610
1599
1611 if search:
1600 if search:
1612 for name, path in ui.configitems("paths"):
1601 for name, path in ui.configitems("paths"):
1613 if name == search:
1602 if name == search:
1614 ui.write("%s\n" % path)
1603 ui.write("%s\n" % path)
1615 return
1604 return
1616 ui.warn(_("not found!\n"))
1605 ui.warn(_("not found!\n"))
1617 return 1
1606 return 1
1618 else:
1607 else:
1619 for name, path in ui.configitems("paths"):
1608 for name, path in ui.configitems("paths"):
1620 ui.write("%s = %s\n" % (name, path))
1609 ui.write("%s = %s\n" % (name, path))
1621
1610
1622 def pull(ui, repo, source="default", **opts):
1611 def pull(ui, repo, source="default", **opts):
1623 """pull changes from the specified source
1612 """pull changes from the specified source
1624
1613
1625 Pull changes from a remote repository to a local one.
1614 Pull changes from a remote repository to a local one.
1626
1615
1627 This finds all changes from the repository at the specified path
1616 This finds all changes from the repository at the specified path
1628 or URL and adds them to the local repository. By default, this
1617 or URL and adds them to the local repository. By default, this
1629 does not update the copy of the project in the working directory.
1618 does not update the copy of the project in the working directory.
1630
1619
1631 Valid URLs are of the form:
1620 Valid URLs are of the form:
1632
1621
1633 local/filesystem/path
1622 local/filesystem/path
1634 http://[user@]host[:port][/path]
1623 http://[user@]host[:port][/path]
1635 https://[user@]host[:port][/path]
1624 https://[user@]host[:port][/path]
1636 ssh://[user@]host[:port][/path]
1625 ssh://[user@]host[:port][/path]
1637
1626
1638 SSH requires an accessible shell account on the destination machine
1627 SSH requires an accessible shell account on the destination machine
1639 and a copy of hg in the remote path. With SSH, paths are relative
1628 and a copy of hg in the remote path. With SSH, paths are relative
1640 to the remote user's home directory by default; use two slashes at
1629 to the remote user's home directory by default; use two slashes at
1641 the start of a path to specify it as relative to the filesystem root.
1630 the start of a path to specify it as relative to the filesystem root.
1642 """
1631 """
1643 source = ui.expandpath(source, repo.root)
1632 source = ui.expandpath(source, repo.root)
1644 ui.status(_('pulling from %s\n') % (source))
1633 ui.status(_('pulling from %s\n') % (source))
1645
1634
1646 if opts['ssh']:
1635 if opts['ssh']:
1647 ui.setconfig("ui", "ssh", opts['ssh'])
1636 ui.setconfig("ui", "ssh", opts['ssh'])
1648 if opts['remotecmd']:
1637 if opts['remotecmd']:
1649 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1638 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1650
1639
1651 other = hg.repository(ui, source)
1640 other = hg.repository(ui, source)
1652 revs = None
1641 revs = None
1653 if opts['rev'] and not other.local():
1642 if opts['rev'] and not other.local():
1654 raise util.Abort("pull -r doesn't work for remote repositories yet")
1643 raise util.Abort("pull -r doesn't work for remote repositories yet")
1655 elif opts['rev']:
1644 elif opts['rev']:
1656 revs = [other.lookup(rev) for rev in opts['rev']]
1645 revs = [other.lookup(rev) for rev in opts['rev']]
1657 r = repo.pull(other, heads=revs)
1646 r = repo.pull(other, heads=revs)
1658 if not r:
1647 if not r:
1659 if opts['update']:
1648 if opts['update']:
1660 return update(ui, repo)
1649 return update(ui, repo)
1661 else:
1650 else:
1662 ui.status(_("(run 'hg update' to get a working copy)\n"))
1651 ui.status(_("(run 'hg update' to get a working copy)\n"))
1663
1652
1664 return r
1653 return r
1665
1654
1666 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1655 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1667 """push changes to the specified destination
1656 """push changes to the specified destination
1668
1657
1669 Push changes from the local repository to the given destination.
1658 Push changes from the local repository to the given destination.
1670
1659
1671 This is the symmetrical operation for pull. It helps to move
1660 This is the symmetrical operation for pull. It helps to move
1672 changes from the current repository to a different one. If the
1661 changes from the current repository to a different one. If the
1673 destination is local this is identical to a pull in that directory
1662 destination is local this is identical to a pull in that directory
1674 from the current one.
1663 from the current one.
1675
1664
1676 By default, push will refuse to run if it detects the result would
1665 By default, push will refuse to run if it detects the result would
1677 increase the number of remote heads. This generally indicates the
1666 increase the number of remote heads. This generally indicates the
1678 the client has forgotten to sync and merge before pushing.
1667 the client has forgotten to sync and merge before pushing.
1679
1668
1680 Valid URLs are of the form:
1669 Valid URLs are of the form:
1681
1670
1682 local/filesystem/path
1671 local/filesystem/path
1683 ssh://[user@]host[:port][/path]
1672 ssh://[user@]host[:port][/path]
1684
1673
1685 SSH requires an accessible shell account on the destination
1674 SSH requires an accessible shell account on the destination
1686 machine and a copy of hg in the remote path.
1675 machine and a copy of hg in the remote path.
1687 """
1676 """
1688 dest = ui.expandpath(dest, repo.root)
1677 dest = ui.expandpath(dest, repo.root)
1689 ui.status('pushing to %s\n' % (dest))
1678 ui.status('pushing to %s\n' % (dest))
1690
1679
1691 if ssh:
1680 if ssh:
1692 ui.setconfig("ui", "ssh", ssh)
1681 ui.setconfig("ui", "ssh", ssh)
1693 if remotecmd:
1682 if remotecmd:
1694 ui.setconfig("ui", "remotecmd", remotecmd)
1683 ui.setconfig("ui", "remotecmd", remotecmd)
1695
1684
1696 other = hg.repository(ui, dest)
1685 other = hg.repository(ui, dest)
1697 r = repo.push(other, force)
1686 r = repo.push(other, force)
1698 return r
1687 return r
1699
1688
1700 def rawcommit(ui, repo, *flist, **rc):
1689 def rawcommit(ui, repo, *flist, **rc):
1701 """raw commit interface
1690 """raw commit interface
1702
1691
1703 Lowlevel commit, for use in helper scripts.
1692 Lowlevel commit, for use in helper scripts.
1704
1693
1705 This command is not intended to be used by normal users, as it is
1694 This command is not intended to be used by normal users, as it is
1706 primarily useful for importing from other SCMs.
1695 primarily useful for importing from other SCMs.
1707 """
1696 """
1708 message = rc['message']
1697 message = rc['message']
1709 if not message and rc['logfile']:
1698 if not message and rc['logfile']:
1710 try:
1699 try:
1711 message = open(rc['logfile']).read()
1700 message = open(rc['logfile']).read()
1712 except IOError:
1701 except IOError:
1713 pass
1702 pass
1714 if not message and not rc['logfile']:
1703 if not message and not rc['logfile']:
1715 raise util.Abort(_("missing commit message"))
1704 raise util.Abort(_("missing commit message"))
1716
1705
1717 files = relpath(repo, list(flist))
1706 files = relpath(repo, list(flist))
1718 if rc['files']:
1707 if rc['files']:
1719 files += open(rc['files']).read().splitlines()
1708 files += open(rc['files']).read().splitlines()
1720
1709
1721 rc['parent'] = map(repo.lookup, rc['parent'])
1710 rc['parent'] = map(repo.lookup, rc['parent'])
1722
1711
1723 try:
1712 try:
1724 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1713 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1725 except ValueError, inst:
1714 except ValueError, inst:
1726 raise util.Abort(str(inst))
1715 raise util.Abort(str(inst))
1727
1716
1728 def recover(ui, repo):
1717 def recover(ui, repo):
1729 """roll back an interrupted transaction
1718 """roll back an interrupted transaction
1730
1719
1731 Recover from an interrupted commit or pull.
1720 Recover from an interrupted commit or pull.
1732
1721
1733 This command tries to fix the repository status after an interrupted
1722 This command tries to fix the repository status after an interrupted
1734 operation. It should only be necessary when Mercurial suggests it.
1723 operation. It should only be necessary when Mercurial suggests it.
1735 """
1724 """
1736 repo.recover()
1725 repo.recover()
1737
1726
1738 def remove(ui, repo, pat, *pats, **opts):
1727 def remove(ui, repo, pat, *pats, **opts):
1739 """remove the specified files on the next commit
1728 """remove the specified files on the next commit
1740
1729
1741 Schedule the indicated files for removal from the repository.
1730 Schedule the indicated files for removal from the repository.
1742
1731
1743 This command schedules the files to be removed at the next commit.
1732 This command schedules the files to be removed at the next commit.
1744 This only removes files from the current branch, not from the
1733 This only removes files from the current branch, not from the
1745 entire project history. If the files still exist in the working
1734 entire project history. If the files still exist in the working
1746 directory, they will be deleted from it.
1735 directory, they will be deleted from it.
1747 """
1736 """
1748 names = []
1737 names = []
1749 def okaytoremove(abs, rel, exact):
1738 def okaytoremove(abs, rel, exact):
1750 c, a, d, u = repo.changes(files = [abs])
1739 c, a, d, u = repo.changes(files = [abs])
1751 reason = None
1740 reason = None
1752 if c: reason = _('is modified')
1741 if c: reason = _('is modified')
1753 elif a: reason = _('has been marked for add')
1742 elif a: reason = _('has been marked for add')
1754 elif u: reason = _('is not managed')
1743 elif u: reason = _('is not managed')
1755 if reason:
1744 if reason:
1756 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1745 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1757 else:
1746 else:
1758 return True
1747 return True
1759 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1748 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1760 if okaytoremove(abs, rel, exact):
1749 if okaytoremove(abs, rel, exact):
1761 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1750 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1762 names.append(abs)
1751 names.append(abs)
1763 repo.remove(names, unlink=True)
1752 repo.remove(names, unlink=True)
1764
1753
1765 def rename(ui, repo, *pats, **opts):
1754 def rename(ui, repo, *pats, **opts):
1766 """rename files; equivalent of copy + remove
1755 """rename files; equivalent of copy + remove
1767
1756
1768 Mark dest as copies of sources; mark sources for deletion. If
1757 Mark dest as copies of sources; mark sources for deletion. If
1769 dest is a directory, copies are put in that directory. If dest is
1758 dest is a directory, copies are put in that directory. If dest is
1770 a file, there can only be one source.
1759 a file, there can only be one source.
1771
1760
1772 By default, this command copies the contents of files as they
1761 By default, this command copies the contents of files as they
1773 stand in the working directory. If invoked with --after, the
1762 stand in the working directory. If invoked with --after, the
1774 operation is recorded, but no copying is performed.
1763 operation is recorded, but no copying is performed.
1775
1764
1776 This command takes effect in the next commit.
1765 This command takes effect in the next commit.
1777
1766
1778 NOTE: This command should be treated as experimental. While it
1767 NOTE: This command should be treated as experimental. While it
1779 should properly record rename files, this information is not yet
1768 should properly record rename files, this information is not yet
1780 fully used by merge, nor fully reported by log.
1769 fully used by merge, nor fully reported by log.
1781 """
1770 """
1782 errs, copied = docopy(ui, repo, pats, opts)
1771 errs, copied = docopy(ui, repo, pats, opts)
1783 names = []
1772 names = []
1784 for abs, rel, exact in copied:
1773 for abs, rel, exact in copied:
1785 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1774 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1786 names.append(abs)
1775 names.append(abs)
1787 repo.remove(names, unlink=True)
1776 repo.remove(names, unlink=True)
1788 return errs
1777 return errs
1789
1778
1790 def revert(ui, repo, *pats, **opts):
1779 def revert(ui, repo, *pats, **opts):
1791 """revert modified files or dirs back to their unmodified states
1780 """revert modified files or dirs back to their unmodified states
1792
1781
1793 Revert any uncommitted modifications made to the named files or
1782 Revert any uncommitted modifications made to the named files or
1794 directories. This restores the contents of the affected files to
1783 directories. This restores the contents of the affected files to
1795 an unmodified state.
1784 an unmodified state.
1796
1785
1797 If a file has been deleted, it is recreated. If the executable
1786 If a file has been deleted, it is recreated. If the executable
1798 mode of a file was changed, it is reset.
1787 mode of a file was changed, it is reset.
1799
1788
1800 If names are given, all files matching the names are reverted.
1789 If names are given, all files matching the names are reverted.
1801
1790
1802 If no names are given, all files in the current directory and
1791 If no names are given, all files in the current directory and
1803 its subdirectories are reverted.
1792 its subdirectories are reverted.
1804 """
1793 """
1805 node = opts['rev'] and repo.lookup(opts['rev']) or \
1794 node = opts['rev'] and repo.lookup(opts['rev']) or \
1806 repo.dirstate.parents()[0]
1795 repo.dirstate.parents()[0]
1807
1796
1808 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1797 files, choose, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1809 (c, a, d, u) = repo.changes(match=choose)
1798 (c, a, d, u) = repo.changes(match=choose)
1810 repo.forget(a)
1799 repo.forget(a)
1811 repo.undelete(d)
1800 repo.undelete(d)
1812
1801
1813 return repo.update(node, False, True, choose, False)
1802 return repo.update(node, False, True, choose, False)
1814
1803
1815 def root(ui, repo):
1804 def root(ui, repo):
1816 """print the root (top) of the current working dir
1805 """print the root (top) of the current working dir
1817
1806
1818 Print the root directory of the current repository.
1807 Print the root directory of the current repository.
1819 """
1808 """
1820 ui.write(repo.root + "\n")
1809 ui.write(repo.root + "\n")
1821
1810
1822 def serve(ui, repo, **opts):
1811 def serve(ui, repo, **opts):
1823 """export the repository via HTTP
1812 """export the repository via HTTP
1824
1813
1825 Start a local HTTP repository browser and pull server.
1814 Start a local HTTP repository browser and pull server.
1826
1815
1827 By default, the server logs accesses to stdout and errors to
1816 By default, the server logs accesses to stdout and errors to
1828 stderr. Use the "-A" and "-E" options to log to files.
1817 stderr. Use the "-A" and "-E" options to log to files.
1829 """
1818 """
1830
1819
1831 if opts["stdio"]:
1820 if opts["stdio"]:
1832 fin, fout = sys.stdin, sys.stdout
1821 fin, fout = sys.stdin, sys.stdout
1833 sys.stdout = sys.stderr
1822 sys.stdout = sys.stderr
1834
1823
1835 # Prevent insertion/deletion of CRs
1824 # Prevent insertion/deletion of CRs
1836 util.set_binary(fin)
1825 util.set_binary(fin)
1837 util.set_binary(fout)
1826 util.set_binary(fout)
1838
1827
1839 def getarg():
1828 def getarg():
1840 argline = fin.readline()[:-1]
1829 argline = fin.readline()[:-1]
1841 arg, l = argline.split()
1830 arg, l = argline.split()
1842 val = fin.read(int(l))
1831 val = fin.read(int(l))
1843 return arg, val
1832 return arg, val
1844 def respond(v):
1833 def respond(v):
1845 fout.write("%d\n" % len(v))
1834 fout.write("%d\n" % len(v))
1846 fout.write(v)
1835 fout.write(v)
1847 fout.flush()
1836 fout.flush()
1848
1837
1849 lock = None
1838 lock = None
1850
1839
1851 while 1:
1840 while 1:
1852 cmd = fin.readline()[:-1]
1841 cmd = fin.readline()[:-1]
1853 if cmd == '':
1842 if cmd == '':
1854 return
1843 return
1855 if cmd == "heads":
1844 if cmd == "heads":
1856 h = repo.heads()
1845 h = repo.heads()
1857 respond(" ".join(map(hex, h)) + "\n")
1846 respond(" ".join(map(hex, h)) + "\n")
1858 if cmd == "lock":
1847 if cmd == "lock":
1859 lock = repo.lock()
1848 lock = repo.lock()
1860 respond("")
1849 respond("")
1861 if cmd == "unlock":
1850 if cmd == "unlock":
1862 if lock:
1851 if lock:
1863 lock.release()
1852 lock.release()
1864 lock = None
1853 lock = None
1865 respond("")
1854 respond("")
1866 elif cmd == "branches":
1855 elif cmd == "branches":
1867 arg, nodes = getarg()
1856 arg, nodes = getarg()
1868 nodes = map(bin, nodes.split(" "))
1857 nodes = map(bin, nodes.split(" "))
1869 r = []
1858 r = []
1870 for b in repo.branches(nodes):
1859 for b in repo.branches(nodes):
1871 r.append(" ".join(map(hex, b)) + "\n")
1860 r.append(" ".join(map(hex, b)) + "\n")
1872 respond("".join(r))
1861 respond("".join(r))
1873 elif cmd == "between":
1862 elif cmd == "between":
1874 arg, pairs = getarg()
1863 arg, pairs = getarg()
1875 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1864 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1876 r = []
1865 r = []
1877 for b in repo.between(pairs):
1866 for b in repo.between(pairs):
1878 r.append(" ".join(map(hex, b)) + "\n")
1867 r.append(" ".join(map(hex, b)) + "\n")
1879 respond("".join(r))
1868 respond("".join(r))
1880 elif cmd == "changegroup":
1869 elif cmd == "changegroup":
1881 nodes = []
1870 nodes = []
1882 arg, roots = getarg()
1871 arg, roots = getarg()
1883 nodes = map(bin, roots.split(" "))
1872 nodes = map(bin, roots.split(" "))
1884
1873
1885 cg = repo.changegroup(nodes)
1874 cg = repo.changegroup(nodes)
1886 while 1:
1875 while 1:
1887 d = cg.read(4096)
1876 d = cg.read(4096)
1888 if not d:
1877 if not d:
1889 break
1878 break
1890 fout.write(d)
1879 fout.write(d)
1891
1880
1892 fout.flush()
1881 fout.flush()
1893
1882
1894 elif cmd == "addchangegroup":
1883 elif cmd == "addchangegroup":
1895 if not lock:
1884 if not lock:
1896 respond("not locked")
1885 respond("not locked")
1897 continue
1886 continue
1898 respond("")
1887 respond("")
1899
1888
1900 r = repo.addchangegroup(fin)
1889 r = repo.addchangegroup(fin)
1901 respond("")
1890 respond("")
1902
1891
1903 optlist = "name templates style address port ipv6 accesslog errorlog"
1892 optlist = "name templates style address port ipv6 accesslog errorlog"
1904 for o in optlist.split():
1893 for o in optlist.split():
1905 if opts[o]:
1894 if opts[o]:
1906 ui.setconfig("web", o, opts[o])
1895 ui.setconfig("web", o, opts[o])
1907
1896
1908 try:
1897 try:
1909 httpd = hgweb.create_server(repo)
1898 httpd = hgweb.create_server(repo)
1910 except socket.error, inst:
1899 except socket.error, inst:
1911 raise util.Abort('cannot start server: ' + inst.args[1])
1900 raise util.Abort('cannot start server: ' + inst.args[1])
1912
1901
1913 if ui.verbose:
1902 if ui.verbose:
1914 addr, port = httpd.socket.getsockname()
1903 addr, port = httpd.socket.getsockname()
1915 if addr == '0.0.0.0':
1904 if addr == '0.0.0.0':
1916 addr = socket.gethostname()
1905 addr = socket.gethostname()
1917 else:
1906 else:
1918 try:
1907 try:
1919 addr = socket.gethostbyaddr(addr)[0]
1908 addr = socket.gethostbyaddr(addr)[0]
1920 except socket.error:
1909 except socket.error:
1921 pass
1910 pass
1922 if port != 80:
1911 if port != 80:
1923 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1912 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1924 else:
1913 else:
1925 ui.status(_('listening at http://%s/\n') % addr)
1914 ui.status(_('listening at http://%s/\n') % addr)
1926 httpd.serve_forever()
1915 httpd.serve_forever()
1927
1916
1928 def status(ui, repo, *pats, **opts):
1917 def status(ui, repo, *pats, **opts):
1929 """show changed files in the working directory
1918 """show changed files in the working directory
1930
1919
1931 Show changed files in the working directory. If no names are
1920 Show changed files in the working directory. If no names are
1932 given, all files are shown. Otherwise, only files matching the
1921 given, all files are shown. Otherwise, only files matching the
1933 given names are shown.
1922 given names are shown.
1934
1923
1935 The codes used to show the status of files are:
1924 The codes used to show the status of files are:
1936 M = modified
1925 M = modified
1937 A = added
1926 A = added
1938 R = removed
1927 R = removed
1939 ? = not tracked
1928 ? = not tracked
1940 """
1929 """
1941
1930
1942 cwd = repo.getcwd()
1931 cwd = repo.getcwd()
1943 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1932 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1944 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1933 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1945 for n in repo.changes(files=files, match=matchfn)]
1934 for n in repo.changes(files=files, match=matchfn)]
1946
1935
1947 changetypes = [(_('modified'), 'M', c),
1936 changetypes = [(_('modified'), 'M', c),
1948 (_('added'), 'A', a),
1937 (_('added'), 'A', a),
1949 (_('removed'), 'R', d),
1938 (_('removed'), 'R', d),
1950 (_('unknown'), '?', u)]
1939 (_('unknown'), '?', u)]
1951
1940
1952 end = opts['print0'] and '\0' or '\n'
1941 end = opts['print0'] and '\0' or '\n'
1953
1942
1954 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1943 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1955 or changetypes):
1944 or changetypes):
1956 if opts['no_status']:
1945 if opts['no_status']:
1957 format = "%%s%s" % end
1946 format = "%%s%s" % end
1958 else:
1947 else:
1959 format = "%s %%s%s" % (char, end);
1948 format = "%s %%s%s" % (char, end);
1960
1949
1961 for f in changes:
1950 for f in changes:
1962 ui.write(format % f)
1951 ui.write(format % f)
1963
1952
1964 def tag(ui, repo, name, rev=None, **opts):
1953 def tag(ui, repo, name, rev=None, **opts):
1965 """add a tag for the current tip or a given revision
1954 """add a tag for the current tip or a given revision
1966
1955
1967 Name a particular revision using <name>.
1956 Name a particular revision using <name>.
1968
1957
1969 Tags are used to name particular revisions of the repository and are
1958 Tags are used to name particular revisions of the repository and are
1970 very useful to compare different revision, to go back to significant
1959 very useful to compare different revision, to go back to significant
1971 earlier versions or to mark branch points as releases, etc.
1960 earlier versions or to mark branch points as releases, etc.
1972
1961
1973 If no revision is given, the tip is used.
1962 If no revision is given, the tip is used.
1974
1963
1975 To facilitate version control, distribution, and merging of tags,
1964 To facilitate version control, distribution, and merging of tags,
1976 they are stored as a file named ".hgtags" which is managed
1965 they are stored as a file named ".hgtags" which is managed
1977 similarly to other project files and can be hand-edited if
1966 similarly to other project files and can be hand-edited if
1978 necessary.
1967 necessary.
1979 """
1968 """
1980 if name == "tip":
1969 if name == "tip":
1981 raise util.Abort(_("the name 'tip' is reserved"))
1970 raise util.Abort(_("the name 'tip' is reserved"))
1982 if 'rev' in opts:
1971 if 'rev' in opts:
1983 rev = opts['rev']
1972 rev = opts['rev']
1984 if rev:
1973 if rev:
1985 r = hex(repo.lookup(rev))
1974 r = hex(repo.lookup(rev))
1986 else:
1975 else:
1987 r = hex(repo.changelog.tip())
1976 r = hex(repo.changelog.tip())
1988
1977
1989 if name.find(revrangesep) >= 0:
1978 if name.find(revrangesep) >= 0:
1990 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
1979 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
1991
1980
1992 if opts['local']:
1981 if opts['local']:
1993 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1982 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1994 return
1983 return
1995
1984
1996 (c, a, d, u) = repo.changes()
1985 (c, a, d, u) = repo.changes()
1997 for x in (c, a, d, u):
1986 for x in (c, a, d, u):
1998 if ".hgtags" in x:
1987 if ".hgtags" in x:
1999 raise util.Abort(_("working copy of .hgtags is changed "
1988 raise util.Abort(_("working copy of .hgtags is changed "
2000 "(please commit .hgtags manually)"))
1989 "(please commit .hgtags manually)"))
2001
1990
2002 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1991 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2003 if repo.dirstate.state(".hgtags") == '?':
1992 if repo.dirstate.state(".hgtags") == '?':
2004 repo.add([".hgtags"])
1993 repo.add([".hgtags"])
2005
1994
2006 message = (opts['message'] or
1995 message = (opts['message'] or
2007 _("Added tag %s for changeset %s") % (name, r))
1996 _("Added tag %s for changeset %s") % (name, r))
2008 try:
1997 try:
2009 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1998 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2010 except ValueError, inst:
1999 except ValueError, inst:
2011 raise util.Abort(str(inst))
2000 raise util.Abort(str(inst))
2012
2001
2013 def tags(ui, repo):
2002 def tags(ui, repo):
2014 """list repository tags
2003 """list repository tags
2015
2004
2016 List the repository tags.
2005 List the repository tags.
2017
2006
2018 This lists both regular and local tags.
2007 This lists both regular and local tags.
2019 """
2008 """
2020
2009
2021 l = repo.tagslist()
2010 l = repo.tagslist()
2022 l.reverse()
2011 l.reverse()
2023 for t, n in l:
2012 for t, n in l:
2024 try:
2013 try:
2025 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2014 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2026 except KeyError:
2015 except KeyError:
2027 r = " ?:?"
2016 r = " ?:?"
2028 ui.write("%-30s %s\n" % (t, r))
2017 ui.write("%-30s %s\n" % (t, r))
2029
2018
2030 def tip(ui, repo):
2019 def tip(ui, repo):
2031 """show the tip revision
2020 """show the tip revision
2032
2021
2033 Show the tip revision.
2022 Show the tip revision.
2034 """
2023 """
2035 n = repo.changelog.tip()
2024 n = repo.changelog.tip()
2036 show_changeset(ui, repo, changenode=n)
2025 show_changeset(ui, repo, changenode=n)
2037
2026
2038 def unbundle(ui, repo, fname):
2027 def unbundle(ui, repo, fname):
2039 """apply a changegroup file
2028 """apply a changegroup file
2040
2029
2041 Apply a compressed changegroup file generated by the bundle
2030 Apply a compressed changegroup file generated by the bundle
2042 command.
2031 command.
2043 """
2032 """
2044 f = urllib.urlopen(fname)
2033 f = urllib.urlopen(fname)
2045
2034
2046 if f.read(4) != "HG10":
2035 if f.read(4) != "HG10":
2047 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2036 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2048
2037
2049 def bzgenerator(f):
2038 def bzgenerator(f):
2050 zd = bz2.BZ2Decompressor()
2039 zd = bz2.BZ2Decompressor()
2051 for chunk in f:
2040 for chunk in f:
2052 yield zd.decompress(chunk)
2041 yield zd.decompress(chunk)
2053
2042
2054 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2043 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2055 repo.addchangegroup(util.chunkbuffer(bzgen))
2044 repo.addchangegroup(util.chunkbuffer(bzgen))
2056
2045
2057 def undo(ui, repo):
2046 def undo(ui, repo):
2058 """undo the last commit or pull
2047 """undo the last commit or pull
2059
2048
2060 Roll back the last pull or commit transaction on the
2049 Roll back the last pull or commit transaction on the
2061 repository, restoring the project to its earlier state.
2050 repository, restoring the project to its earlier state.
2062
2051
2063 This command should be used with care. There is only one level of
2052 This command should be used with care. There is only one level of
2064 undo and there is no redo.
2053 undo and there is no redo.
2065
2054
2066 This command is not intended for use on public repositories. Once
2055 This command is not intended for use on public repositories. Once
2067 a change is visible for pull by other users, undoing it locally is
2056 a change is visible for pull by other users, undoing it locally is
2068 ineffective.
2057 ineffective.
2069 """
2058 """
2070 repo.undo()
2059 repo.undo()
2071
2060
2072 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2061 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2073 """update or merge working directory
2062 """update or merge working directory
2074
2063
2075 Update the working directory to the specified revision.
2064 Update the working directory to the specified revision.
2076
2065
2077 If there are no outstanding changes in the working directory and
2066 If there are no outstanding changes in the working directory and
2078 there is a linear relationship between the current version and the
2067 there is a linear relationship between the current version and the
2079 requested version, the result is the requested version.
2068 requested version, the result is the requested version.
2080
2069
2081 Otherwise the result is a merge between the contents of the
2070 Otherwise the result is a merge between the contents of the
2082 current working directory and the requested version. Files that
2071 current working directory and the requested version. Files that
2083 changed between either parent are marked as changed for the next
2072 changed between either parent are marked as changed for the next
2084 commit and a commit must be performed before any further updates
2073 commit and a commit must be performed before any further updates
2085 are allowed.
2074 are allowed.
2086
2075
2087 By default, update will refuse to run if doing so would require
2076 By default, update will refuse to run if doing so would require
2088 merging or discarding local changes.
2077 merging or discarding local changes.
2089 """
2078 """
2090 if branch:
2079 if branch:
2091 br = repo.branchlookup(branch=branch)
2080 br = repo.branchlookup(branch=branch)
2092 found = []
2081 found = []
2093 for x in br:
2082 for x in br:
2094 if branch in br[x]:
2083 if branch in br[x]:
2095 found.append(x)
2084 found.append(x)
2096 if len(found) > 1:
2085 if len(found) > 1:
2097 ui.warn(_("Found multiple heads for %s\n") % branch)
2086 ui.warn(_("Found multiple heads for %s\n") % branch)
2098 for x in found:
2087 for x in found:
2099 show_changeset(ui, repo, changenode=x, brinfo=br)
2088 show_changeset(ui, repo, changenode=x, brinfo=br)
2100 return 1
2089 return 1
2101 if len(found) == 1:
2090 if len(found) == 1:
2102 node = found[0]
2091 node = found[0]
2103 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2092 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2104 else:
2093 else:
2105 ui.warn(_("branch %s not found\n") % (branch))
2094 ui.warn(_("branch %s not found\n") % (branch))
2106 return 1
2095 return 1
2107 else:
2096 else:
2108 node = node and repo.lookup(node) or repo.changelog.tip()
2097 node = node and repo.lookup(node) or repo.changelog.tip()
2109 return repo.update(node, allow=merge, force=clean)
2098 return repo.update(node, allow=merge, force=clean)
2110
2099
2111 def verify(ui, repo):
2100 def verify(ui, repo):
2112 """verify the integrity of the repository
2101 """verify the integrity of the repository
2113
2102
2114 Verify the integrity of the current repository.
2103 Verify the integrity of the current repository.
2115
2104
2116 This will perform an extensive check of the repository's
2105 This will perform an extensive check of the repository's
2117 integrity, validating the hashes and checksums of each entry in
2106 integrity, validating the hashes and checksums of each entry in
2118 the changelog, manifest, and tracked files, as well as the
2107 the changelog, manifest, and tracked files, as well as the
2119 integrity of their crosslinks and indices.
2108 integrity of their crosslinks and indices.
2120 """
2109 """
2121 return repo.verify()
2110 return repo.verify()
2122
2111
2123 # Command options and aliases are listed here, alphabetically
2112 # Command options and aliases are listed here, alphabetically
2124
2113
2125 table = {
2114 table = {
2126 "^add":
2115 "^add":
2127 (add,
2116 (add,
2128 [('I', 'include', [], _('include names matching the given patterns')),
2117 [('I', 'include', [], _('include names matching the given patterns')),
2129 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2118 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2130 "hg add [OPTION]... [FILE]..."),
2119 "hg add [OPTION]... [FILE]..."),
2131 "addremove":
2120 "addremove":
2132 (addremove,
2121 (addremove,
2133 [('I', 'include', [], _('include names matching the given patterns')),
2122 [('I', 'include', [], _('include names matching the given patterns')),
2134 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2123 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2135 "hg addremove [OPTION]... [FILE]..."),
2124 "hg addremove [OPTION]... [FILE]..."),
2136 "^annotate":
2125 "^annotate":
2137 (annotate,
2126 (annotate,
2138 [('r', 'rev', '', _('annotate the specified revision')),
2127 [('r', 'rev', '', _('annotate the specified revision')),
2139 ('a', 'text', None, _('treat all files as text')),
2128 ('a', 'text', None, _('treat all files as text')),
2140 ('u', 'user', None, _('list the author')),
2129 ('u', 'user', None, _('list the author')),
2141 ('n', 'number', None, _('list the revision number (default)')),
2130 ('n', 'number', None, _('list the revision number (default)')),
2142 ('c', 'changeset', None, _('list the changeset')),
2131 ('c', 'changeset', None, _('list the changeset')),
2143 ('I', 'include', [], _('include names matching the given patterns')),
2132 ('I', 'include', [], _('include names matching the given patterns')),
2144 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2133 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2145 _('hg annotate [OPTION]... FILE...')),
2134 _('hg annotate [OPTION]... FILE...')),
2146 "bundle":
2135 "bundle":
2147 (bundle,
2136 (bundle,
2148 [],
2137 [],
2149 _('hg bundle FILE DEST')),
2138 _('hg bundle FILE DEST')),
2150 "cat":
2139 "cat":
2151 (cat,
2140 (cat,
2152 [('I', 'include', [], _('include names matching the given patterns')),
2141 [('I', 'include', [], _('include names matching the given patterns')),
2153 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2142 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2154 ('o', 'output', "", _('print output to file with formatted name')),
2143 ('o', 'output', "", _('print output to file with formatted name')),
2155 ('r', 'rev', '', _('print the given revision'))],
2144 ('r', 'rev', '', _('print the given revision'))],
2156 _('hg cat [OPTION]... FILE...')),
2145 _('hg cat [OPTION]... FILE...')),
2157 "^clone":
2146 "^clone":
2158 (clone,
2147 (clone,
2159 [('U', 'noupdate', None, _('do not update the new working directory')),
2148 [('U', 'noupdate', None, _('do not update the new working directory')),
2160 ('e', 'ssh', "", _('specify ssh command to use')),
2149 ('e', 'ssh', "", _('specify ssh command to use')),
2161 ('', 'pull', None, _('use pull protocol to copy metadata')),
2150 ('', 'pull', None, _('use pull protocol to copy metadata')),
2162 ('r', 'rev', [], _('a changeset you would like to have after cloning')),
2151 ('r', 'rev', [], _('a changeset you would like to have after cloning')),
2163 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2152 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2164 _('hg clone [OPTION]... SOURCE [DEST]')),
2153 _('hg clone [OPTION]... SOURCE [DEST]')),
2165 "^commit|ci":
2154 "^commit|ci":
2166 (commit,
2155 (commit,
2167 [('A', 'addremove', None, _('run addremove during commit')),
2156 [('A', 'addremove', None, _('run addremove during commit')),
2168 ('I', 'include', [], _('include names matching the given patterns')),
2157 ('I', 'include', [], _('include names matching the given patterns')),
2169 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2158 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2170 ('m', 'message', "", _('use <text> as commit message')),
2159 ('m', 'message', "", _('use <text> as commit message')),
2171 ('l', 'logfile', "", _('read the commit message from <file>')),
2160 ('l', 'logfile', "", _('read the commit message from <file>')),
2172 ('d', 'date', "", _('record datecode as commit date')),
2161 ('d', 'date', "", _('record datecode as commit date')),
2173 ('u', 'user', "", _('record user as commiter'))],
2162 ('u', 'user', "", _('record user as commiter'))],
2174 _('hg commit [OPTION]... [FILE]...')),
2163 _('hg commit [OPTION]... [FILE]...')),
2175 "copy|cp": (copy,
2164 "copy|cp": (copy,
2176 [('I', 'include', [], _('include names matching the given patterns')),
2165 [('I', 'include', [], _('include names matching the given patterns')),
2177 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2166 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2178 ('A', 'after', None, _('record a copy that has already occurred')),
2167 ('A', 'after', None, _('record a copy that has already occurred')),
2179 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2168 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2180 _('hg copy [OPTION]... [SOURCE]... DEST')),
2169 _('hg copy [OPTION]... [SOURCE]... DEST')),
2181 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2170 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2182 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2171 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2183 "debugconfig": (debugconfig, [], _('debugconfig')),
2172 "debugconfig": (debugconfig, [], _('debugconfig')),
2184 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2173 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2185 "debugstate": (debugstate, [], _('debugstate')),
2174 "debugstate": (debugstate, [], _('debugstate')),
2186 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2175 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2187 "debugindex": (debugindex, [], _('debugindex FILE')),
2176 "debugindex": (debugindex, [], _('debugindex FILE')),
2188 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2177 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2189 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2178 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2190 "debugwalk":
2179 "debugwalk":
2191 (debugwalk,
2180 (debugwalk,
2192 [('I', 'include', [], _('include names matching the given patterns')),
2181 [('I', 'include', [], _('include names matching the given patterns')),
2193 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2182 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2194 _('debugwalk [OPTION]... [FILE]...')),
2183 _('debugwalk [OPTION]... [FILE]...')),
2195 "^diff":
2184 "^diff":
2196 (diff,
2185 (diff,
2197 [('r', 'rev', [], _('revision')),
2186 [('r', 'rev', [], _('revision')),
2198 ('a', 'text', None, _('treat all files as text')),
2187 ('a', 'text', None, _('treat all files as text')),
2199 ('I', 'include', [], _('include names matching the given patterns')),
2188 ('I', 'include', [], _('include names matching the given patterns')),
2200 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2189 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2201 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2190 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2202 "^export":
2191 "^export":
2203 (export,
2192 (export,
2204 [('o', 'output', "", _('print output to file with formatted name')),
2193 [('o', 'output', "", _('print output to file with formatted name')),
2205 ('a', 'text', None, _('treat all files as text'))],
2194 ('a', 'text', None, _('treat all files as text'))],
2206 "hg export [-a] [-o OUTFILE] REV..."),
2195 "hg export [-a] [-o OUTFILE] REV..."),
2207 "forget":
2196 "forget":
2208 (forget,
2197 (forget,
2209 [('I', 'include', [], _('include names matching the given patterns')),
2198 [('I', 'include', [], _('include names matching the given patterns')),
2210 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2199 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2211 "hg forget [OPTION]... FILE..."),
2200 "hg forget [OPTION]... FILE..."),
2212 "grep":
2201 "grep":
2213 (grep,
2202 (grep,
2214 [('0', 'print0', None, _('end fields with NUL')),
2203 [('0', 'print0', None, _('end fields with NUL')),
2215 ('I', 'include', [], _('include names matching the given patterns')),
2204 ('I', 'include', [], _('include names matching the given patterns')),
2216 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2205 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2217 ('', 'all', None, _('print all revisions that match')),
2206 ('', 'all', None, _('print all revisions that match')),
2218 ('i', 'ignore-case', None, _('ignore case when matching')),
2207 ('i', 'ignore-case', None, _('ignore case when matching')),
2219 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2208 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2220 ('n', 'line-number', None, _('print matching line numbers')),
2209 ('n', 'line-number', None, _('print matching line numbers')),
2221 ('r', 'rev', [], _('search in given revision range')),
2210 ('r', 'rev', [], _('search in given revision range')),
2222 ('u', 'user', None, _('print user who committed change'))],
2211 ('u', 'user', None, _('print user who committed change'))],
2223 "hg grep [OPTION]... PATTERN [FILE]..."),
2212 "hg grep [OPTION]... PATTERN [FILE]..."),
2224 "heads":
2213 "heads":
2225 (heads,
2214 (heads,
2226 [('b', 'branches', None, _('find branch info'))],
2215 [('b', 'branches', None, _('find branch info'))],
2227 _('hg heads [-b]')),
2216 _('hg heads [-b]')),
2228 "help": (help_, [], _('hg help [COMMAND]')),
2217 "help": (help_, [], _('hg help [COMMAND]')),
2229 "identify|id": (identify, [], _('hg identify')),
2218 "identify|id": (identify, [], _('hg identify')),
2230 "import|patch":
2219 "import|patch":
2231 (import_,
2220 (import_,
2232 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2221 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2233 _('meaning as the corresponding patch option')),
2222 _('meaning as the corresponding patch option')),
2234 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2223 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2235 ('b', 'base', "", _('base path'))],
2224 ('b', 'base', "", _('base path'))],
2236 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2225 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2237 "incoming|in": (incoming,
2226 "incoming|in": (incoming,
2238 [('M', 'no-merges', None, _("do not show merges")),
2227 [('M', 'no-merges', None, _("do not show merges")),
2239 ('p', 'patch', None, _('show patch')),
2228 ('p', 'patch', None, _('show patch')),
2240 ('n', 'newest-first', None, _('show newest record first'))],
2229 ('n', 'newest-first', None, _('show newest record first'))],
2241 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2230 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2242 "^init": (init, [], _('hg init [DEST]')),
2231 "^init": (init, [], _('hg init [DEST]')),
2243 "locate":
2232 "locate":
2244 (locate,
2233 (locate,
2245 [('r', 'rev', '', _('search the repository as it stood at rev')),
2234 [('r', 'rev', '', _('search the repository as it stood at rev')),
2246 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2235 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2247 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2236 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2248 ('I', 'include', [], _('include names matching the given patterns')),
2237 ('I', 'include', [], _('include names matching the given patterns')),
2249 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2238 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2250 _('hg locate [OPTION]... [PATTERN]...')),
2239 _('hg locate [OPTION]... [PATTERN]...')),
2251 "^log|history":
2240 "^log|history":
2252 (log,
2241 (log,
2253 [('I', 'include', [], _('include names matching the given patterns')),
2242 [('I', 'include', [], _('include names matching the given patterns')),
2254 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2243 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2255 ('b', 'branch', None, _('show branches')),
2244 ('b', 'branch', None, _('show branches')),
2256 ('k', 'keyword', [], _('search for a keyword')),
2245 ('k', 'keyword', [], _('search for a keyword')),
2257 ('r', 'rev', [], _('show the specified revision or range')),
2246 ('r', 'rev', [], _('show the specified revision or range')),
2258 ('M', 'no-merges', None, _("do not show merges")),
2247 ('M', 'no-merges', None, _("do not show merges")),
2259 ('m', 'only-merges', None, _("show only merges")),
2248 ('m', 'only-merges', None, _("show only merges")),
2260 ('p', 'patch', None, _('show patch'))],
2249 ('p', 'patch', None, _('show patch'))],
2261 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2250 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2262 "manifest": (manifest, [], _('hg manifest [REV]')),
2251 "manifest": (manifest, [], _('hg manifest [REV]')),
2263 "outgoing|out": (outgoing,
2252 "outgoing|out": (outgoing,
2264 [('M', 'no-merges', None, _("do not show merges")),
2253 [('M', 'no-merges', None, _("do not show merges")),
2265 ('p', 'patch', None, _('show patch')),
2254 ('p', 'patch', None, _('show patch')),
2266 ('n', 'newest-first', None, _('show newest record first'))],
2255 ('n', 'newest-first', None, _('show newest record first'))],
2267 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2256 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2268 "^parents": (parents, [], _('hg parents [REV]')),
2257 "^parents": (parents, [], _('hg parents [REV]')),
2269 "paths": (paths, [], _('hg paths [NAME]')),
2258 "paths": (paths, [], _('hg paths [NAME]')),
2270 "^pull":
2259 "^pull":
2271 (pull,
2260 (pull,
2272 [('u', 'update', None, _('update the working directory to tip after pull')),
2261 [('u', 'update', None, _('update the working directory to tip after pull')),
2273 ('e', 'ssh', "", _('specify ssh command to use')),
2262 ('e', 'ssh', "", _('specify ssh command to use')),
2274 ('r', 'rev', [], _('a specific revision you would like to pull')),
2263 ('r', 'rev', [], _('a specific revision you would like to pull')),
2275 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2264 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2276 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2265 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2277 "^push":
2266 "^push":
2278 (push,
2267 (push,
2279 [('f', 'force', None, _('force push')),
2268 [('f', 'force', None, _('force push')),
2280 ('e', 'ssh', "", _('specify ssh command to use')),
2269 ('e', 'ssh', "", _('specify ssh command to use')),
2281 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2270 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2282 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2271 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2283 "rawcommit":
2272 "rawcommit":
2284 (rawcommit,
2273 (rawcommit,
2285 [('p', 'parent', [], _('parent')),
2274 [('p', 'parent', [], _('parent')),
2286 ('d', 'date', "", _('date code')),
2275 ('d', 'date', "", _('date code')),
2287 ('u', 'user', "", _('user')),
2276 ('u', 'user', "", _('user')),
2288 ('F', 'files', "", _('file list')),
2277 ('F', 'files', "", _('file list')),
2289 ('m', 'message', "", _('commit message')),
2278 ('m', 'message', "", _('commit message')),
2290 ('l', 'logfile', "", _('commit message file'))],
2279 ('l', 'logfile', "", _('commit message file'))],
2291 _('hg rawcommit [OPTION]... [FILE]...')),
2280 _('hg rawcommit [OPTION]... [FILE]...')),
2292 "recover": (recover, [], _("hg recover")),
2281 "recover": (recover, [], _("hg recover")),
2293 "^remove|rm": (remove,
2282 "^remove|rm": (remove,
2294 [('I', 'include', [], _('include names matching the given patterns')),
2283 [('I', 'include', [], _('include names matching the given patterns')),
2295 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2284 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2296 _("hg remove [OPTION]... FILE...")),
2285 _("hg remove [OPTION]... FILE...")),
2297 "rename|mv": (rename,
2286 "rename|mv": (rename,
2298 [('I', 'include', [], _('include names matching the given patterns')),
2287 [('I', 'include', [], _('include names matching the given patterns')),
2299 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2288 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2300 ('A', 'after', None, _('record a rename that has already occurred')),
2289 ('A', 'after', None, _('record a rename that has already occurred')),
2301 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2290 ('f', 'force', None, _('forcibly copy over an existing managed file'))],
2302 _('hg rename [OPTION]... [SOURCE]... DEST')),
2291 _('hg rename [OPTION]... [SOURCE]... DEST')),
2303 "^revert":
2292 "^revert":
2304 (revert,
2293 (revert,
2305 [('I', 'include', [], _('include names matching the given patterns')),
2294 [('I', 'include', [], _('include names matching the given patterns')),
2306 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2295 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2307 ("r", "rev", "", _("revision to revert to"))],
2296 ("r", "rev", "", _("revision to revert to"))],
2308 _("hg revert [-n] [-r REV] [NAME]...")),
2297 _("hg revert [-n] [-r REV] [NAME]...")),
2309 "root": (root, [], _("hg root")),
2298 "root": (root, [], _("hg root")),
2310 "^serve":
2299 "^serve":
2311 (serve,
2300 (serve,
2312 [('A', 'accesslog', '', _('name of access log file to write to')),
2301 [('A', 'accesslog', '', _('name of access log file to write to')),
2313 ('E', 'errorlog', '', _('name of error log file to write to')),
2302 ('E', 'errorlog', '', _('name of error log file to write to')),
2314 ('p', 'port', 0, _('port to use (default: 8000)')),
2303 ('p', 'port', 0, _('port to use (default: 8000)')),
2315 ('a', 'address', '', _('address to use')),
2304 ('a', 'address', '', _('address to use')),
2316 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2305 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2317 ('', 'stdio', None, _('for remote clients')),
2306 ('', 'stdio', None, _('for remote clients')),
2318 ('t', 'templates', "", _('web templates to use')),
2307 ('t', 'templates', "", _('web templates to use')),
2319 ('', 'style', "", _('template style to use')),
2308 ('', 'style', "", _('template style to use')),
2320 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2309 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2321 _("hg serve [OPTION]...")),
2310 _("hg serve [OPTION]...")),
2322 "^status|st":
2311 "^status|st":
2323 (status,
2312 (status,
2324 [('m', 'modified', None, _('show only modified files')),
2313 [('m', 'modified', None, _('show only modified files')),
2325 ('a', 'added', None, _('show only added files')),
2314 ('a', 'added', None, _('show only added files')),
2326 ('r', 'removed', None, _('show only removed files')),
2315 ('r', 'removed', None, _('show only removed files')),
2327 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2316 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2328 ('n', 'no-status', None, _('hide status prefix')),
2317 ('n', 'no-status', None, _('hide status prefix')),
2329 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2318 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2330 ('I', 'include', [], _('include names matching the given patterns')),
2319 ('I', 'include', [], _('include names matching the given patterns')),
2331 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2320 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2332 _("hg status [OPTION]... [FILE]...")),
2321 _("hg status [OPTION]... [FILE]...")),
2333 "tag":
2322 "tag":
2334 (tag,
2323 (tag,
2335 [('l', 'local', None, _('make the tag local')),
2324 [('l', 'local', None, _('make the tag local')),
2336 ('m', 'message', "", _('message for tag commit log entry')),
2325 ('m', 'message', "", _('message for tag commit log entry')),
2337 ('d', 'date', "", _('record datecode as commit date')),
2326 ('d', 'date', "", _('record datecode as commit date')),
2338 ('u', 'user', "", _('record user as commiter')),
2327 ('u', 'user', "", _('record user as commiter')),
2339 ('r', 'rev', "", _('revision to tag'))],
2328 ('r', 'rev', "", _('revision to tag'))],
2340 _('hg tag [OPTION]... NAME [REV]')),
2329 _('hg tag [OPTION]... NAME [REV]')),
2341 "tags": (tags, [], _('hg tags')),
2330 "tags": (tags, [], _('hg tags')),
2342 "tip": (tip, [], _('hg tip')),
2331 "tip": (tip, [], _('hg tip')),
2343 "unbundle":
2332 "unbundle":
2344 (unbundle,
2333 (unbundle,
2345 [],
2334 [],
2346 _('hg unbundle FILE')),
2335 _('hg unbundle FILE')),
2347 "undo": (undo, [], _('hg undo')),
2336 "undo": (undo, [], _('hg undo')),
2348 "^update|up|checkout|co":
2337 "^update|up|checkout|co":
2349 (update,
2338 (update,
2350 [('b', 'branch', "", _('checkout the head of a specific branch')),
2339 [('b', 'branch', "", _('checkout the head of a specific branch')),
2351 ('m', 'merge', None, _('allow merging of branches')),
2340 ('m', 'merge', None, _('allow merging of branches')),
2352 ('C', 'clean', None, _('overwrite locally modified files'))],
2341 ('C', 'clean', None, _('overwrite locally modified files'))],
2353 _('hg update [-b TAG] [-m] [-C] [REV]')),
2342 _('hg update [-b TAG] [-m] [-C] [REV]')),
2354 "verify": (verify, [], _('hg verify')),
2343 "verify": (verify, [], _('hg verify')),
2355 "version": (show_version, [], _('hg version')),
2344 "version": (show_version, [], _('hg version')),
2356 }
2345 }
2357
2346
2358 globalopts = [
2347 globalopts = [
2359 ('R', 'repository', "", _("repository root directory")),
2348 ('R', 'repository', "", _("repository root directory")),
2360 ('', 'cwd', '', _("change working directory")),
2349 ('', 'cwd', '', _("change working directory")),
2361 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2350 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2362 ('q', 'quiet', None, _("suppress output")),
2351 ('q', 'quiet', None, _("suppress output")),
2363 ('v', 'verbose', None, _("enable additional output")),
2352 ('v', 'verbose', None, _("enable additional output")),
2364 ('', 'debug', None, _("enable debugging output")),
2353 ('', 'debug', None, _("enable debugging output")),
2365 ('', 'debugger', None, _("start debugger")),
2354 ('', 'debugger', None, _("start debugger")),
2366 ('', 'traceback', None, _("print traceback on exception")),
2355 ('', 'traceback', None, _("print traceback on exception")),
2367 ('', 'time', None, _("time how long the command takes")),
2356 ('', 'time', None, _("time how long the command takes")),
2368 ('', 'profile', None, _("print command execution profile")),
2357 ('', 'profile', None, _("print command execution profile")),
2369 ('', 'version', None, _("output version information and exit")),
2358 ('', 'version', None, _("output version information and exit")),
2370 ('h', 'help', None, _("display help and exit")),
2359 ('h', 'help', None, _("display help and exit")),
2371 ]
2360 ]
2372
2361
2373 norepo = ("clone init version help debugancestor debugconfig debugdata"
2362 norepo = ("clone init version help debugancestor debugconfig debugdata"
2374 " debugindex debugindexdot paths")
2363 " debugindex debugindexdot paths")
2375
2364
2376 def find(cmd):
2365 def find(cmd):
2377 choice = []
2366 choice = []
2378 for e in table.keys():
2367 for e in table.keys():
2379 aliases = e.lstrip("^").split("|")
2368 aliases = e.lstrip("^").split("|")
2380 if cmd in aliases:
2369 if cmd in aliases:
2381 return e, table[e]
2370 return e, table[e]
2382 for a in aliases:
2371 for a in aliases:
2383 if a.startswith(cmd):
2372 if a.startswith(cmd):
2384 choice.append(e)
2373 choice.append(e)
2385 if len(choice) == 1:
2374 if len(choice) == 1:
2386 e = choice[0]
2375 e = choice[0]
2387 return e, table[e]
2376 return e, table[e]
2388
2377
2389 raise UnknownCommand(cmd)
2378 raise UnknownCommand(cmd)
2390
2379
2391 class SignalInterrupt(Exception):
2380 class SignalInterrupt(Exception):
2392 """Exception raised on SIGTERM and SIGHUP."""
2381 """Exception raised on SIGTERM and SIGHUP."""
2393
2382
2394 def catchterm(*args):
2383 def catchterm(*args):
2395 raise SignalInterrupt
2384 raise SignalInterrupt
2396
2385
2397 def run():
2386 def run():
2398 sys.exit(dispatch(sys.argv[1:]))
2387 sys.exit(dispatch(sys.argv[1:]))
2399
2388
2400 class ParseError(Exception):
2389 class ParseError(Exception):
2401 """Exception raised on errors in parsing the command line."""
2390 """Exception raised on errors in parsing the command line."""
2402
2391
2403 def parse(ui, args):
2392 def parse(ui, args):
2404 options = {}
2393 options = {}
2405 cmdoptions = {}
2394 cmdoptions = {}
2406
2395
2407 try:
2396 try:
2408 args = fancyopts.fancyopts(args, globalopts, options)
2397 args = fancyopts.fancyopts(args, globalopts, options)
2409 except fancyopts.getopt.GetoptError, inst:
2398 except fancyopts.getopt.GetoptError, inst:
2410 raise ParseError(None, inst)
2399 raise ParseError(None, inst)
2411
2400
2412 if args:
2401 if args:
2413 cmd, args = args[0], args[1:]
2402 cmd, args = args[0], args[1:]
2414 defaults = ui.config("defaults", cmd)
2403 defaults = ui.config("defaults", cmd)
2415 if defaults:
2404 if defaults:
2416 # reparse with command defaults added
2405 # reparse with command defaults added
2417 args = [cmd] + defaults.split() + args
2406 args = [cmd] + defaults.split() + args
2418 try:
2407 try:
2419 args = fancyopts.fancyopts(args, globalopts, options)
2408 args = fancyopts.fancyopts(args, globalopts, options)
2420 except fancyopts.getopt.GetoptError, inst:
2409 except fancyopts.getopt.GetoptError, inst:
2421 raise ParseError(None, inst)
2410 raise ParseError(None, inst)
2422
2411
2423 cmd, args = args[0], args[1:]
2412 cmd, args = args[0], args[1:]
2424
2413
2425 i = find(cmd)[1]
2414 i = find(cmd)[1]
2426 c = list(i[1])
2415 c = list(i[1])
2427 else:
2416 else:
2428 cmd = None
2417 cmd = None
2429 c = []
2418 c = []
2430
2419
2431 # combine global options into local
2420 # combine global options into local
2432 for o in globalopts:
2421 for o in globalopts:
2433 c.append((o[0], o[1], options[o[1]], o[3]))
2422 c.append((o[0], o[1], options[o[1]], o[3]))
2434
2423
2435 try:
2424 try:
2436 args = fancyopts.fancyopts(args, c, cmdoptions)
2425 args = fancyopts.fancyopts(args, c, cmdoptions)
2437 except fancyopts.getopt.GetoptError, inst:
2426 except fancyopts.getopt.GetoptError, inst:
2438 raise ParseError(cmd, inst)
2427 raise ParseError(cmd, inst)
2439
2428
2440 # separate global options back out
2429 # separate global options back out
2441 for o in globalopts:
2430 for o in globalopts:
2442 n = o[1]
2431 n = o[1]
2443 options[n] = cmdoptions[n]
2432 options[n] = cmdoptions[n]
2444 del cmdoptions[n]
2433 del cmdoptions[n]
2445
2434
2446 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2435 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2447
2436
2448 def dispatch(args):
2437 def dispatch(args):
2449 signal.signal(signal.SIGTERM, catchterm)
2438 signal.signal(signal.SIGTERM, catchterm)
2450 try:
2439 try:
2451 signal.signal(signal.SIGHUP, catchterm)
2440 signal.signal(signal.SIGHUP, catchterm)
2452 except AttributeError:
2441 except AttributeError:
2453 pass
2442 pass
2454
2443
2455 try:
2444 try:
2456 u = ui.ui()
2445 u = ui.ui()
2457 except util.Abort, inst:
2446 except util.Abort, inst:
2458 sys.stderr.write(_("abort: %s\n") % inst)
2447 sys.stderr.write(_("abort: %s\n") % inst)
2459 sys.exit(1)
2448 sys.exit(1)
2460
2449
2461 external = []
2450 external = []
2462 for x in u.extensions():
2451 for x in u.extensions():
2463 def on_exception(Exception, inst):
2452 def on_exception(Exception, inst):
2464 u.warn(_("*** failed to import extension %s\n") % x[1])
2453 u.warn(_("*** failed to import extension %s\n") % x[1])
2465 u.warn("%s\n" % inst)
2454 u.warn("%s\n" % inst)
2466 if "--traceback" in sys.argv[1:]:
2455 if "--traceback" in sys.argv[1:]:
2467 traceback.print_exc()
2456 traceback.print_exc()
2468 if x[1]:
2457 if x[1]:
2469 try:
2458 try:
2470 mod = imp.load_source(x[0], x[1])
2459 mod = imp.load_source(x[0], x[1])
2471 except Exception, inst:
2460 except Exception, inst:
2472 on_exception(Exception, inst)
2461 on_exception(Exception, inst)
2473 continue
2462 continue
2474 else:
2463 else:
2475 def importh(name):
2464 def importh(name):
2476 mod = __import__(name)
2465 mod = __import__(name)
2477 components = name.split('.')
2466 components = name.split('.')
2478 for comp in components[1:]:
2467 for comp in components[1:]:
2479 mod = getattr(mod, comp)
2468 mod = getattr(mod, comp)
2480 return mod
2469 return mod
2481 try:
2470 try:
2482 mod = importh(x[0])
2471 mod = importh(x[0])
2483 except Exception, inst:
2472 except Exception, inst:
2484 on_exception(Exception, inst)
2473 on_exception(Exception, inst)
2485 continue
2474 continue
2486
2475
2487 external.append(mod)
2476 external.append(mod)
2488 for x in external:
2477 for x in external:
2489 cmdtable = getattr(x, 'cmdtable', {})
2478 cmdtable = getattr(x, 'cmdtable', {})
2490 for t in cmdtable:
2479 for t in cmdtable:
2491 if t in table:
2480 if t in table:
2492 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2481 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2493 table.update(cmdtable)
2482 table.update(cmdtable)
2494
2483
2495 try:
2484 try:
2496 cmd, func, args, options, cmdoptions = parse(u, args)
2485 cmd, func, args, options, cmdoptions = parse(u, args)
2497 except ParseError, inst:
2486 except ParseError, inst:
2498 if inst.args[0]:
2487 if inst.args[0]:
2499 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2488 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2500 help_(u, inst.args[0])
2489 help_(u, inst.args[0])
2501 else:
2490 else:
2502 u.warn(_("hg: %s\n") % inst.args[1])
2491 u.warn(_("hg: %s\n") % inst.args[1])
2503 help_(u, 'shortlist')
2492 help_(u, 'shortlist')
2504 sys.exit(-1)
2493 sys.exit(-1)
2505 except UnknownCommand, inst:
2494 except UnknownCommand, inst:
2506 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2495 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2507 help_(u, 'shortlist')
2496 help_(u, 'shortlist')
2508 sys.exit(1)
2497 sys.exit(1)
2509
2498
2510 if options["time"]:
2499 if options["time"]:
2511 def get_times():
2500 def get_times():
2512 t = os.times()
2501 t = os.times()
2513 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2502 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2514 t = (t[0], t[1], t[2], t[3], time.clock())
2503 t = (t[0], t[1], t[2], t[3], time.clock())
2515 return t
2504 return t
2516 s = get_times()
2505 s = get_times()
2517 def print_time():
2506 def print_time():
2518 t = get_times()
2507 t = get_times()
2519 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2508 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2520 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2509 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2521 atexit.register(print_time)
2510 atexit.register(print_time)
2522
2511
2523 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2512 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2524 not options["noninteractive"])
2513 not options["noninteractive"])
2525
2514
2526 # enter the debugger before command execution
2515 # enter the debugger before command execution
2527 if options['debugger']:
2516 if options['debugger']:
2528 pdb.set_trace()
2517 pdb.set_trace()
2529
2518
2530 try:
2519 try:
2531 try:
2520 try:
2532 if options['help']:
2521 if options['help']:
2533 help_(u, cmd, options['version'])
2522 help_(u, cmd, options['version'])
2534 sys.exit(0)
2523 sys.exit(0)
2535 elif options['version']:
2524 elif options['version']:
2536 show_version(u)
2525 show_version(u)
2537 sys.exit(0)
2526 sys.exit(0)
2538 elif not cmd:
2527 elif not cmd:
2539 help_(u, 'shortlist')
2528 help_(u, 'shortlist')
2540 sys.exit(0)
2529 sys.exit(0)
2541
2530
2542 if options['cwd']:
2531 if options['cwd']:
2543 try:
2532 try:
2544 os.chdir(options['cwd'])
2533 os.chdir(options['cwd'])
2545 except OSError, inst:
2534 except OSError, inst:
2546 raise util.Abort('%s: %s' %
2535 raise util.Abort('%s: %s' %
2547 (options['cwd'], inst.strerror))
2536 (options['cwd'], inst.strerror))
2548
2537
2549 if cmd not in norepo.split():
2538 if cmd not in norepo.split():
2550 path = options["repository"] or ""
2539 path = options["repository"] or ""
2551 repo = hg.repository(ui=u, path=path)
2540 repo = hg.repository(ui=u, path=path)
2552 for x in external:
2541 for x in external:
2553 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2542 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2554 d = lambda: func(u, repo, *args, **cmdoptions)
2543 d = lambda: func(u, repo, *args, **cmdoptions)
2555 else:
2544 else:
2556 d = lambda: func(u, *args, **cmdoptions)
2545 d = lambda: func(u, *args, **cmdoptions)
2557
2546
2558 if options['profile']:
2547 if options['profile']:
2559 import hotshot, hotshot.stats
2548 import hotshot, hotshot.stats
2560 prof = hotshot.Profile("hg.prof")
2549 prof = hotshot.Profile("hg.prof")
2561 r = prof.runcall(d)
2550 r = prof.runcall(d)
2562 prof.close()
2551 prof.close()
2563 stats = hotshot.stats.load("hg.prof")
2552 stats = hotshot.stats.load("hg.prof")
2564 stats.strip_dirs()
2553 stats.strip_dirs()
2565 stats.sort_stats('time', 'calls')
2554 stats.sort_stats('time', 'calls')
2566 stats.print_stats(40)
2555 stats.print_stats(40)
2567 return r
2556 return r
2568 else:
2557 else:
2569 return d()
2558 return d()
2570 except:
2559 except:
2571 # enter the debugger when we hit an exception
2560 # enter the debugger when we hit an exception
2572 if options['debugger']:
2561 if options['debugger']:
2573 pdb.post_mortem(sys.exc_info()[2])
2562 pdb.post_mortem(sys.exc_info()[2])
2574 if options['traceback']:
2563 if options['traceback']:
2575 traceback.print_exc()
2564 traceback.print_exc()
2576 raise
2565 raise
2577 except hg.RepoError, inst:
2566 except hg.RepoError, inst:
2578 u.warn(_("abort: "), inst, "!\n")
2567 u.warn(_("abort: "), inst, "!\n")
2579 except revlog.RevlogError, inst:
2568 except revlog.RevlogError, inst:
2580 u.warn(_("abort: "), inst, "!\n")
2569 u.warn(_("abort: "), inst, "!\n")
2581 except SignalInterrupt:
2570 except SignalInterrupt:
2582 u.warn(_("killed!\n"))
2571 u.warn(_("killed!\n"))
2583 except KeyboardInterrupt:
2572 except KeyboardInterrupt:
2584 try:
2573 try:
2585 u.warn(_("interrupted!\n"))
2574 u.warn(_("interrupted!\n"))
2586 except IOError, inst:
2575 except IOError, inst:
2587 if inst.errno == errno.EPIPE:
2576 if inst.errno == errno.EPIPE:
2588 if u.debugflag:
2577 if u.debugflag:
2589 u.warn(_("\nbroken pipe\n"))
2578 u.warn(_("\nbroken pipe\n"))
2590 else:
2579 else:
2591 raise
2580 raise
2592 except IOError, inst:
2581 except IOError, inst:
2593 if hasattr(inst, "code"):
2582 if hasattr(inst, "code"):
2594 u.warn(_("abort: %s\n") % inst)
2583 u.warn(_("abort: %s\n") % inst)
2595 elif hasattr(inst, "reason"):
2584 elif hasattr(inst, "reason"):
2596 u.warn(_("abort: error: %s\n") % inst.reason[1])
2585 u.warn(_("abort: error: %s\n") % inst.reason[1])
2597 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2586 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2598 if u.debugflag:
2587 if u.debugflag:
2599 u.warn(_("broken pipe\n"))
2588 u.warn(_("broken pipe\n"))
2600 elif getattr(inst, "strerror", None):
2589 elif getattr(inst, "strerror", None):
2601 if getattr(inst, "filename", None):
2590 if getattr(inst, "filename", None):
2602 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2591 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2603 else:
2592 else:
2604 u.warn(_("abort: %s\n") % inst.strerror)
2593 u.warn(_("abort: %s\n") % inst.strerror)
2605 else:
2594 else:
2606 raise
2595 raise
2607 except OSError, inst:
2596 except OSError, inst:
2608 if hasattr(inst, "filename"):
2597 if hasattr(inst, "filename"):
2609 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2598 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2610 else:
2599 else:
2611 u.warn(_("abort: %s\n") % inst.strerror)
2600 u.warn(_("abort: %s\n") % inst.strerror)
2612 except util.Abort, inst:
2601 except util.Abort, inst:
2613 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2602 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2614 sys.exit(1)
2603 sys.exit(1)
2615 except TypeError, inst:
2604 except TypeError, inst:
2616 # was this an argument error?
2605 # was this an argument error?
2617 tb = traceback.extract_tb(sys.exc_info()[2])
2606 tb = traceback.extract_tb(sys.exc_info()[2])
2618 if len(tb) > 2: # no
2607 if len(tb) > 2: # no
2619 raise
2608 raise
2620 u.debug(inst, "\n")
2609 u.debug(inst, "\n")
2621 u.warn(_("%s: invalid arguments\n") % cmd)
2610 u.warn(_("%s: invalid arguments\n") % cmd)
2622 help_(u, cmd)
2611 help_(u, cmd)
2623 except UnknownCommand, inst:
2612 except UnknownCommand, inst:
2624 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2613 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2625 help_(u, 'shortlist')
2614 help_(u, 'shortlist')
2626 except SystemExit:
2615 except SystemExit:
2627 # don't catch this in the catch-all below
2616 # don't catch this in the catch-all below
2628 raise
2617 raise
2629 except:
2618 except:
2630 u.warn(_("** unknown exception encountered, details follow\n"))
2619 u.warn(_("** unknown exception encountered, details follow\n"))
2631 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2620 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2632 raise
2621 raise
2633
2622
2634 sys.exit(-1)
2623 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now