##// END OF EJS Templates
Move revision parsing into cmdutil.
Brendan Cully -
r3090:eeaf9bcd default
parent child Browse files
Show More
@@ -1,179 +1,179 b''
1 # churn.py - create a graph showing who changed the most lines
1 # churn.py - create a graph showing who changed the most lines
2 #
2 #
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
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 #
8 #
9 # Aliases map file format is simple one alias per line in the following
9 # Aliases map file format is simple one alias per line in the following
10 # format:
10 # format:
11 #
11 #
12 # <alias email> <actual email>
12 # <alias email> <actual email>
13
13
14 from mercurial.demandload import *
14 from mercurial.demandload import *
15 from mercurial.i18n import gettext as _
15 from mercurial.i18n import gettext as _
16 demandload(globals(), 'time sys signal os')
16 demandload(globals(), 'time sys signal os')
17 demandload(globals(), 'mercurial:hg,mdiff,fancyopts,commands,ui,util,templater,node')
17 demandload(globals(), 'mercurial:hg,mdiff,fancyopts,cmdutil,ui,util,templater,node')
18
18
19 def __gather(ui, repo, node1, node2):
19 def __gather(ui, repo, node1, node2):
20 def dirtywork(f, mmap1, mmap2):
20 def dirtywork(f, mmap1, mmap2):
21 lines = 0
21 lines = 0
22
22
23 to = mmap1 and repo.file(f).read(mmap1[f]) or None
23 to = mmap1 and repo.file(f).read(mmap1[f]) or None
24 tn = mmap2 and repo.file(f).read(mmap2[f]) or None
24 tn = mmap2 and repo.file(f).read(mmap2[f]) or None
25
25
26 diff = mdiff.unidiff(to, "", tn, "", f).split("\n")
26 diff = mdiff.unidiff(to, "", tn, "", f).split("\n")
27
27
28 for line in diff:
28 for line in diff:
29 if not line:
29 if not line:
30 continue # skip EOF
30 continue # skip EOF
31 if line.startswith(" "):
31 if line.startswith(" "):
32 continue # context line
32 continue # context line
33 if line.startswith("--- ") or line.startswith("+++ "):
33 if line.startswith("--- ") or line.startswith("+++ "):
34 continue # begining of diff
34 continue # begining of diff
35 if line.startswith("@@ "):
35 if line.startswith("@@ "):
36 continue # info line
36 continue # info line
37
37
38 # changed lines
38 # changed lines
39 lines += 1
39 lines += 1
40
40
41 return lines
41 return lines
42
42
43 ##
43 ##
44
44
45 lines = 0
45 lines = 0
46
46
47 changes = repo.status(node1, node2, None, util.always)[:5]
47 changes = repo.status(node1, node2, None, util.always)[:5]
48
48
49 modified, added, removed, deleted, unknown = changes
49 modified, added, removed, deleted, unknown = changes
50
50
51 who = repo.changelog.read(node2)[1]
51 who = repo.changelog.read(node2)[1]
52 who = templater.email(who) # get the email of the person
52 who = templater.email(who) # get the email of the person
53
53
54 mmap1 = repo.manifest.read(repo.changelog.read(node1)[0])
54 mmap1 = repo.manifest.read(repo.changelog.read(node1)[0])
55 mmap2 = repo.manifest.read(repo.changelog.read(node2)[0])
55 mmap2 = repo.manifest.read(repo.changelog.read(node2)[0])
56 for f in modified:
56 for f in modified:
57 lines += dirtywork(f, mmap1, mmap2)
57 lines += dirtywork(f, mmap1, mmap2)
58
58
59 for f in added:
59 for f in added:
60 lines += dirtywork(f, None, mmap2)
60 lines += dirtywork(f, None, mmap2)
61
61
62 for f in removed:
62 for f in removed:
63 lines += dirtywork(f, mmap1, None)
63 lines += dirtywork(f, mmap1, None)
64
64
65 for f in deleted:
65 for f in deleted:
66 lines += dirtywork(f, mmap1, mmap2)
66 lines += dirtywork(f, mmap1, mmap2)
67
67
68 for f in unknown:
68 for f in unknown:
69 lines += dirtywork(f, mmap1, mmap2)
69 lines += dirtywork(f, mmap1, mmap2)
70
70
71 return (who, lines)
71 return (who, lines)
72
72
73 def gather_stats(ui, repo, amap, revs=None, progress=False):
73 def gather_stats(ui, repo, amap, revs=None, progress=False):
74 stats = {}
74 stats = {}
75
75
76 cl = repo.changelog
76 cl = repo.changelog
77
77
78 if not revs:
78 if not revs:
79 revs = range(0, cl.count())
79 revs = range(0, cl.count())
80
80
81 nr_revs = len(revs)
81 nr_revs = len(revs)
82 cur_rev = 0
82 cur_rev = 0
83
83
84 for rev in revs:
84 for rev in revs:
85 cur_rev += 1 # next revision
85 cur_rev += 1 # next revision
86
86
87 node2 = cl.node(rev)
87 node2 = cl.node(rev)
88 node1 = cl.parents(node2)[0]
88 node1 = cl.parents(node2)[0]
89
89
90 if cl.parents(node2)[1] != node.nullid:
90 if cl.parents(node2)[1] != node.nullid:
91 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
91 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
92 continue
92 continue
93
93
94 who, lines = __gather(ui, repo, node1, node2)
94 who, lines = __gather(ui, repo, node1, node2)
95
95
96 # remap the owner if possible
96 # remap the owner if possible
97 if amap.has_key(who):
97 if amap.has_key(who):
98 ui.note("using '%s' alias for '%s'\n" % (amap[who], who))
98 ui.note("using '%s' alias for '%s'\n" % (amap[who], who))
99 who = amap[who]
99 who = amap[who]
100
100
101 if not stats.has_key(who):
101 if not stats.has_key(who):
102 stats[who] = 0
102 stats[who] = 0
103 stats[who] += lines
103 stats[who] += lines
104
104
105 ui.note("rev %d: %d lines by %s\n" % (rev, lines, who))
105 ui.note("rev %d: %d lines by %s\n" % (rev, lines, who))
106
106
107 if progress:
107 if progress:
108 if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs):
108 if int(100.0*(cur_rev - 1)/nr_revs) < int(100.0*cur_rev/nr_revs):
109 ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),))
109 ui.write("%d%%.." % (int(100.0*cur_rev/nr_revs),))
110 sys.stdout.flush()
110 sys.stdout.flush()
111
111
112 if progress:
112 if progress:
113 ui.write("done\n")
113 ui.write("done\n")
114 sys.stdout.flush()
114 sys.stdout.flush()
115
115
116 return stats
116 return stats
117
117
118 def churn(ui, repo, **opts):
118 def churn(ui, repo, **opts):
119 "Graphs the number of lines changed"
119 "Graphs the number of lines changed"
120
120
121 def pad(s, l):
121 def pad(s, l):
122 if len(s) < l:
122 if len(s) < l:
123 return s + " " * (l-len(s))
123 return s + " " * (l-len(s))
124 return s[0:l]
124 return s[0:l]
125
125
126 def graph(n, maximum, width, char):
126 def graph(n, maximum, width, char):
127 n = int(n * width / float(maximum))
127 n = int(n * width / float(maximum))
128
128
129 return char * (n)
129 return char * (n)
130
130
131 def get_aliases(f):
131 def get_aliases(f):
132 aliases = {}
132 aliases = {}
133
133
134 for l in f.readlines():
134 for l in f.readlines():
135 l = l.strip()
135 l = l.strip()
136 alias, actual = l.split(" ")
136 alias, actual = l.split(" ")
137 aliases[alias] = actual
137 aliases[alias] = actual
138
138
139 return aliases
139 return aliases
140
140
141 amap = {}
141 amap = {}
142 aliases = opts.get('aliases')
142 aliases = opts.get('aliases')
143 if aliases:
143 if aliases:
144 try:
144 try:
145 f = open(aliases,"r")
145 f = open(aliases,"r")
146 except OSError, e:
146 except OSError, e:
147 print "Error: " + e
147 print "Error: " + e
148 return
148 return
149
149
150 amap = get_aliases(f)
150 amap = get_aliases(f)
151 f.close()
151 f.close()
152
152
153 revs = [int(r) for r in commands.revrange(ui, repo, opts['rev'])]
153 revs = [int(r) for r in cmdutil.revrange(ui, repo, opts['rev'])]
154 revs.sort()
154 revs.sort()
155 stats = gather_stats(ui, repo, amap, revs, opts.get('progress'))
155 stats = gather_stats(ui, repo, amap, revs, opts.get('progress'))
156
156
157 # make a list of tuples (name, lines) and sort it in descending order
157 # make a list of tuples (name, lines) and sort it in descending order
158 ordered = stats.items()
158 ordered = stats.items()
159 ordered.sort(lambda x, y: cmp(y[1], x[1]))
159 ordered.sort(lambda x, y: cmp(y[1], x[1]))
160
160
161 maximum = ordered[0][1]
161 maximum = ordered[0][1]
162
162
163 ui.note("Assuming 80 character terminal\n")
163 ui.note("Assuming 80 character terminal\n")
164 width = 80 - 1
164 width = 80 - 1
165
165
166 for i in ordered:
166 for i in ordered:
167 person = i[0]
167 person = i[0]
168 lines = i[1]
168 lines = i[1]
169 print "%s %6d %s" % (pad(person, 20), lines,
169 print "%s %6d %s" % (pad(person, 20), lines,
170 graph(lines, maximum, width - 20 - 1 - 6 - 2 - 2, '*'))
170 graph(lines, maximum, width - 20 - 1 - 6 - 2 - 2, '*'))
171
171
172 cmdtable = {
172 cmdtable = {
173 "churn":
173 "churn":
174 (churn,
174 (churn,
175 [('r', 'rev', [], _('limit statistics to the specified revisions')),
175 [('r', 'rev', [], _('limit statistics to the specified revisions')),
176 ('', 'aliases', '', _('file with email aliases')),
176 ('', 'aliases', '', _('file with email aliases')),
177 ('', 'progress', None, _('show progress'))],
177 ('', 'progress', None, _('show progress'))],
178 'hg churn [-r revision range] [-a file] [--progress]'),
178 'hg churn [-r revision range] [-a file] [--progress]'),
179 }
179 }
@@ -1,174 +1,174 b''
1 # extdiff.py - external diff program support for mercurial
1 # extdiff.py - external diff program support for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.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 # The `extdiff' Mercurial extension allows you to use external programs
8 # The `extdiff' Mercurial extension allows you to use external programs
9 # to compare revisions, or revision with working dir. The external diff
9 # to compare revisions, or revision with working dir. The external diff
10 # programs are called with a configurable set of options and two
10 # programs are called with a configurable set of options and two
11 # non-option arguments: paths to directories containing snapshots of
11 # non-option arguments: paths to directories containing snapshots of
12 # files to compare.
12 # files to compare.
13 #
13 #
14 # To enable this extension:
14 # To enable this extension:
15 #
15 #
16 # [extensions]
16 # [extensions]
17 # hgext.extdiff =
17 # hgext.extdiff =
18 #
18 #
19 # The `extdiff' extension also allows to configure new diff commands, so
19 # The `extdiff' extension also allows to configure new diff commands, so
20 # you do not need to type "hg extdiff -p kdiff3" always.
20 # you do not need to type "hg extdiff -p kdiff3" always.
21 #
21 #
22 # [extdiff]
22 # [extdiff]
23 # # add new command that runs GNU diff(1) in 'context diff' mode
23 # # add new command that runs GNU diff(1) in 'context diff' mode
24 # cmd.cdiff = gdiff
24 # cmd.cdiff = gdiff
25 # opts.cdiff = -Nprc5
25 # opts.cdiff = -Nprc5
26 # # add new command called vdiff, runs kdiff3
26 # # add new command called vdiff, runs kdiff3
27 # cmd.vdiff = kdiff3
27 # cmd.vdiff = kdiff3
28 # # add new command called meld, runs meld (no need to name twice)
28 # # add new command called meld, runs meld (no need to name twice)
29 # cmd.meld =
29 # cmd.meld =
30 # # add new command called vimdiff, runs gvimdiff with DirDiff plugin
30 # # add new command called vimdiff, runs gvimdiff with DirDiff plugin
31 # #(see http://www.vim.org/scripts/script.php?script_id=102)
31 # #(see http://www.vim.org/scripts/script.php?script_id=102)
32 # cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
32 # cmd.vimdiff = LC_ALL=C gvim -f '+bdel 1 2' '+ execute "DirDiff ".argv(0)." ".argv(1)'
33 #
33 #
34 # Each custom diff commands can have two parts: a `cmd' and an `opts'
34 # Each custom diff commands can have two parts: a `cmd' and an `opts'
35 # part. The cmd.xxx option defines the name of an executable program
35 # part. The cmd.xxx option defines the name of an executable program
36 # that will be run, and opts.xxx defines a set of command-line options
36 # that will be run, and opts.xxx defines a set of command-line options
37 # which will be inserted to the command between the program name and
37 # which will be inserted to the command between the program name and
38 # the files/directories to diff (i.e. the cdiff example above).
38 # the files/directories to diff (i.e. the cdiff example above).
39 #
39 #
40 # You can use -I/-X and list of file or directory names like normal
40 # You can use -I/-X and list of file or directory names like normal
41 # "hg diff" command. The `extdiff' extension makes snapshots of only
41 # "hg diff" command. The `extdiff' extension makes snapshots of only
42 # needed files, so running the external diff program will actually be
42 # needed files, so running the external diff program will actually be
43 # pretty fast (at least faster than having to compare the entire tree).
43 # pretty fast (at least faster than having to compare the entire tree).
44
44
45 from mercurial.demandload import demandload
45 from mercurial.demandload import demandload
46 from mercurial.i18n import gettext as _
46 from mercurial.i18n import gettext as _
47 from mercurial.node import *
47 from mercurial.node import *
48 demandload(globals(), 'mercurial:commands,cmdutil,util os shutil tempfile')
48 demandload(globals(), 'mercurial:cmdutil,util os shutil tempfile')
49
49
50 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
50 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
51 def snapshot_node(files, node):
51 def snapshot_node(files, node):
52 '''snapshot files as of some revision'''
52 '''snapshot files as of some revision'''
53 changes = repo.changelog.read(node)
53 changes = repo.changelog.read(node)
54 mf = repo.manifest.read(changes[0])
54 mf = repo.manifest.read(changes[0])
55 dirname = '%s.%s' % (os.path.basename(repo.root), short(node))
55 dirname = '%s.%s' % (os.path.basename(repo.root), short(node))
56 base = os.path.join(tmproot, dirname)
56 base = os.path.join(tmproot, dirname)
57 os.mkdir(base)
57 os.mkdir(base)
58 if not ui.quiet:
58 if not ui.quiet:
59 ui.write_err(_('making snapshot of %d files from rev %s\n') %
59 ui.write_err(_('making snapshot of %d files from rev %s\n') %
60 (len(files), short(node)))
60 (len(files), short(node)))
61 for fn in files:
61 for fn in files:
62 wfn = util.pconvert(fn)
62 wfn = util.pconvert(fn)
63 ui.note(' %s\n' % wfn)
63 ui.note(' %s\n' % wfn)
64 dest = os.path.join(base, wfn)
64 dest = os.path.join(base, wfn)
65 destdir = os.path.dirname(dest)
65 destdir = os.path.dirname(dest)
66 if not os.path.isdir(destdir):
66 if not os.path.isdir(destdir):
67 os.makedirs(destdir)
67 os.makedirs(destdir)
68 repo.wwrite(wfn, repo.file(fn).read(mf[fn]), open(dest, 'w'))
68 repo.wwrite(wfn, repo.file(fn).read(mf[fn]), open(dest, 'w'))
69 return dirname
69 return dirname
70
70
71 def snapshot_wdir(files):
71 def snapshot_wdir(files):
72 '''snapshot files from working directory.
72 '''snapshot files from working directory.
73 if not using snapshot, -I/-X does not work and recursive diff
73 if not using snapshot, -I/-X does not work and recursive diff
74 in tools like kdiff3 and meld displays too many files.'''
74 in tools like kdiff3 and meld displays too many files.'''
75 dirname = os.path.basename(repo.root)
75 dirname = os.path.basename(repo.root)
76 base = os.path.join(tmproot, dirname)
76 base = os.path.join(tmproot, dirname)
77 os.mkdir(base)
77 os.mkdir(base)
78 if not ui.quiet:
78 if not ui.quiet:
79 ui.write_err(_('making snapshot of %d files from working dir\n') %
79 ui.write_err(_('making snapshot of %d files from working dir\n') %
80 (len(files)))
80 (len(files)))
81 for fn in files:
81 for fn in files:
82 wfn = util.pconvert(fn)
82 wfn = util.pconvert(fn)
83 ui.note(' %s\n' % wfn)
83 ui.note(' %s\n' % wfn)
84 dest = os.path.join(base, wfn)
84 dest = os.path.join(base, wfn)
85 destdir = os.path.dirname(dest)
85 destdir = os.path.dirname(dest)
86 if not os.path.isdir(destdir):
86 if not os.path.isdir(destdir):
87 os.makedirs(destdir)
87 os.makedirs(destdir)
88 fp = open(dest, 'w')
88 fp = open(dest, 'w')
89 for chunk in util.filechunkiter(repo.wopener(wfn)):
89 for chunk in util.filechunkiter(repo.wopener(wfn)):
90 fp.write(chunk)
90 fp.write(chunk)
91 return dirname
91 return dirname
92
92
93 node1, node2 = commands.revpair(ui, repo, opts['rev'])
93 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
94 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
94 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
95 modified, added, removed, deleted, unknown = repo.status(
95 modified, added, removed, deleted, unknown = repo.status(
96 node1, node2, files, match=matchfn)[:5]
96 node1, node2, files, match=matchfn)[:5]
97 if not (modified or added or removed):
97 if not (modified or added or removed):
98 return 0
98 return 0
99
99
100 tmproot = tempfile.mkdtemp(prefix='extdiff.')
100 tmproot = tempfile.mkdtemp(prefix='extdiff.')
101 try:
101 try:
102 dir1 = snapshot_node(modified + removed, node1)
102 dir1 = snapshot_node(modified + removed, node1)
103 if node2:
103 if node2:
104 dir2 = snapshot_node(modified + added, node2)
104 dir2 = snapshot_node(modified + added, node2)
105 else:
105 else:
106 dir2 = snapshot_wdir(modified + added)
106 dir2 = snapshot_wdir(modified + added)
107 cmdline = ('%s %s %s %s' %
107 cmdline = ('%s %s %s %s' %
108 (util.shellquote(diffcmd), ' '.join(diffopts),
108 (util.shellquote(diffcmd), ' '.join(diffopts),
109 util.shellquote(dir1), util.shellquote(dir2)))
109 util.shellquote(dir1), util.shellquote(dir2)))
110 ui.debug('running %r in %s\n' % (cmdline, tmproot))
110 ui.debug('running %r in %s\n' % (cmdline, tmproot))
111 util.system(cmdline, cwd=tmproot)
111 util.system(cmdline, cwd=tmproot)
112 return 1
112 return 1
113 finally:
113 finally:
114 ui.note(_('cleaning up temp directory\n'))
114 ui.note(_('cleaning up temp directory\n'))
115 shutil.rmtree(tmproot)
115 shutil.rmtree(tmproot)
116
116
117 def extdiff(ui, repo, *pats, **opts):
117 def extdiff(ui, repo, *pats, **opts):
118 '''use external program to diff repository (or selected files)
118 '''use external program to diff repository (or selected files)
119
119
120 Show differences between revisions for the specified files, using
120 Show differences between revisions for the specified files, using
121 an external program. The default program used is diff, with
121 an external program. The default program used is diff, with
122 default options "-Npru".
122 default options "-Npru".
123
123
124 To select a different program, use the -p option. The program
124 To select a different program, use the -p option. The program
125 will be passed the names of two directories to compare. To pass
125 will be passed the names of two directories to compare. To pass
126 additional options to the program, use the -o option. These will
126 additional options to the program, use the -o option. These will
127 be passed before the names of the directories to compare.
127 be passed before the names of the directories to compare.
128
128
129 When two revision arguments are given, then changes are
129 When two revision arguments are given, then changes are
130 shown between those revisions. If only one revision is
130 shown between those revisions. If only one revision is
131 specified then that revision is compared to the working
131 specified then that revision is compared to the working
132 directory, and, when no revisions are specified, the
132 directory, and, when no revisions are specified, the
133 working directory files are compared to its parent.'''
133 working directory files are compared to its parent.'''
134 return dodiff(ui, repo, opts['program'] or 'diff',
134 return dodiff(ui, repo, opts['program'] or 'diff',
135 opts['option'] or ['-Npru'], pats, opts)
135 opts['option'] or ['-Npru'], pats, opts)
136
136
137 cmdtable = {
137 cmdtable = {
138 "extdiff":
138 "extdiff":
139 (extdiff,
139 (extdiff,
140 [('p', 'program', '', _('comparison program to run')),
140 [('p', 'program', '', _('comparison program to run')),
141 ('o', 'option', [], _('pass option to comparison program')),
141 ('o', 'option', [], _('pass option to comparison program')),
142 ('r', 'rev', [], _('revision')),
142 ('r', 'rev', [], _('revision')),
143 ('I', 'include', [], _('include names matching the given patterns')),
143 ('I', 'include', [], _('include names matching the given patterns')),
144 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
144 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
145 _('hg extdiff [OPT]... [FILE]...')),
145 _('hg extdiff [OPT]... [FILE]...')),
146 }
146 }
147
147
148 def uisetup(ui):
148 def uisetup(ui):
149 for cmd, path in ui.configitems('extdiff'):
149 for cmd, path in ui.configitems('extdiff'):
150 if not cmd.startswith('cmd.'): continue
150 if not cmd.startswith('cmd.'): continue
151 cmd = cmd[4:]
151 cmd = cmd[4:]
152 if not path: path = cmd
152 if not path: path = cmd
153 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
153 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
154 diffopts = diffopts and [diffopts] or []
154 diffopts = diffopts and [diffopts] or []
155 def save(cmd, path, diffopts):
155 def save(cmd, path, diffopts):
156 '''use closure to save diff command to use'''
156 '''use closure to save diff command to use'''
157 def mydiff(ui, repo, *pats, **opts):
157 def mydiff(ui, repo, *pats, **opts):
158 return dodiff(ui, repo, path, diffopts, pats, opts)
158 return dodiff(ui, repo, path, diffopts, pats, opts)
159 mydiff.__doc__ = '''use %(path)r to diff repository (or selected files)
159 mydiff.__doc__ = '''use %(path)r to diff repository (or selected files)
160
160
161 Show differences between revisions for the specified
161 Show differences between revisions for the specified
162 files, using the %(path)r program.
162 files, using the %(path)r program.
163
163
164 When two revision arguments are given, then changes are
164 When two revision arguments are given, then changes are
165 shown between those revisions. If only one revision is
165 shown between those revisions. If only one revision is
166 specified then that revision is compared to the working
166 specified then that revision is compared to the working
167 directory, and, when no revisions are specified, the
167 directory, and, when no revisions are specified, the
168 working directory files are compared to its parent.''' % {
168 working directory files are compared to its parent.''' % {
169 'path': path,
169 'path': path,
170 }
170 }
171 return mydiff
171 return mydiff
172 cmdtable[cmd] = (save(cmd, path, diffopts),
172 cmdtable[cmd] = (save(cmd, path, diffopts),
173 cmdtable['extdiff'][1][1:],
173 cmdtable['extdiff'][1][1:],
174 _('hg %s [OPT]... [FILE]...') % cmd)
174 _('hg %s [OPT]... [FILE]...') % cmd)
@@ -1,145 +1,215 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from 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(), 'mdiff util')
11 demandload(globals(), 'mdiff util')
12 demandload(globals(), 'os sys')
12 demandload(globals(), 'os sys')
13
13
14 revrangesep = ':'
15
16 def revfix(repo, val, defval):
17 '''turn user-level id of changeset into rev number.
18 user-level id can be tag, changeset, rev number, or negative rev
19 number relative to number of revs (-1 is tip, etc).'''
20 if not val:
21 return defval
22 try:
23 num = int(val)
24 if str(num) != val:
25 raise ValueError
26 if num < 0:
27 num += repo.changelog.count()
28 if num < 0:
29 num = 0
30 elif num >= repo.changelog.count():
31 raise ValueError
32 except ValueError:
33 try:
34 num = repo.changelog.rev(repo.lookup(val))
35 except KeyError:
36 raise util.Abort(_('invalid revision identifier %s') % val)
37 return num
38
39 def revpair(ui, repo, revs):
40 '''return pair of nodes, given list of revisions. second item can
41 be None, meaning use working dir.'''
42 if not revs:
43 return repo.dirstate.parents()[0], None
44 end = None
45 if len(revs) == 1:
46 start = revs[0]
47 if revrangesep in start:
48 start, end = start.split(revrangesep, 1)
49 start = revfix(repo, start, 0)
50 end = revfix(repo, end, repo.changelog.count() - 1)
51 else:
52 start = revfix(repo, start, None)
53 elif len(revs) == 2:
54 if revrangesep in revs[0] or revrangesep in revs[1]:
55 raise util.Abort(_('too many revisions specified'))
56 start = revfix(repo, revs[0], None)
57 end = revfix(repo, revs[1], None)
58 else:
59 raise util.Abort(_('too many revisions specified'))
60 if end is not None: end = repo.lookup(str(end))
61 return repo.lookup(str(start)), end
62
63 def revrange(ui, repo, revs):
64 """Yield revision as strings from a list of revision specifications."""
65 seen = {}
66 for spec in revs:
67 if revrangesep in spec:
68 start, end = spec.split(revrangesep, 1)
69 start = revfix(repo, start, 0)
70 end = revfix(repo, end, repo.changelog.count() - 1)
71 step = start > end and -1 or 1
72 for rev in xrange(start, end+step, step):
73 if rev in seen:
74 continue
75 seen[rev] = 1
76 yield str(rev)
77 else:
78 rev = revfix(repo, spec, None)
79 if rev in seen:
80 continue
81 seen[rev] = 1
82 yield str(rev)
83
14 def make_filename(repo, pat, node,
84 def make_filename(repo, pat, node,
15 total=None, seqno=None, revwidth=None, pathname=None):
85 total=None, seqno=None, revwidth=None, pathname=None):
16 node_expander = {
86 node_expander = {
17 'H': lambda: hex(node),
87 'H': lambda: hex(node),
18 'R': lambda: str(repo.changelog.rev(node)),
88 'R': lambda: str(repo.changelog.rev(node)),
19 'h': lambda: short(node),
89 'h': lambda: short(node),
20 }
90 }
21 expander = {
91 expander = {
22 '%': lambda: '%',
92 '%': lambda: '%',
23 'b': lambda: os.path.basename(repo.root),
93 'b': lambda: os.path.basename(repo.root),
24 }
94 }
25
95
26 try:
96 try:
27 if node:
97 if node:
28 expander.update(node_expander)
98 expander.update(node_expander)
29 if node and revwidth is not None:
99 if node and revwidth is not None:
30 expander['r'] = (lambda:
100 expander['r'] = (lambda:
31 str(repo.changelog.rev(node)).zfill(revwidth))
101 str(repo.changelog.rev(node)).zfill(revwidth))
32 if total is not None:
102 if total is not None:
33 expander['N'] = lambda: str(total)
103 expander['N'] = lambda: str(total)
34 if seqno is not None:
104 if seqno is not None:
35 expander['n'] = lambda: str(seqno)
105 expander['n'] = lambda: str(seqno)
36 if total is not None and seqno is not None:
106 if total is not None and seqno is not None:
37 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
107 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
38 if pathname is not None:
108 if pathname is not None:
39 expander['s'] = lambda: os.path.basename(pathname)
109 expander['s'] = lambda: os.path.basename(pathname)
40 expander['d'] = lambda: os.path.dirname(pathname) or '.'
110 expander['d'] = lambda: os.path.dirname(pathname) or '.'
41 expander['p'] = lambda: pathname
111 expander['p'] = lambda: pathname
42
112
43 newname = []
113 newname = []
44 patlen = len(pat)
114 patlen = len(pat)
45 i = 0
115 i = 0
46 while i < patlen:
116 while i < patlen:
47 c = pat[i]
117 c = pat[i]
48 if c == '%':
118 if c == '%':
49 i += 1
119 i += 1
50 c = pat[i]
120 c = pat[i]
51 c = expander[c]()
121 c = expander[c]()
52 newname.append(c)
122 newname.append(c)
53 i += 1
123 i += 1
54 return ''.join(newname)
124 return ''.join(newname)
55 except KeyError, inst:
125 except KeyError, inst:
56 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
126 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
57 inst.args[0])
127 inst.args[0])
58
128
59 def make_file(repo, pat, node=None,
129 def make_file(repo, pat, node=None,
60 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
130 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
61 if not pat or pat == '-':
131 if not pat or pat == '-':
62 return 'w' in mode and sys.stdout or sys.stdin
132 return 'w' in mode and sys.stdout or sys.stdin
63 if hasattr(pat, 'write') and 'w' in mode:
133 if hasattr(pat, 'write') and 'w' in mode:
64 return pat
134 return pat
65 if hasattr(pat, 'read') and 'r' in mode:
135 if hasattr(pat, 'read') and 'r' in mode:
66 return pat
136 return pat
67 return open(make_filename(repo, pat, node, total, seqno, revwidth,
137 return open(make_filename(repo, pat, node, total, seqno, revwidth,
68 pathname),
138 pathname),
69 mode)
139 mode)
70
140
71 def matchpats(repo, pats=[], opts={}, head=''):
141 def matchpats(repo, pats=[], opts={}, head=''):
72 cwd = repo.getcwd()
142 cwd = repo.getcwd()
73 if not pats and cwd:
143 if not pats and cwd:
74 opts['include'] = [os.path.join(cwd, i)
144 opts['include'] = [os.path.join(cwd, i)
75 for i in opts.get('include', [])]
145 for i in opts.get('include', [])]
76 opts['exclude'] = [os.path.join(cwd, x)
146 opts['exclude'] = [os.path.join(cwd, x)
77 for x in opts.get('exclude', [])]
147 for x in opts.get('exclude', [])]
78 cwd = ''
148 cwd = ''
79 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
149 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
80 opts.get('exclude'), head)
150 opts.get('exclude'), head)
81
151
82 def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
152 def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
83 files, matchfn, anypats = matchpats(repo, pats, opts, head)
153 files, matchfn, anypats = matchpats(repo, pats, opts, head)
84 exact = dict(zip(files, files))
154 exact = dict(zip(files, files))
85 def walk():
155 def walk():
86 for src, fn in repo.walk(node=node, files=files, match=matchfn,
156 for src, fn in repo.walk(node=node, files=files, match=matchfn,
87 badmatch=badmatch):
157 badmatch=badmatch):
88 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
158 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
89 return files, matchfn, walk()
159 return files, matchfn, walk()
90
160
91 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
161 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
92 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
162 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
93 for r in results:
163 for r in results:
94 yield r
164 yield r
95
165
96 def findrenames(repo, added=None, removed=None, threshold=0.5):
166 def findrenames(repo, added=None, removed=None, threshold=0.5):
97 if added is None or removed is None:
167 if added is None or removed is None:
98 added, removed = repo.status()[1:3]
168 added, removed = repo.status()[1:3]
99 changes = repo.changelog.read(repo.dirstate.parents()[0])
169 changes = repo.changelog.read(repo.dirstate.parents()[0])
100 mf = repo.manifest.read(changes[0])
170 mf = repo.manifest.read(changes[0])
101 for a in added:
171 for a in added:
102 aa = repo.wread(a)
172 aa = repo.wread(a)
103 bestscore, bestname = None, None
173 bestscore, bestname = None, None
104 for r in removed:
174 for r in removed:
105 rr = repo.file(r).read(mf[r])
175 rr = repo.file(r).read(mf[r])
106 delta = mdiff.textdiff(aa, rr)
176 delta = mdiff.textdiff(aa, rr)
107 if len(delta) < len(aa):
177 if len(delta) < len(aa):
108 myscore = 1.0 - (float(len(delta)) / len(aa))
178 myscore = 1.0 - (float(len(delta)) / len(aa))
109 if bestscore is None or myscore > bestscore:
179 if bestscore is None or myscore > bestscore:
110 bestscore, bestname = myscore, r
180 bestscore, bestname = myscore, r
111 if bestname and bestscore >= threshold:
181 if bestname and bestscore >= threshold:
112 yield bestname, a, bestscore
182 yield bestname, a, bestscore
113
183
114 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
184 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
115 similarity=None):
185 similarity=None):
116 if dry_run is None:
186 if dry_run is None:
117 dry_run = opts.get('dry_run')
187 dry_run = opts.get('dry_run')
118 if similarity is None:
188 if similarity is None:
119 similarity = float(opts.get('similarity') or 0)
189 similarity = float(opts.get('similarity') or 0)
120 add, remove = [], []
190 add, remove = [], []
121 mapping = {}
191 mapping = {}
122 for src, abs, rel, exact in walk(repo, pats, opts):
192 for src, abs, rel, exact in walk(repo, pats, opts):
123 if src == 'f' and repo.dirstate.state(abs) == '?':
193 if src == 'f' and repo.dirstate.state(abs) == '?':
124 add.append(abs)
194 add.append(abs)
125 mapping[abs] = rel, exact
195 mapping[abs] = rel, exact
126 if repo.ui.verbose or not exact:
196 if repo.ui.verbose or not exact:
127 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
197 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
128 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
198 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
129 remove.append(abs)
199 remove.append(abs)
130 mapping[abs] = rel, exact
200 mapping[abs] = rel, exact
131 if repo.ui.verbose or not exact:
201 if repo.ui.verbose or not exact:
132 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
202 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
133 if not dry_run:
203 if not dry_run:
134 repo.add(add, wlock=wlock)
204 repo.add(add, wlock=wlock)
135 repo.remove(remove, wlock=wlock)
205 repo.remove(remove, wlock=wlock)
136 if similarity > 0:
206 if similarity > 0:
137 for old, new, score in findrenames(repo, add, remove, similarity):
207 for old, new, score in findrenames(repo, add, remove, similarity):
138 oldrel, oldexact = mapping[old]
208 oldrel, oldexact = mapping[old]
139 newrel, newexact = mapping[new]
209 newrel, newexact = mapping[new]
140 if repo.ui.verbose or not oldexact or not newexact:
210 if repo.ui.verbose or not oldexact or not newexact:
141 repo.ui.status(_('recording removal of %s as rename to %s '
211 repo.ui.status(_('recording removal of %s as rename to %s '
142 '(%d%% similar)\n') %
212 '(%d%% similar)\n') %
143 (oldrel, newrel, score * 100))
213 (oldrel, newrel, score * 100))
144 if not dry_run:
214 if not dry_run:
145 repo.copy(old, new, wlock=wlock)
215 repo.copy(old, new, wlock=wlock)
@@ -1,3509 +1,3439 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from 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 shlex")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb shlex")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
13 demandload(globals(), "fnmatch difflib patch random signal tempfile time")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 demandload(globals(), "archival cStringIO changegroup")
15 demandload(globals(), "archival cStringIO changegroup")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
16 demandload(globals(), "cmdutil hgweb.server sshserver")
17
17
18 class UnknownCommand(Exception):
18 class UnknownCommand(Exception):
19 """Exception raised if command is not in the command table."""
19 """Exception raised if command is not in the command table."""
20 class AmbiguousCommand(Exception):
20 class AmbiguousCommand(Exception):
21 """Exception raised if command shortcut matches more than one command."""
21 """Exception raised if command shortcut matches more than one command."""
22
22
23 def bail_if_changed(repo):
23 def bail_if_changed(repo):
24 modified, added, removed, deleted = repo.status()[:4]
24 modified, added, removed, deleted = repo.status()[:4]
25 if modified or added or removed or deleted:
25 if modified or added or removed or deleted:
26 raise util.Abort(_("outstanding uncommitted changes"))
26 raise util.Abort(_("outstanding uncommitted changes"))
27
27
28 def 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 logmessage(opts):
34 def logmessage(opts):
35 """ get the log message according to -m and -l option """
35 """ get the log message according to -m and -l option """
36 message = opts['message']
36 message = opts['message']
37 logfile = opts['logfile']
37 logfile = opts['logfile']
38
38
39 if message and logfile:
39 if message and logfile:
40 raise util.Abort(_('options --message and --logfile are mutually '
40 raise util.Abort(_('options --message and --logfile are mutually '
41 'exclusive'))
41 'exclusive'))
42 if not message and logfile:
42 if not message and logfile:
43 try:
43 try:
44 if logfile == '-':
44 if logfile == '-':
45 message = sys.stdin.read()
45 message = sys.stdin.read()
46 else:
46 else:
47 message = open(logfile).read()
47 message = open(logfile).read()
48 except IOError, inst:
48 except IOError, inst:
49 raise util.Abort(_("can't read commit message '%s': %s") %
49 raise util.Abort(_("can't read commit message '%s': %s") %
50 (logfile, inst.strerror))
50 (logfile, inst.strerror))
51 return message
51 return message
52
52
53 def walkchangerevs(ui, repo, pats, opts):
53 def walkchangerevs(ui, repo, pats, opts):
54 '''Iterate over files and the revs they changed in.
54 '''Iterate over files and the revs they changed in.
55
55
56 Callers most commonly need to iterate backwards over the history
56 Callers most commonly need to iterate backwards over the history
57 it is interested in. Doing so has awful (quadratic-looking)
57 it is interested in. Doing so has awful (quadratic-looking)
58 performance, so we use iterators in a "windowed" way.
58 performance, so we use iterators in a "windowed" way.
59
59
60 We walk a window of revisions in the desired order. Within the
60 We walk a window of revisions in the desired order. Within the
61 window, we first walk forwards to gather data, then in the desired
61 window, we first walk forwards to gather data, then in the desired
62 order (usually backwards) to display it.
62 order (usually backwards) to display it.
63
63
64 This function returns an (iterator, getchange, matchfn) tuple. The
64 This function returns an (iterator, getchange, matchfn) tuple. The
65 getchange function returns the changelog entry for a numeric
65 getchange function returns the changelog entry for a numeric
66 revision. The iterator yields 3-tuples. They will be of one of
66 revision. The iterator yields 3-tuples. They will be of one of
67 the following forms:
67 the following forms:
68
68
69 "window", incrementing, lastrev: stepping through a window,
69 "window", incrementing, lastrev: stepping through a window,
70 positive if walking forwards through revs, last rev in the
70 positive if walking forwards through revs, last rev in the
71 sequence iterated over - use to reset state for the current window
71 sequence iterated over - use to reset state for the current window
72
72
73 "add", rev, fns: out-of-order traversal of the given file names
73 "add", rev, fns: out-of-order traversal of the given file names
74 fns, which changed during revision rev - use to gather data for
74 fns, which changed during revision rev - use to gather data for
75 possible display
75 possible display
76
76
77 "iter", rev, None: in-order traversal of the revs earlier iterated
77 "iter", rev, None: in-order traversal of the revs earlier iterated
78 over with "add" - use to display data'''
78 over with "add" - use to display data'''
79
79
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
80 def increasing_windows(start, end, windowsize=8, sizelimit=512):
81 if start < end:
81 if start < end:
82 while start < end:
82 while start < end:
83 yield start, min(windowsize, end-start)
83 yield start, min(windowsize, end-start)
84 start += windowsize
84 start += windowsize
85 if windowsize < sizelimit:
85 if windowsize < sizelimit:
86 windowsize *= 2
86 windowsize *= 2
87 else:
87 else:
88 while start > end:
88 while start > end:
89 yield start, min(windowsize, start-end-1)
89 yield start, min(windowsize, start-end-1)
90 start -= windowsize
90 start -= windowsize
91 if windowsize < sizelimit:
91 if windowsize < sizelimit:
92 windowsize *= 2
92 windowsize *= 2
93
93
94
94
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
96 follow = opts.get('follow') or opts.get('follow_first')
96 follow = opts.get('follow') or opts.get('follow_first')
97
97
98 if repo.changelog.count() == 0:
98 if repo.changelog.count() == 0:
99 return [], False, matchfn
99 return [], False, matchfn
100
100
101 if follow:
101 if follow:
102 p = repo.dirstate.parents()[0]
102 p = repo.dirstate.parents()[0]
103 if p == nullid:
103 if p == nullid:
104 ui.warn(_('No working directory revision; defaulting to tip\n'))
104 ui.warn(_('No working directory revision; defaulting to tip\n'))
105 start = 'tip'
105 start = 'tip'
106 else:
106 else:
107 start = repo.changelog.rev(p)
107 start = repo.changelog.rev(p)
108 defrange = '%s:0' % start
108 defrange = '%s:0' % start
109 else:
109 else:
110 defrange = 'tip:0'
110 defrange = 'tip:0'
111 revs = map(int, revrange(ui, repo, opts['rev'] or [defrange]))
111 revs = map(int, cmdutil.revrange(ui, repo, opts['rev'] or [defrange]))
112 wanted = {}
112 wanted = {}
113 slowpath = anypats
113 slowpath = anypats
114 fncache = {}
114 fncache = {}
115
115
116 chcache = {}
116 chcache = {}
117 def getchange(rev):
117 def getchange(rev):
118 ch = chcache.get(rev)
118 ch = chcache.get(rev)
119 if ch is None:
119 if ch is None:
120 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
120 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
121 return ch
121 return ch
122
122
123 if not slowpath and not files:
123 if not slowpath and not files:
124 # No files, no patterns. Display all revs.
124 # No files, no patterns. Display all revs.
125 wanted = dict(zip(revs, revs))
125 wanted = dict(zip(revs, revs))
126 copies = []
126 copies = []
127 if not slowpath:
127 if not slowpath:
128 # Only files, no patterns. Check the history of each file.
128 # Only files, no patterns. Check the history of each file.
129 def filerevgen(filelog, node):
129 def filerevgen(filelog, node):
130 cl_count = repo.changelog.count()
130 cl_count = repo.changelog.count()
131 if node is None:
131 if node is None:
132 last = filelog.count() - 1
132 last = filelog.count() - 1
133 else:
133 else:
134 last = filelog.rev(node)
134 last = filelog.rev(node)
135 for i, window in increasing_windows(last, -1):
135 for i, window in increasing_windows(last, -1):
136 revs = []
136 revs = []
137 for j in xrange(i - window, i + 1):
137 for j in xrange(i - window, i + 1):
138 n = filelog.node(j)
138 n = filelog.node(j)
139 revs.append((filelog.linkrev(n),
139 revs.append((filelog.linkrev(n),
140 follow and filelog.renamed(n)))
140 follow and filelog.renamed(n)))
141 revs.reverse()
141 revs.reverse()
142 for rev in revs:
142 for rev in revs:
143 # only yield rev for which we have the changelog, it can
143 # only yield rev for which we have the changelog, it can
144 # happen while doing "hg log" during a pull or commit
144 # happen while doing "hg log" during a pull or commit
145 if rev[0] < cl_count:
145 if rev[0] < cl_count:
146 yield rev
146 yield rev
147 def iterfiles():
147 def iterfiles():
148 for filename in files:
148 for filename in files:
149 yield filename, None
149 yield filename, None
150 for filename_node in copies:
150 for filename_node in copies:
151 yield filename_node
151 yield filename_node
152 minrev, maxrev = min(revs), max(revs)
152 minrev, maxrev = min(revs), max(revs)
153 for file_, node in iterfiles():
153 for file_, node in iterfiles():
154 filelog = repo.file(file_)
154 filelog = repo.file(file_)
155 # A zero count may be a directory or deleted file, so
155 # A zero count may be a directory or deleted file, so
156 # try to find matching entries on the slow path.
156 # try to find matching entries on the slow path.
157 if filelog.count() == 0:
157 if filelog.count() == 0:
158 slowpath = True
158 slowpath = True
159 break
159 break
160 for rev, copied in filerevgen(filelog, node):
160 for rev, copied in filerevgen(filelog, node):
161 if rev <= maxrev:
161 if rev <= maxrev:
162 if rev < minrev:
162 if rev < minrev:
163 break
163 break
164 fncache.setdefault(rev, [])
164 fncache.setdefault(rev, [])
165 fncache[rev].append(file_)
165 fncache[rev].append(file_)
166 wanted[rev] = 1
166 wanted[rev] = 1
167 if follow and copied:
167 if follow and copied:
168 copies.append(copied)
168 copies.append(copied)
169 if slowpath:
169 if slowpath:
170 if follow:
170 if follow:
171 raise util.Abort(_('can only follow copies/renames for explicit '
171 raise util.Abort(_('can only follow copies/renames for explicit '
172 'file names'))
172 'file names'))
173
173
174 # The slow path checks files modified in every changeset.
174 # The slow path checks files modified in every changeset.
175 def changerevgen():
175 def changerevgen():
176 for i, window in increasing_windows(repo.changelog.count()-1, -1):
176 for i, window in increasing_windows(repo.changelog.count()-1, -1):
177 for j in xrange(i - window, i + 1):
177 for j in xrange(i - window, i + 1):
178 yield j, getchange(j)[3]
178 yield j, getchange(j)[3]
179
179
180 for rev, changefiles in changerevgen():
180 for rev, changefiles in changerevgen():
181 matches = filter(matchfn, changefiles)
181 matches = filter(matchfn, changefiles)
182 if matches:
182 if matches:
183 fncache[rev] = matches
183 fncache[rev] = matches
184 wanted[rev] = 1
184 wanted[rev] = 1
185
185
186 class followfilter:
186 class followfilter:
187 def __init__(self, onlyfirst=False):
187 def __init__(self, onlyfirst=False):
188 self.startrev = -1
188 self.startrev = -1
189 self.roots = []
189 self.roots = []
190 self.onlyfirst = onlyfirst
190 self.onlyfirst = onlyfirst
191
191
192 def match(self, rev):
192 def match(self, rev):
193 def realparents(rev):
193 def realparents(rev):
194 if self.onlyfirst:
194 if self.onlyfirst:
195 return repo.changelog.parentrevs(rev)[0:1]
195 return repo.changelog.parentrevs(rev)[0:1]
196 else:
196 else:
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev))
198
198
199 if self.startrev == -1:
199 if self.startrev == -1:
200 self.startrev = rev
200 self.startrev = rev
201 return True
201 return True
202
202
203 if rev > self.startrev:
203 if rev > self.startrev:
204 # forward: all descendants
204 # forward: all descendants
205 if not self.roots:
205 if not self.roots:
206 self.roots.append(self.startrev)
206 self.roots.append(self.startrev)
207 for parent in realparents(rev):
207 for parent in realparents(rev):
208 if parent in self.roots:
208 if parent in self.roots:
209 self.roots.append(rev)
209 self.roots.append(rev)
210 return True
210 return True
211 else:
211 else:
212 # backwards: all parents
212 # backwards: all parents
213 if not self.roots:
213 if not self.roots:
214 self.roots.extend(realparents(self.startrev))
214 self.roots.extend(realparents(self.startrev))
215 if rev in self.roots:
215 if rev in self.roots:
216 self.roots.remove(rev)
216 self.roots.remove(rev)
217 self.roots.extend(realparents(rev))
217 self.roots.extend(realparents(rev))
218 return True
218 return True
219
219
220 return False
220 return False
221
221
222 # it might be worthwhile to do this in the iterator if the rev range
222 # it might be worthwhile to do this in the iterator if the rev range
223 # is descending and the prune args are all within that range
223 # is descending and the prune args are all within that range
224 for rev in opts.get('prune', ()):
224 for rev in opts.get('prune', ()):
225 rev = repo.changelog.rev(repo.lookup(rev))
225 rev = repo.changelog.rev(repo.lookup(rev))
226 ff = followfilter()
226 ff = followfilter()
227 stop = min(revs[0], revs[-1])
227 stop = min(revs[0], revs[-1])
228 for x in range(rev, stop-1, -1):
228 for x in range(rev, stop-1, -1):
229 if ff.match(x) and wanted.has_key(x):
229 if ff.match(x) and wanted.has_key(x):
230 del wanted[x]
230 del wanted[x]
231
231
232 def iterate():
232 def iterate():
233 if follow and not files:
233 if follow and not files:
234 ff = followfilter(onlyfirst=opts.get('follow_first'))
234 ff = followfilter(onlyfirst=opts.get('follow_first'))
235 def want(rev):
235 def want(rev):
236 if ff.match(rev) and rev in wanted:
236 if ff.match(rev) and rev in wanted:
237 return True
237 return True
238 return False
238 return False
239 else:
239 else:
240 def want(rev):
240 def want(rev):
241 return rev in wanted
241 return rev in wanted
242
242
243 for i, window in increasing_windows(0, len(revs)):
243 for i, window in increasing_windows(0, len(revs)):
244 yield 'window', revs[0] < revs[-1], revs[-1]
244 yield 'window', revs[0] < revs[-1], revs[-1]
245 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
245 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
246 srevs = list(nrevs)
246 srevs = list(nrevs)
247 srevs.sort()
247 srevs.sort()
248 for rev in srevs:
248 for rev in srevs:
249 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
249 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
250 yield 'add', rev, fns
250 yield 'add', rev, fns
251 for rev in nrevs:
251 for rev in nrevs:
252 yield 'iter', rev, None
252 yield 'iter', rev, None
253 return iterate(), getchange, matchfn
253 return iterate(), getchange, matchfn
254
254
255 revrangesep = ':'
256
257 def revfix(repo, val, defval):
258 '''turn user-level id of changeset into rev number.
259 user-level id can be tag, changeset, rev number, or negative rev
260 number relative to number of revs (-1 is tip, etc).'''
261 if not val:
262 return defval
263 try:
264 num = int(val)
265 if str(num) != val:
266 raise ValueError
267 if num < 0:
268 num += repo.changelog.count()
269 if num < 0:
270 num = 0
271 elif num >= repo.changelog.count():
272 raise ValueError
273 except ValueError:
274 try:
275 num = repo.changelog.rev(repo.lookup(val))
276 except KeyError:
277 raise util.Abort(_('invalid revision identifier %s') % val)
278 return num
279
280 def revpair(ui, repo, revs):
281 '''return pair of nodes, given list of revisions. second item can
282 be None, meaning use working dir.'''
283 if not revs:
284 return repo.dirstate.parents()[0], None
285 end = None
286 if len(revs) == 1:
287 start = revs[0]
288 if revrangesep in start:
289 start, end = start.split(revrangesep, 1)
290 start = revfix(repo, start, 0)
291 end = revfix(repo, end, repo.changelog.count() - 1)
292 else:
293 start = revfix(repo, start, None)
294 elif len(revs) == 2:
295 if revrangesep in revs[0] or revrangesep in revs[1]:
296 raise util.Abort(_('too many revisions specified'))
297 start = revfix(repo, revs[0], None)
298 end = revfix(repo, revs[1], None)
299 else:
300 raise util.Abort(_('too many revisions specified'))
301 if end is not None: end = repo.lookup(str(end))
302 return repo.lookup(str(start)), end
303
304 def revrange(ui, repo, revs):
305 """Yield revision as strings from a list of revision specifications."""
306 seen = {}
307 for spec in revs:
308 if revrangesep in spec:
309 start, end = spec.split(revrangesep, 1)
310 start = revfix(repo, start, 0)
311 end = revfix(repo, end, repo.changelog.count() - 1)
312 step = start > end and -1 or 1
313 for rev in xrange(start, end+step, step):
314 if rev in seen:
315 continue
316 seen[rev] = 1
317 yield str(rev)
318 else:
319 rev = revfix(repo, spec, None)
320 if rev in seen:
321 continue
322 seen[rev] = 1
323 yield str(rev)
324
325 def write_bundle(cg, filename=None, compress=True):
255 def write_bundle(cg, filename=None, compress=True):
326 """Write a bundle file and return its filename.
256 """Write a bundle file and return its filename.
327
257
328 Existing files will not be overwritten.
258 Existing files will not be overwritten.
329 If no filename is specified, a temporary file is created.
259 If no filename is specified, a temporary file is created.
330 bz2 compression can be turned off.
260 bz2 compression can be turned off.
331 The bundle file will be deleted in case of errors.
261 The bundle file will be deleted in case of errors.
332 """
262 """
333 class nocompress(object):
263 class nocompress(object):
334 def compress(self, x):
264 def compress(self, x):
335 return x
265 return x
336 def flush(self):
266 def flush(self):
337 return ""
267 return ""
338
268
339 fh = None
269 fh = None
340 cleanup = None
270 cleanup = None
341 try:
271 try:
342 if filename:
272 if filename:
343 if os.path.exists(filename):
273 if os.path.exists(filename):
344 raise util.Abort(_("file '%s' already exists") % filename)
274 raise util.Abort(_("file '%s' already exists") % filename)
345 fh = open(filename, "wb")
275 fh = open(filename, "wb")
346 else:
276 else:
347 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
277 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
348 fh = os.fdopen(fd, "wb")
278 fh = os.fdopen(fd, "wb")
349 cleanup = filename
279 cleanup = filename
350
280
351 if compress:
281 if compress:
352 fh.write("HG10")
282 fh.write("HG10")
353 z = bz2.BZ2Compressor(9)
283 z = bz2.BZ2Compressor(9)
354 else:
284 else:
355 fh.write("HG10UN")
285 fh.write("HG10UN")
356 z = nocompress()
286 z = nocompress()
357 # parse the changegroup data, otherwise we will block
287 # parse the changegroup data, otherwise we will block
358 # in case of sshrepo because we don't know the end of the stream
288 # in case of sshrepo because we don't know the end of the stream
359
289
360 # an empty chunkiter is the end of the changegroup
290 # an empty chunkiter is the end of the changegroup
361 empty = False
291 empty = False
362 while not empty:
292 while not empty:
363 empty = True
293 empty = True
364 for chunk in changegroup.chunkiter(cg):
294 for chunk in changegroup.chunkiter(cg):
365 empty = False
295 empty = False
366 fh.write(z.compress(changegroup.genchunk(chunk)))
296 fh.write(z.compress(changegroup.genchunk(chunk)))
367 fh.write(z.compress(changegroup.closechunk()))
297 fh.write(z.compress(changegroup.closechunk()))
368 fh.write(z.flush())
298 fh.write(z.flush())
369 cleanup = None
299 cleanup = None
370 return filename
300 return filename
371 finally:
301 finally:
372 if fh is not None:
302 if fh is not None:
373 fh.close()
303 fh.close()
374 if cleanup is not None:
304 if cleanup is not None:
375 os.unlink(cleanup)
305 os.unlink(cleanup)
376
306
377 def trimuser(ui, name, rev, revcache):
307 def trimuser(ui, name, rev, revcache):
378 """trim the name of the user who committed a change"""
308 """trim the name of the user who committed a change"""
379 user = revcache.get(rev)
309 user = revcache.get(rev)
380 if user is None:
310 if user is None:
381 user = revcache[rev] = ui.shortuser(name)
311 user = revcache[rev] = ui.shortuser(name)
382 return user
312 return user
383
313
384 class changeset_printer(object):
314 class changeset_printer(object):
385 '''show changeset information when templating not requested.'''
315 '''show changeset information when templating not requested.'''
386
316
387 def __init__(self, ui, repo):
317 def __init__(self, ui, repo):
388 self.ui = ui
318 self.ui = ui
389 self.repo = repo
319 self.repo = repo
390
320
391 def show(self, rev=0, changenode=None, brinfo=None):
321 def show(self, rev=0, changenode=None, brinfo=None):
392 '''show a single changeset or file revision'''
322 '''show a single changeset or file revision'''
393 log = self.repo.changelog
323 log = self.repo.changelog
394 if changenode is None:
324 if changenode is None:
395 changenode = log.node(rev)
325 changenode = log.node(rev)
396 elif not rev:
326 elif not rev:
397 rev = log.rev(changenode)
327 rev = log.rev(changenode)
398
328
399 if self.ui.quiet:
329 if self.ui.quiet:
400 self.ui.write("%d:%s\n" % (rev, short(changenode)))
330 self.ui.write("%d:%s\n" % (rev, short(changenode)))
401 return
331 return
402
332
403 changes = log.read(changenode)
333 changes = log.read(changenode)
404 date = util.datestr(changes[2])
334 date = util.datestr(changes[2])
405
335
406 hexfunc = self.ui.debugflag and hex or short
336 hexfunc = self.ui.debugflag and hex or short
407
337
408 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
338 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode)
409 if self.ui.debugflag or p != nullid]
339 if self.ui.debugflag or p != nullid]
410 if (not self.ui.debugflag and len(parents) == 1 and
340 if (not self.ui.debugflag and len(parents) == 1 and
411 parents[0][0] == rev-1):
341 parents[0][0] == rev-1):
412 parents = []
342 parents = []
413
343
414 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
344 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
415
345
416 for tag in self.repo.nodetags(changenode):
346 for tag in self.repo.nodetags(changenode):
417 self.ui.status(_("tag: %s\n") % tag)
347 self.ui.status(_("tag: %s\n") % tag)
418 for parent in parents:
348 for parent in parents:
419 self.ui.write(_("parent: %d:%s\n") % parent)
349 self.ui.write(_("parent: %d:%s\n") % parent)
420
350
421 if brinfo and changenode in brinfo:
351 if brinfo and changenode in brinfo:
422 br = brinfo[changenode]
352 br = brinfo[changenode]
423 self.ui.write(_("branch: %s\n") % " ".join(br))
353 self.ui.write(_("branch: %s\n") % " ".join(br))
424
354
425 self.ui.debug(_("manifest: %d:%s\n") %
355 self.ui.debug(_("manifest: %d:%s\n") %
426 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
356 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
427 self.ui.status(_("user: %s\n") % changes[1])
357 self.ui.status(_("user: %s\n") % changes[1])
428 self.ui.status(_("date: %s\n") % date)
358 self.ui.status(_("date: %s\n") % date)
429
359
430 if self.ui.debugflag:
360 if self.ui.debugflag:
431 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
361 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
432 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
362 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
433 files):
363 files):
434 if value:
364 if value:
435 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
365 self.ui.note("%-12s %s\n" % (key, " ".join(value)))
436 else:
366 else:
437 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
367 self.ui.note(_("files: %s\n") % " ".join(changes[3]))
438
368
439 description = changes[4].strip()
369 description = changes[4].strip()
440 if description:
370 if description:
441 if self.ui.verbose:
371 if self.ui.verbose:
442 self.ui.status(_("description:\n"))
372 self.ui.status(_("description:\n"))
443 self.ui.status(description)
373 self.ui.status(description)
444 self.ui.status("\n\n")
374 self.ui.status("\n\n")
445 else:
375 else:
446 self.ui.status(_("summary: %s\n") %
376 self.ui.status(_("summary: %s\n") %
447 description.splitlines()[0])
377 description.splitlines()[0])
448 self.ui.status("\n")
378 self.ui.status("\n")
449
379
450 def show_changeset(ui, repo, opts):
380 def show_changeset(ui, repo, opts):
451 '''show one changeset. uses template or regular display. caller
381 '''show one changeset. uses template or regular display. caller
452 can pass in 'style' and 'template' options in opts.'''
382 can pass in 'style' and 'template' options in opts.'''
453
383
454 tmpl = opts.get('template')
384 tmpl = opts.get('template')
455 if tmpl:
385 if tmpl:
456 tmpl = templater.parsestring(tmpl, quoted=False)
386 tmpl = templater.parsestring(tmpl, quoted=False)
457 else:
387 else:
458 tmpl = ui.config('ui', 'logtemplate')
388 tmpl = ui.config('ui', 'logtemplate')
459 if tmpl: tmpl = templater.parsestring(tmpl)
389 if tmpl: tmpl = templater.parsestring(tmpl)
460 mapfile = opts.get('style') or ui.config('ui', 'style')
390 mapfile = opts.get('style') or ui.config('ui', 'style')
461 if tmpl or mapfile:
391 if tmpl or mapfile:
462 if mapfile:
392 if mapfile:
463 if not os.path.isfile(mapfile):
393 if not os.path.isfile(mapfile):
464 mapname = templater.templatepath('map-cmdline.' + mapfile)
394 mapname = templater.templatepath('map-cmdline.' + mapfile)
465 if not mapname: mapname = templater.templatepath(mapfile)
395 if not mapname: mapname = templater.templatepath(mapfile)
466 if mapname: mapfile = mapname
396 if mapname: mapfile = mapname
467 try:
397 try:
468 t = templater.changeset_templater(ui, repo, mapfile)
398 t = templater.changeset_templater(ui, repo, mapfile)
469 except SyntaxError, inst:
399 except SyntaxError, inst:
470 raise util.Abort(inst.args[0])
400 raise util.Abort(inst.args[0])
471 if tmpl: t.use_template(tmpl)
401 if tmpl: t.use_template(tmpl)
472 return t
402 return t
473 return changeset_printer(ui, repo)
403 return changeset_printer(ui, repo)
474
404
475 def setremoteconfig(ui, opts):
405 def setremoteconfig(ui, opts):
476 "copy remote options to ui tree"
406 "copy remote options to ui tree"
477 if opts.get('ssh'):
407 if opts.get('ssh'):
478 ui.setconfig("ui", "ssh", opts['ssh'])
408 ui.setconfig("ui", "ssh", opts['ssh'])
479 if opts.get('remotecmd'):
409 if opts.get('remotecmd'):
480 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
410 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
481
411
482 def show_version(ui):
412 def show_version(ui):
483 """output version and copyright information"""
413 """output version and copyright information"""
484 ui.write(_("Mercurial Distributed SCM (version %s)\n")
414 ui.write(_("Mercurial Distributed SCM (version %s)\n")
485 % version.get_version())
415 % version.get_version())
486 ui.status(_(
416 ui.status(_(
487 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
417 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
488 "This is free software; see the source for copying conditions. "
418 "This is free software; see the source for copying conditions. "
489 "There is NO\nwarranty; "
419 "There is NO\nwarranty; "
490 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
420 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
491 ))
421 ))
492
422
493 def help_(ui, name=None, with_version=False):
423 def help_(ui, name=None, with_version=False):
494 """show help for a command, extension, or list of commands
424 """show help for a command, extension, or list of commands
495
425
496 With no arguments, print a list of commands and short help.
426 With no arguments, print a list of commands and short help.
497
427
498 Given a command name, print help for that command.
428 Given a command name, print help for that command.
499
429
500 Given an extension name, print help for that extension, and the
430 Given an extension name, print help for that extension, and the
501 commands it provides."""
431 commands it provides."""
502 option_lists = []
432 option_lists = []
503
433
504 def helpcmd(name):
434 def helpcmd(name):
505 if with_version:
435 if with_version:
506 show_version(ui)
436 show_version(ui)
507 ui.write('\n')
437 ui.write('\n')
508 aliases, i = findcmd(ui, name)
438 aliases, i = findcmd(ui, name)
509 # synopsis
439 # synopsis
510 ui.write("%s\n\n" % i[2])
440 ui.write("%s\n\n" % i[2])
511
441
512 # description
442 # description
513 doc = i[0].__doc__
443 doc = i[0].__doc__
514 if not doc:
444 if not doc:
515 doc = _("(No help text available)")
445 doc = _("(No help text available)")
516 if ui.quiet:
446 if ui.quiet:
517 doc = doc.splitlines(0)[0]
447 doc = doc.splitlines(0)[0]
518 ui.write("%s\n" % doc.rstrip())
448 ui.write("%s\n" % doc.rstrip())
519
449
520 if not ui.quiet:
450 if not ui.quiet:
521 # aliases
451 # aliases
522 if len(aliases) > 1:
452 if len(aliases) > 1:
523 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
453 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
524
454
525 # options
455 # options
526 if i[1]:
456 if i[1]:
527 option_lists.append(("options", i[1]))
457 option_lists.append(("options", i[1]))
528
458
529 def helplist(select=None):
459 def helplist(select=None):
530 h = {}
460 h = {}
531 cmds = {}
461 cmds = {}
532 for c, e in table.items():
462 for c, e in table.items():
533 f = c.split("|", 1)[0]
463 f = c.split("|", 1)[0]
534 if select and not select(f):
464 if select and not select(f):
535 continue
465 continue
536 if name == "shortlist" and not f.startswith("^"):
466 if name == "shortlist" and not f.startswith("^"):
537 continue
467 continue
538 f = f.lstrip("^")
468 f = f.lstrip("^")
539 if not ui.debugflag and f.startswith("debug"):
469 if not ui.debugflag and f.startswith("debug"):
540 continue
470 continue
541 doc = e[0].__doc__
471 doc = e[0].__doc__
542 if not doc:
472 if not doc:
543 doc = _("(No help text available)")
473 doc = _("(No help text available)")
544 h[f] = doc.splitlines(0)[0].rstrip()
474 h[f] = doc.splitlines(0)[0].rstrip()
545 cmds[f] = c.lstrip("^")
475 cmds[f] = c.lstrip("^")
546
476
547 fns = h.keys()
477 fns = h.keys()
548 fns.sort()
478 fns.sort()
549 m = max(map(len, fns))
479 m = max(map(len, fns))
550 for f in fns:
480 for f in fns:
551 if ui.verbose:
481 if ui.verbose:
552 commands = cmds[f].replace("|",", ")
482 commands = cmds[f].replace("|",", ")
553 ui.write(" %s:\n %s\n"%(commands, h[f]))
483 ui.write(" %s:\n %s\n"%(commands, h[f]))
554 else:
484 else:
555 ui.write(' %-*s %s\n' % (m, f, h[f]))
485 ui.write(' %-*s %s\n' % (m, f, h[f]))
556
486
557 def helpext(name):
487 def helpext(name):
558 try:
488 try:
559 mod = findext(name)
489 mod = findext(name)
560 except KeyError:
490 except KeyError:
561 raise UnknownCommand(name)
491 raise UnknownCommand(name)
562
492
563 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
493 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
564 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
494 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
565 for d in doc[1:]:
495 for d in doc[1:]:
566 ui.write(d, '\n')
496 ui.write(d, '\n')
567
497
568 ui.status('\n')
498 ui.status('\n')
569 if ui.verbose:
499 if ui.verbose:
570 ui.status(_('list of commands:\n\n'))
500 ui.status(_('list of commands:\n\n'))
571 else:
501 else:
572 ui.status(_('list of commands (use "hg help -v %s" '
502 ui.status(_('list of commands (use "hg help -v %s" '
573 'to show aliases and global options):\n\n') % name)
503 'to show aliases and global options):\n\n') % name)
574
504
575 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
505 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
576 helplist(modcmds.has_key)
506 helplist(modcmds.has_key)
577
507
578 if name and name != 'shortlist':
508 if name and name != 'shortlist':
579 try:
509 try:
580 helpcmd(name)
510 helpcmd(name)
581 except UnknownCommand:
511 except UnknownCommand:
582 helpext(name)
512 helpext(name)
583
513
584 else:
514 else:
585 # program name
515 # program name
586 if ui.verbose or with_version:
516 if ui.verbose or with_version:
587 show_version(ui)
517 show_version(ui)
588 else:
518 else:
589 ui.status(_("Mercurial Distributed SCM\n"))
519 ui.status(_("Mercurial Distributed SCM\n"))
590 ui.status('\n')
520 ui.status('\n')
591
521
592 # list of commands
522 # list of commands
593 if name == "shortlist":
523 if name == "shortlist":
594 ui.status(_('basic commands (use "hg help" '
524 ui.status(_('basic commands (use "hg help" '
595 'for the full list or option "-v" for details):\n\n'))
525 'for the full list or option "-v" for details):\n\n'))
596 elif ui.verbose:
526 elif ui.verbose:
597 ui.status(_('list of commands:\n\n'))
527 ui.status(_('list of commands:\n\n'))
598 else:
528 else:
599 ui.status(_('list of commands (use "hg help -v" '
529 ui.status(_('list of commands (use "hg help -v" '
600 'to show aliases and global options):\n\n'))
530 'to show aliases and global options):\n\n'))
601
531
602 helplist()
532 helplist()
603
533
604 # global options
534 # global options
605 if ui.verbose:
535 if ui.verbose:
606 option_lists.append(("global options", globalopts))
536 option_lists.append(("global options", globalopts))
607
537
608 # list all option lists
538 # list all option lists
609 opt_output = []
539 opt_output = []
610 for title, options in option_lists:
540 for title, options in option_lists:
611 opt_output.append(("\n%s:\n" % title, None))
541 opt_output.append(("\n%s:\n" % title, None))
612 for shortopt, longopt, default, desc in options:
542 for shortopt, longopt, default, desc in options:
613 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
543 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
614 longopt and " --%s" % longopt),
544 longopt and " --%s" % longopt),
615 "%s%s" % (desc,
545 "%s%s" % (desc,
616 default
546 default
617 and _(" (default: %s)") % default
547 and _(" (default: %s)") % default
618 or "")))
548 or "")))
619
549
620 if opt_output:
550 if opt_output:
621 opts_len = max([len(line[0]) for line in opt_output if line[1]])
551 opts_len = max([len(line[0]) for line in opt_output if line[1]])
622 for first, second in opt_output:
552 for first, second in opt_output:
623 if second:
553 if second:
624 ui.write(" %-*s %s\n" % (opts_len, first, second))
554 ui.write(" %-*s %s\n" % (opts_len, first, second))
625 else:
555 else:
626 ui.write("%s\n" % first)
556 ui.write("%s\n" % first)
627
557
628 # Commands start here, listed alphabetically
558 # Commands start here, listed alphabetically
629
559
630 def add(ui, repo, *pats, **opts):
560 def add(ui, repo, *pats, **opts):
631 """add the specified files on the next commit
561 """add the specified files on the next commit
632
562
633 Schedule files to be version controlled and added to the repository.
563 Schedule files to be version controlled and added to the repository.
634
564
635 The files will be added to the repository at the next commit.
565 The files will be added to the repository at the next commit.
636
566
637 If no names are given, add all files in the repository.
567 If no names are given, add all files in the repository.
638 """
568 """
639
569
640 names = []
570 names = []
641 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
571 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
642 if exact:
572 if exact:
643 if ui.verbose:
573 if ui.verbose:
644 ui.status(_('adding %s\n') % rel)
574 ui.status(_('adding %s\n') % rel)
645 names.append(abs)
575 names.append(abs)
646 elif repo.dirstate.state(abs) == '?':
576 elif repo.dirstate.state(abs) == '?':
647 ui.status(_('adding %s\n') % rel)
577 ui.status(_('adding %s\n') % rel)
648 names.append(abs)
578 names.append(abs)
649 if not opts.get('dry_run'):
579 if not opts.get('dry_run'):
650 repo.add(names)
580 repo.add(names)
651
581
652 def addremove(ui, repo, *pats, **opts):
582 def addremove(ui, repo, *pats, **opts):
653 """add all new files, delete all missing files (DEPRECATED)
583 """add all new files, delete all missing files (DEPRECATED)
654
584
655 Add all new files and remove all missing files from the repository.
585 Add all new files and remove all missing files from the repository.
656
586
657 New files are ignored if they match any of the patterns in .hgignore. As
587 New files are ignored if they match any of the patterns in .hgignore. As
658 with add, these changes take effect at the next commit.
588 with add, these changes take effect at the next commit.
659
589
660 Use the -s option to detect renamed files. With a parameter > 0,
590 Use the -s option to detect renamed files. With a parameter > 0,
661 this compares every removed file with every added file and records
591 this compares every removed file with every added file and records
662 those similar enough as renames. This option takes a percentage
592 those similar enough as renames. This option takes a percentage
663 between 0 (disabled) and 100 (files must be identical) as its
593 between 0 (disabled) and 100 (files must be identical) as its
664 parameter. Detecting renamed files this way can be expensive.
594 parameter. Detecting renamed files this way can be expensive.
665 """
595 """
666 sim = float(opts.get('similarity') or 0)
596 sim = float(opts.get('similarity') or 0)
667 if sim < 0 or sim > 100:
597 if sim < 0 or sim > 100:
668 raise util.Abort(_('similarity must be between 0 and 100'))
598 raise util.Abort(_('similarity must be between 0 and 100'))
669 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
599 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
670
600
671 def annotate(ui, repo, *pats, **opts):
601 def annotate(ui, repo, *pats, **opts):
672 """show changeset information per file line
602 """show changeset information per file line
673
603
674 List changes in files, showing the revision id responsible for each line
604 List changes in files, showing the revision id responsible for each line
675
605
676 This command is useful to discover who did a change or when a change took
606 This command is useful to discover who did a change or when a change took
677 place.
607 place.
678
608
679 Without the -a option, annotate will avoid processing files it
609 Without the -a option, annotate will avoid processing files it
680 detects as binary. With -a, annotate will generate an annotation
610 detects as binary. With -a, annotate will generate an annotation
681 anyway, probably with undesirable results.
611 anyway, probably with undesirable results.
682 """
612 """
683 def getnode(rev):
613 def getnode(rev):
684 return short(repo.changelog.node(rev))
614 return short(repo.changelog.node(rev))
685
615
686 ucache = {}
616 ucache = {}
687 def getname(rev):
617 def getname(rev):
688 try:
618 try:
689 return ucache[rev]
619 return ucache[rev]
690 except:
620 except:
691 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
621 u = trimuser(ui, repo.changectx(rev).user(), rev, ucache)
692 ucache[rev] = u
622 ucache[rev] = u
693 return u
623 return u
694
624
695 dcache = {}
625 dcache = {}
696 def getdate(rev):
626 def getdate(rev):
697 datestr = dcache.get(rev)
627 datestr = dcache.get(rev)
698 if datestr is None:
628 if datestr is None:
699 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
629 datestr = dcache[rev] = util.datestr(repo.changectx(rev).date())
700 return datestr
630 return datestr
701
631
702 if not pats:
632 if not pats:
703 raise util.Abort(_('at least one file name or pattern required'))
633 raise util.Abort(_('at least one file name or pattern required'))
704
634
705 opmap = [['user', getname], ['number', str], ['changeset', getnode],
635 opmap = [['user', getname], ['number', str], ['changeset', getnode],
706 ['date', getdate]]
636 ['date', getdate]]
707 if not opts['user'] and not opts['changeset'] and not opts['date']:
637 if not opts['user'] and not opts['changeset'] and not opts['date']:
708 opts['number'] = 1
638 opts['number'] = 1
709
639
710 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
640 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0])
711
641
712 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
642 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
713 node=ctx.node()):
643 node=ctx.node()):
714 fctx = ctx.filectx(abs)
644 fctx = ctx.filectx(abs)
715 if not opts['text'] and util.binary(fctx.data()):
645 if not opts['text'] and util.binary(fctx.data()):
716 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
646 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
717 continue
647 continue
718
648
719 lines = fctx.annotate()
649 lines = fctx.annotate()
720 pieces = []
650 pieces = []
721
651
722 for o, f in opmap:
652 for o, f in opmap:
723 if opts[o]:
653 if opts[o]:
724 l = [f(n) for n, dummy in lines]
654 l = [f(n) for n, dummy in lines]
725 if l:
655 if l:
726 m = max(map(len, l))
656 m = max(map(len, l))
727 pieces.append(["%*s" % (m, x) for x in l])
657 pieces.append(["%*s" % (m, x) for x in l])
728
658
729 if pieces:
659 if pieces:
730 for p, l in zip(zip(*pieces), lines):
660 for p, l in zip(zip(*pieces), lines):
731 ui.write("%s: %s" % (" ".join(p), l[1]))
661 ui.write("%s: %s" % (" ".join(p), l[1]))
732
662
733 def archive(ui, repo, dest, **opts):
663 def archive(ui, repo, dest, **opts):
734 '''create unversioned archive of a repository revision
664 '''create unversioned archive of a repository revision
735
665
736 By default, the revision used is the parent of the working
666 By default, the revision used is the parent of the working
737 directory; use "-r" to specify a different revision.
667 directory; use "-r" to specify a different revision.
738
668
739 To specify the type of archive to create, use "-t". Valid
669 To specify the type of archive to create, use "-t". Valid
740 types are:
670 types are:
741
671
742 "files" (default): a directory full of files
672 "files" (default): a directory full of files
743 "tar": tar archive, uncompressed
673 "tar": tar archive, uncompressed
744 "tbz2": tar archive, compressed using bzip2
674 "tbz2": tar archive, compressed using bzip2
745 "tgz": tar archive, compressed using gzip
675 "tgz": tar archive, compressed using gzip
746 "uzip": zip archive, uncompressed
676 "uzip": zip archive, uncompressed
747 "zip": zip archive, compressed using deflate
677 "zip": zip archive, compressed using deflate
748
678
749 The exact name of the destination archive or directory is given
679 The exact name of the destination archive or directory is given
750 using a format string; see "hg help export" for details.
680 using a format string; see "hg help export" for details.
751
681
752 Each member added to an archive file has a directory prefix
682 Each member added to an archive file has a directory prefix
753 prepended. Use "-p" to specify a format string for the prefix.
683 prepended. Use "-p" to specify a format string for the prefix.
754 The default is the basename of the archive, with suffixes removed.
684 The default is the basename of the archive, with suffixes removed.
755 '''
685 '''
756
686
757 if opts['rev']:
687 if opts['rev']:
758 node = repo.lookup(opts['rev'])
688 node = repo.lookup(opts['rev'])
759 else:
689 else:
760 node, p2 = repo.dirstate.parents()
690 node, p2 = repo.dirstate.parents()
761 if p2 != nullid:
691 if p2 != nullid:
762 raise util.Abort(_('uncommitted merge - please provide a '
692 raise util.Abort(_('uncommitted merge - please provide a '
763 'specific revision'))
693 'specific revision'))
764
694
765 dest = cmdutil.make_filename(repo, dest, node)
695 dest = cmdutil.make_filename(repo, dest, node)
766 if os.path.realpath(dest) == repo.root:
696 if os.path.realpath(dest) == repo.root:
767 raise util.Abort(_('repository root cannot be destination'))
697 raise util.Abort(_('repository root cannot be destination'))
768 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
698 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
769 kind = opts.get('type') or 'files'
699 kind = opts.get('type') or 'files'
770 prefix = opts['prefix']
700 prefix = opts['prefix']
771 if dest == '-':
701 if dest == '-':
772 if kind == 'files':
702 if kind == 'files':
773 raise util.Abort(_('cannot archive plain files to stdout'))
703 raise util.Abort(_('cannot archive plain files to stdout'))
774 dest = sys.stdout
704 dest = sys.stdout
775 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
705 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
776 prefix = cmdutil.make_filename(repo, prefix, node)
706 prefix = cmdutil.make_filename(repo, prefix, node)
777 archival.archive(repo, dest, node, kind, not opts['no_decode'],
707 archival.archive(repo, dest, node, kind, not opts['no_decode'],
778 matchfn, prefix)
708 matchfn, prefix)
779
709
780 def backout(ui, repo, rev, **opts):
710 def backout(ui, repo, rev, **opts):
781 '''reverse effect of earlier changeset
711 '''reverse effect of earlier changeset
782
712
783 Commit the backed out changes as a new changeset. The new
713 Commit the backed out changes as a new changeset. The new
784 changeset is a child of the backed out changeset.
714 changeset is a child of the backed out changeset.
785
715
786 If you back out a changeset other than the tip, a new head is
716 If you back out a changeset other than the tip, a new head is
787 created. This head is the parent of the working directory. If
717 created. This head is the parent of the working directory. If
788 you back out an old changeset, your working directory will appear
718 you back out an old changeset, your working directory will appear
789 old after the backout. You should merge the backout changeset
719 old after the backout. You should merge the backout changeset
790 with another head.
720 with another head.
791
721
792 The --merge option remembers the parent of the working directory
722 The --merge option remembers the parent of the working directory
793 before starting the backout, then merges the new head with that
723 before starting the backout, then merges the new head with that
794 changeset afterwards. This saves you from doing the merge by
724 changeset afterwards. This saves you from doing the merge by
795 hand. The result of this merge is not committed, as for a normal
725 hand. The result of this merge is not committed, as for a normal
796 merge.'''
726 merge.'''
797
727
798 bail_if_changed(repo)
728 bail_if_changed(repo)
799 op1, op2 = repo.dirstate.parents()
729 op1, op2 = repo.dirstate.parents()
800 if op2 != nullid:
730 if op2 != nullid:
801 raise util.Abort(_('outstanding uncommitted merge'))
731 raise util.Abort(_('outstanding uncommitted merge'))
802 node = repo.lookup(rev)
732 node = repo.lookup(rev)
803 p1, p2 = repo.changelog.parents(node)
733 p1, p2 = repo.changelog.parents(node)
804 if p1 == nullid:
734 if p1 == nullid:
805 raise util.Abort(_('cannot back out a change with no parents'))
735 raise util.Abort(_('cannot back out a change with no parents'))
806 if p2 != nullid:
736 if p2 != nullid:
807 if not opts['parent']:
737 if not opts['parent']:
808 raise util.Abort(_('cannot back out a merge changeset without '
738 raise util.Abort(_('cannot back out a merge changeset without '
809 '--parent'))
739 '--parent'))
810 p = repo.lookup(opts['parent'])
740 p = repo.lookup(opts['parent'])
811 if p not in (p1, p2):
741 if p not in (p1, p2):
812 raise util.Abort(_('%s is not a parent of %s' %
742 raise util.Abort(_('%s is not a parent of %s' %
813 (short(p), short(node))))
743 (short(p), short(node))))
814 parent = p
744 parent = p
815 else:
745 else:
816 if opts['parent']:
746 if opts['parent']:
817 raise util.Abort(_('cannot use --parent on non-merge changeset'))
747 raise util.Abort(_('cannot use --parent on non-merge changeset'))
818 parent = p1
748 parent = p1
819 hg.clean(repo, node, show_stats=False)
749 hg.clean(repo, node, show_stats=False)
820 revert_opts = opts.copy()
750 revert_opts = opts.copy()
821 revert_opts['all'] = True
751 revert_opts['all'] = True
822 revert_opts['rev'] = hex(parent)
752 revert_opts['rev'] = hex(parent)
823 revert(ui, repo, **revert_opts)
753 revert(ui, repo, **revert_opts)
824 commit_opts = opts.copy()
754 commit_opts = opts.copy()
825 commit_opts['addremove'] = False
755 commit_opts['addremove'] = False
826 if not commit_opts['message'] and not commit_opts['logfile']:
756 if not commit_opts['message'] and not commit_opts['logfile']:
827 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
757 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
828 commit_opts['force_editor'] = True
758 commit_opts['force_editor'] = True
829 commit(ui, repo, **commit_opts)
759 commit(ui, repo, **commit_opts)
830 def nice(node):
760 def nice(node):
831 return '%d:%s' % (repo.changelog.rev(node), short(node))
761 return '%d:%s' % (repo.changelog.rev(node), short(node))
832 ui.status(_('changeset %s backs out changeset %s\n') %
762 ui.status(_('changeset %s backs out changeset %s\n') %
833 (nice(repo.changelog.tip()), nice(node)))
763 (nice(repo.changelog.tip()), nice(node)))
834 if op1 != node:
764 if op1 != node:
835 if opts['merge']:
765 if opts['merge']:
836 ui.status(_('merging with changeset %s\n') % nice(op1))
766 ui.status(_('merging with changeset %s\n') % nice(op1))
837 n = _lookup(repo, hex(op1))
767 n = _lookup(repo, hex(op1))
838 hg.merge(repo, n)
768 hg.merge(repo, n)
839 else:
769 else:
840 ui.status(_('the backout changeset is a new head - '
770 ui.status(_('the backout changeset is a new head - '
841 'do not forget to merge\n'))
771 'do not forget to merge\n'))
842 ui.status(_('(use "backout --merge" '
772 ui.status(_('(use "backout --merge" '
843 'if you want to auto-merge)\n'))
773 'if you want to auto-merge)\n'))
844
774
845 def bundle(ui, repo, fname, dest=None, **opts):
775 def bundle(ui, repo, fname, dest=None, **opts):
846 """create a changegroup file
776 """create a changegroup file
847
777
848 Generate a compressed changegroup file collecting all changesets
778 Generate a compressed changegroup file collecting all changesets
849 not found in the other repository.
779 not found in the other repository.
850
780
851 This file can then be transferred using conventional means and
781 This file can then be transferred using conventional means and
852 applied to another repository with the unbundle command. This is
782 applied to another repository with the unbundle command. This is
853 useful when native push and pull are not available or when
783 useful when native push and pull are not available or when
854 exporting an entire repository is undesirable. The standard file
784 exporting an entire repository is undesirable. The standard file
855 extension is ".hg".
785 extension is ".hg".
856
786
857 Unlike import/export, this exactly preserves all changeset
787 Unlike import/export, this exactly preserves all changeset
858 contents including permissions, rename data, and revision history.
788 contents including permissions, rename data, and revision history.
859 """
789 """
860 dest = ui.expandpath(dest or 'default-push', dest or 'default')
790 dest = ui.expandpath(dest or 'default-push', dest or 'default')
861 other = hg.repository(ui, dest)
791 other = hg.repository(ui, dest)
862 o = repo.findoutgoing(other, force=opts['force'])
792 o = repo.findoutgoing(other, force=opts['force'])
863 cg = repo.changegroup(o, 'bundle')
793 cg = repo.changegroup(o, 'bundle')
864 write_bundle(cg, fname)
794 write_bundle(cg, fname)
865
795
866 def cat(ui, repo, file1, *pats, **opts):
796 def cat(ui, repo, file1, *pats, **opts):
867 """output the latest or given revisions of files
797 """output the latest or given revisions of files
868
798
869 Print the specified files as they were at the given revision.
799 Print the specified files as they were at the given revision.
870 If no revision is given then the tip is used.
800 If no revision is given then the tip is used.
871
801
872 Output may be to a file, in which case the name of the file is
802 Output may be to a file, in which case the name of the file is
873 given using a format string. The formatting rules are the same as
803 given using a format string. The formatting rules are the same as
874 for the export command, with the following additions:
804 for the export command, with the following additions:
875
805
876 %s basename of file being printed
806 %s basename of file being printed
877 %d dirname of file being printed, or '.' if in repo root
807 %d dirname of file being printed, or '.' if in repo root
878 %p root-relative path name of file being printed
808 %p root-relative path name of file being printed
879 """
809 """
880 ctx = repo.changectx(opts['rev'] or "-1")
810 ctx = repo.changectx(opts['rev'] or "-1")
881 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
811 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
882 ctx.node()):
812 ctx.node()):
883 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
813 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
884 fp.write(ctx.filectx(abs).data())
814 fp.write(ctx.filectx(abs).data())
885
815
886 def clone(ui, source, dest=None, **opts):
816 def clone(ui, source, dest=None, **opts):
887 """make a copy of an existing repository
817 """make a copy of an existing repository
888
818
889 Create a copy of an existing repository in a new directory.
819 Create a copy of an existing repository in a new directory.
890
820
891 If no destination directory name is specified, it defaults to the
821 If no destination directory name is specified, it defaults to the
892 basename of the source.
822 basename of the source.
893
823
894 The location of the source is added to the new repository's
824 The location of the source is added to the new repository's
895 .hg/hgrc file, as the default to be used for future pulls.
825 .hg/hgrc file, as the default to be used for future pulls.
896
826
897 For efficiency, hardlinks are used for cloning whenever the source
827 For efficiency, hardlinks are used for cloning whenever the source
898 and destination are on the same filesystem (note this applies only
828 and destination are on the same filesystem (note this applies only
899 to the repository data, not to the checked out files). Some
829 to the repository data, not to the checked out files). Some
900 filesystems, such as AFS, implement hardlinking incorrectly, but
830 filesystems, such as AFS, implement hardlinking incorrectly, but
901 do not report errors. In these cases, use the --pull option to
831 do not report errors. In these cases, use the --pull option to
902 avoid hardlinking.
832 avoid hardlinking.
903
833
904 You can safely clone repositories and checked out files using full
834 You can safely clone repositories and checked out files using full
905 hardlinks with
835 hardlinks with
906
836
907 $ cp -al REPO REPOCLONE
837 $ cp -al REPO REPOCLONE
908
838
909 which is the fastest way to clone. However, the operation is not
839 which is the fastest way to clone. However, the operation is not
910 atomic (making sure REPO is not modified during the operation is
840 atomic (making sure REPO is not modified during the operation is
911 up to you) and you have to make sure your editor breaks hardlinks
841 up to you) and you have to make sure your editor breaks hardlinks
912 (Emacs and most Linux Kernel tools do so).
842 (Emacs and most Linux Kernel tools do so).
913
843
914 If you use the -r option to clone up to a specific revision, no
844 If you use the -r option to clone up to a specific revision, no
915 subsequent revisions will be present in the cloned repository.
845 subsequent revisions will be present in the cloned repository.
916 This option implies --pull, even on local repositories.
846 This option implies --pull, even on local repositories.
917
847
918 See pull for valid source format details.
848 See pull for valid source format details.
919
849
920 It is possible to specify an ssh:// URL as the destination, but no
850 It is possible to specify an ssh:// URL as the destination, but no
921 .hg/hgrc will be created on the remote side. Look at the help text
851 .hg/hgrc will be created on the remote side. Look at the help text
922 for the pull command for important details about ssh:// URLs.
852 for the pull command for important details about ssh:// URLs.
923 """
853 """
924 setremoteconfig(ui, opts)
854 setremoteconfig(ui, opts)
925 hg.clone(ui, ui.expandpath(source), dest,
855 hg.clone(ui, ui.expandpath(source), dest,
926 pull=opts['pull'],
856 pull=opts['pull'],
927 stream=opts['uncompressed'],
857 stream=opts['uncompressed'],
928 rev=opts['rev'],
858 rev=opts['rev'],
929 update=not opts['noupdate'])
859 update=not opts['noupdate'])
930
860
931 def commit(ui, repo, *pats, **opts):
861 def commit(ui, repo, *pats, **opts):
932 """commit the specified files or all outstanding changes
862 """commit the specified files or all outstanding changes
933
863
934 Commit changes to the given files into the repository.
864 Commit changes to the given files into the repository.
935
865
936 If a list of files is omitted, all changes reported by "hg status"
866 If a list of files is omitted, all changes reported by "hg status"
937 will be committed.
867 will be committed.
938
868
939 If no commit message is specified, the editor configured in your hgrc
869 If no commit message is specified, the editor configured in your hgrc
940 or in the EDITOR environment variable is started to enter a message.
870 or in the EDITOR environment variable is started to enter a message.
941 """
871 """
942 message = logmessage(opts)
872 message = logmessage(opts)
943
873
944 if opts['addremove']:
874 if opts['addremove']:
945 cmdutil.addremove(repo, pats, opts)
875 cmdutil.addremove(repo, pats, opts)
946 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
876 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
947 if pats:
877 if pats:
948 modified, added, removed = repo.status(files=fns, match=match)[:3]
878 modified, added, removed = repo.status(files=fns, match=match)[:3]
949 files = modified + added + removed
879 files = modified + added + removed
950 else:
880 else:
951 files = []
881 files = []
952 try:
882 try:
953 repo.commit(files, message, opts['user'], opts['date'], match,
883 repo.commit(files, message, opts['user'], opts['date'], match,
954 force_editor=opts.get('force_editor'))
884 force_editor=opts.get('force_editor'))
955 except ValueError, inst:
885 except ValueError, inst:
956 raise util.Abort(str(inst))
886 raise util.Abort(str(inst))
957
887
958 def docopy(ui, repo, pats, opts, wlock):
888 def docopy(ui, repo, pats, opts, wlock):
959 # called with the repo lock held
889 # called with the repo lock held
960 cwd = repo.getcwd()
890 cwd = repo.getcwd()
961 errors = 0
891 errors = 0
962 copied = []
892 copied = []
963 targets = {}
893 targets = {}
964
894
965 def okaytocopy(abs, rel, exact):
895 def okaytocopy(abs, rel, exact):
966 reasons = {'?': _('is not managed'),
896 reasons = {'?': _('is not managed'),
967 'a': _('has been marked for add'),
897 'a': _('has been marked for add'),
968 'r': _('has been marked for remove')}
898 'r': _('has been marked for remove')}
969 state = repo.dirstate.state(abs)
899 state = repo.dirstate.state(abs)
970 reason = reasons.get(state)
900 reason = reasons.get(state)
971 if reason:
901 if reason:
972 if state == 'a':
902 if state == 'a':
973 origsrc = repo.dirstate.copied(abs)
903 origsrc = repo.dirstate.copied(abs)
974 if origsrc is not None:
904 if origsrc is not None:
975 return origsrc
905 return origsrc
976 if exact:
906 if exact:
977 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
907 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
978 else:
908 else:
979 return abs
909 return abs
980
910
981 def copy(origsrc, abssrc, relsrc, target, exact):
911 def copy(origsrc, abssrc, relsrc, target, exact):
982 abstarget = util.canonpath(repo.root, cwd, target)
912 abstarget = util.canonpath(repo.root, cwd, target)
983 reltarget = util.pathto(cwd, abstarget)
913 reltarget = util.pathto(cwd, abstarget)
984 prevsrc = targets.get(abstarget)
914 prevsrc = targets.get(abstarget)
985 if prevsrc is not None:
915 if prevsrc is not None:
986 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
916 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
987 (reltarget, abssrc, prevsrc))
917 (reltarget, abssrc, prevsrc))
988 return
918 return
989 if (not opts['after'] and os.path.exists(reltarget) or
919 if (not opts['after'] and os.path.exists(reltarget) or
990 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
920 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
991 if not opts['force']:
921 if not opts['force']:
992 ui.warn(_('%s: not overwriting - file exists\n') %
922 ui.warn(_('%s: not overwriting - file exists\n') %
993 reltarget)
923 reltarget)
994 return
924 return
995 if not opts['after'] and not opts.get('dry_run'):
925 if not opts['after'] and not opts.get('dry_run'):
996 os.unlink(reltarget)
926 os.unlink(reltarget)
997 if opts['after']:
927 if opts['after']:
998 if not os.path.exists(reltarget):
928 if not os.path.exists(reltarget):
999 return
929 return
1000 else:
930 else:
1001 targetdir = os.path.dirname(reltarget) or '.'
931 targetdir = os.path.dirname(reltarget) or '.'
1002 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
932 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
1003 os.makedirs(targetdir)
933 os.makedirs(targetdir)
1004 try:
934 try:
1005 restore = repo.dirstate.state(abstarget) == 'r'
935 restore = repo.dirstate.state(abstarget) == 'r'
1006 if restore and not opts.get('dry_run'):
936 if restore and not opts.get('dry_run'):
1007 repo.undelete([abstarget], wlock)
937 repo.undelete([abstarget], wlock)
1008 try:
938 try:
1009 if not opts.get('dry_run'):
939 if not opts.get('dry_run'):
1010 shutil.copyfile(relsrc, reltarget)
940 shutil.copyfile(relsrc, reltarget)
1011 shutil.copymode(relsrc, reltarget)
941 shutil.copymode(relsrc, reltarget)
1012 restore = False
942 restore = False
1013 finally:
943 finally:
1014 if restore:
944 if restore:
1015 repo.remove([abstarget], wlock)
945 repo.remove([abstarget], wlock)
1016 except shutil.Error, inst:
946 except shutil.Error, inst:
1017 raise util.Abort(str(inst))
947 raise util.Abort(str(inst))
1018 except IOError, inst:
948 except IOError, inst:
1019 if inst.errno == errno.ENOENT:
949 if inst.errno == errno.ENOENT:
1020 ui.warn(_('%s: deleted in working copy\n') % relsrc)
950 ui.warn(_('%s: deleted in working copy\n') % relsrc)
1021 else:
951 else:
1022 ui.warn(_('%s: cannot copy - %s\n') %
952 ui.warn(_('%s: cannot copy - %s\n') %
1023 (relsrc, inst.strerror))
953 (relsrc, inst.strerror))
1024 errors += 1
954 errors += 1
1025 return
955 return
1026 if ui.verbose or not exact:
956 if ui.verbose or not exact:
1027 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
957 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
1028 targets[abstarget] = abssrc
958 targets[abstarget] = abssrc
1029 if abstarget != origsrc and not opts.get('dry_run'):
959 if abstarget != origsrc and not opts.get('dry_run'):
1030 repo.copy(origsrc, abstarget, wlock)
960 repo.copy(origsrc, abstarget, wlock)
1031 copied.append((abssrc, relsrc, exact))
961 copied.append((abssrc, relsrc, exact))
1032
962
1033 def targetpathfn(pat, dest, srcs):
963 def targetpathfn(pat, dest, srcs):
1034 if os.path.isdir(pat):
964 if os.path.isdir(pat):
1035 abspfx = util.canonpath(repo.root, cwd, pat)
965 abspfx = util.canonpath(repo.root, cwd, pat)
1036 if destdirexists:
966 if destdirexists:
1037 striplen = len(os.path.split(abspfx)[0])
967 striplen = len(os.path.split(abspfx)[0])
1038 else:
968 else:
1039 striplen = len(abspfx)
969 striplen = len(abspfx)
1040 if striplen:
970 if striplen:
1041 striplen += len(os.sep)
971 striplen += len(os.sep)
1042 res = lambda p: os.path.join(dest, p[striplen:])
972 res = lambda p: os.path.join(dest, p[striplen:])
1043 elif destdirexists:
973 elif destdirexists:
1044 res = lambda p: os.path.join(dest, os.path.basename(p))
974 res = lambda p: os.path.join(dest, os.path.basename(p))
1045 else:
975 else:
1046 res = lambda p: dest
976 res = lambda p: dest
1047 return res
977 return res
1048
978
1049 def targetpathafterfn(pat, dest, srcs):
979 def targetpathafterfn(pat, dest, srcs):
1050 if util.patkind(pat, None)[0]:
980 if util.patkind(pat, None)[0]:
1051 # a mercurial pattern
981 # a mercurial pattern
1052 res = lambda p: os.path.join(dest, os.path.basename(p))
982 res = lambda p: os.path.join(dest, os.path.basename(p))
1053 else:
983 else:
1054 abspfx = util.canonpath(repo.root, cwd, pat)
984 abspfx = util.canonpath(repo.root, cwd, pat)
1055 if len(abspfx) < len(srcs[0][0]):
985 if len(abspfx) < len(srcs[0][0]):
1056 # A directory. Either the target path contains the last
986 # A directory. Either the target path contains the last
1057 # component of the source path or it does not.
987 # component of the source path or it does not.
1058 def evalpath(striplen):
988 def evalpath(striplen):
1059 score = 0
989 score = 0
1060 for s in srcs:
990 for s in srcs:
1061 t = os.path.join(dest, s[0][striplen:])
991 t = os.path.join(dest, s[0][striplen:])
1062 if os.path.exists(t):
992 if os.path.exists(t):
1063 score += 1
993 score += 1
1064 return score
994 return score
1065
995
1066 striplen = len(abspfx)
996 striplen = len(abspfx)
1067 if striplen:
997 if striplen:
1068 striplen += len(os.sep)
998 striplen += len(os.sep)
1069 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
999 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
1070 score = evalpath(striplen)
1000 score = evalpath(striplen)
1071 striplen1 = len(os.path.split(abspfx)[0])
1001 striplen1 = len(os.path.split(abspfx)[0])
1072 if striplen1:
1002 if striplen1:
1073 striplen1 += len(os.sep)
1003 striplen1 += len(os.sep)
1074 if evalpath(striplen1) > score:
1004 if evalpath(striplen1) > score:
1075 striplen = striplen1
1005 striplen = striplen1
1076 res = lambda p: os.path.join(dest, p[striplen:])
1006 res = lambda p: os.path.join(dest, p[striplen:])
1077 else:
1007 else:
1078 # a file
1008 # a file
1079 if destdirexists:
1009 if destdirexists:
1080 res = lambda p: os.path.join(dest, os.path.basename(p))
1010 res = lambda p: os.path.join(dest, os.path.basename(p))
1081 else:
1011 else:
1082 res = lambda p: dest
1012 res = lambda p: dest
1083 return res
1013 return res
1084
1014
1085
1015
1086 pats = list(pats)
1016 pats = list(pats)
1087 if not pats:
1017 if not pats:
1088 raise util.Abort(_('no source or destination specified'))
1018 raise util.Abort(_('no source or destination specified'))
1089 if len(pats) == 1:
1019 if len(pats) == 1:
1090 raise util.Abort(_('no destination specified'))
1020 raise util.Abort(_('no destination specified'))
1091 dest = pats.pop()
1021 dest = pats.pop()
1092 destdirexists = os.path.isdir(dest)
1022 destdirexists = os.path.isdir(dest)
1093 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1023 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
1094 raise util.Abort(_('with multiple sources, destination must be an '
1024 raise util.Abort(_('with multiple sources, destination must be an '
1095 'existing directory'))
1025 'existing directory'))
1096 if opts['after']:
1026 if opts['after']:
1097 tfn = targetpathafterfn
1027 tfn = targetpathafterfn
1098 else:
1028 else:
1099 tfn = targetpathfn
1029 tfn = targetpathfn
1100 copylist = []
1030 copylist = []
1101 for pat in pats:
1031 for pat in pats:
1102 srcs = []
1032 srcs = []
1103 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1033 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
1104 origsrc = okaytocopy(abssrc, relsrc, exact)
1034 origsrc = okaytocopy(abssrc, relsrc, exact)
1105 if origsrc:
1035 if origsrc:
1106 srcs.append((origsrc, abssrc, relsrc, exact))
1036 srcs.append((origsrc, abssrc, relsrc, exact))
1107 if not srcs:
1037 if not srcs:
1108 continue
1038 continue
1109 copylist.append((tfn(pat, dest, srcs), srcs))
1039 copylist.append((tfn(pat, dest, srcs), srcs))
1110 if not copylist:
1040 if not copylist:
1111 raise util.Abort(_('no files to copy'))
1041 raise util.Abort(_('no files to copy'))
1112
1042
1113 for targetpath, srcs in copylist:
1043 for targetpath, srcs in copylist:
1114 for origsrc, abssrc, relsrc, exact in srcs:
1044 for origsrc, abssrc, relsrc, exact in srcs:
1115 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1045 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
1116
1046
1117 if errors:
1047 if errors:
1118 ui.warn(_('(consider using --after)\n'))
1048 ui.warn(_('(consider using --after)\n'))
1119 return errors, copied
1049 return errors, copied
1120
1050
1121 def copy(ui, repo, *pats, **opts):
1051 def copy(ui, repo, *pats, **opts):
1122 """mark files as copied for the next commit
1052 """mark files as copied for the next commit
1123
1053
1124 Mark dest as having copies of source files. If dest is a
1054 Mark dest as having copies of source files. If dest is a
1125 directory, copies are put in that directory. If dest is a file,
1055 directory, copies are put in that directory. If dest is a file,
1126 there can only be one source.
1056 there can only be one source.
1127
1057
1128 By default, this command copies the contents of files as they
1058 By default, this command copies the contents of files as they
1129 stand in the working directory. If invoked with --after, the
1059 stand in the working directory. If invoked with --after, the
1130 operation is recorded, but no copying is performed.
1060 operation is recorded, but no copying is performed.
1131
1061
1132 This command takes effect in the next commit.
1062 This command takes effect in the next commit.
1133
1063
1134 NOTE: This command should be treated as experimental. While it
1064 NOTE: This command should be treated as experimental. While it
1135 should properly record copied files, this information is not yet
1065 should properly record copied files, this information is not yet
1136 fully used by merge, nor fully reported by log.
1066 fully used by merge, nor fully reported by log.
1137 """
1067 """
1138 wlock = repo.wlock(0)
1068 wlock = repo.wlock(0)
1139 errs, copied = docopy(ui, repo, pats, opts, wlock)
1069 errs, copied = docopy(ui, repo, pats, opts, wlock)
1140 return errs
1070 return errs
1141
1071
1142 def debugancestor(ui, index, rev1, rev2):
1072 def debugancestor(ui, index, rev1, rev2):
1143 """find the ancestor revision of two revisions in a given index"""
1073 """find the ancestor revision of two revisions in a given index"""
1144 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1074 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1145 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1075 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1146 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1076 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1147
1077
1148 def debugcomplete(ui, cmd='', **opts):
1078 def debugcomplete(ui, cmd='', **opts):
1149 """returns the completion list associated with the given command"""
1079 """returns the completion list associated with the given command"""
1150
1080
1151 if opts['options']:
1081 if opts['options']:
1152 options = []
1082 options = []
1153 otables = [globalopts]
1083 otables = [globalopts]
1154 if cmd:
1084 if cmd:
1155 aliases, entry = findcmd(ui, cmd)
1085 aliases, entry = findcmd(ui, cmd)
1156 otables.append(entry[1])
1086 otables.append(entry[1])
1157 for t in otables:
1087 for t in otables:
1158 for o in t:
1088 for o in t:
1159 if o[0]:
1089 if o[0]:
1160 options.append('-%s' % o[0])
1090 options.append('-%s' % o[0])
1161 options.append('--%s' % o[1])
1091 options.append('--%s' % o[1])
1162 ui.write("%s\n" % "\n".join(options))
1092 ui.write("%s\n" % "\n".join(options))
1163 return
1093 return
1164
1094
1165 clist = findpossible(ui, cmd).keys()
1095 clist = findpossible(ui, cmd).keys()
1166 clist.sort()
1096 clist.sort()
1167 ui.write("%s\n" % "\n".join(clist))
1097 ui.write("%s\n" % "\n".join(clist))
1168
1098
1169 def debugrebuildstate(ui, repo, rev=None):
1099 def debugrebuildstate(ui, repo, rev=None):
1170 """rebuild the dirstate as it would look like for the given revision"""
1100 """rebuild the dirstate as it would look like for the given revision"""
1171 if not rev:
1101 if not rev:
1172 rev = repo.changelog.tip()
1102 rev = repo.changelog.tip()
1173 else:
1103 else:
1174 rev = repo.lookup(rev)
1104 rev = repo.lookup(rev)
1175 change = repo.changelog.read(rev)
1105 change = repo.changelog.read(rev)
1176 n = change[0]
1106 n = change[0]
1177 files = repo.manifest.read(n)
1107 files = repo.manifest.read(n)
1178 wlock = repo.wlock()
1108 wlock = repo.wlock()
1179 repo.dirstate.rebuild(rev, files)
1109 repo.dirstate.rebuild(rev, files)
1180
1110
1181 def debugcheckstate(ui, repo):
1111 def debugcheckstate(ui, repo):
1182 """validate the correctness of the current dirstate"""
1112 """validate the correctness of the current dirstate"""
1183 parent1, parent2 = repo.dirstate.parents()
1113 parent1, parent2 = repo.dirstate.parents()
1184 repo.dirstate.read()
1114 repo.dirstate.read()
1185 dc = repo.dirstate.map
1115 dc = repo.dirstate.map
1186 keys = dc.keys()
1116 keys = dc.keys()
1187 keys.sort()
1117 keys.sort()
1188 m1n = repo.changelog.read(parent1)[0]
1118 m1n = repo.changelog.read(parent1)[0]
1189 m2n = repo.changelog.read(parent2)[0]
1119 m2n = repo.changelog.read(parent2)[0]
1190 m1 = repo.manifest.read(m1n)
1120 m1 = repo.manifest.read(m1n)
1191 m2 = repo.manifest.read(m2n)
1121 m2 = repo.manifest.read(m2n)
1192 errors = 0
1122 errors = 0
1193 for f in dc:
1123 for f in dc:
1194 state = repo.dirstate.state(f)
1124 state = repo.dirstate.state(f)
1195 if state in "nr" and f not in m1:
1125 if state in "nr" and f not in m1:
1196 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1126 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1197 errors += 1
1127 errors += 1
1198 if state in "a" and f in m1:
1128 if state in "a" and f in m1:
1199 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1129 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1200 errors += 1
1130 errors += 1
1201 if state in "m" and f not in m1 and f not in m2:
1131 if state in "m" and f not in m1 and f not in m2:
1202 ui.warn(_("%s in state %s, but not in either manifest\n") %
1132 ui.warn(_("%s in state %s, but not in either manifest\n") %
1203 (f, state))
1133 (f, state))
1204 errors += 1
1134 errors += 1
1205 for f in m1:
1135 for f in m1:
1206 state = repo.dirstate.state(f)
1136 state = repo.dirstate.state(f)
1207 if state not in "nrm":
1137 if state not in "nrm":
1208 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1138 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1209 errors += 1
1139 errors += 1
1210 if errors:
1140 if errors:
1211 error = _(".hg/dirstate inconsistent with current parent's manifest")
1141 error = _(".hg/dirstate inconsistent with current parent's manifest")
1212 raise util.Abort(error)
1142 raise util.Abort(error)
1213
1143
1214 def debugconfig(ui, repo, *values):
1144 def debugconfig(ui, repo, *values):
1215 """show combined config settings from all hgrc files
1145 """show combined config settings from all hgrc files
1216
1146
1217 With no args, print names and values of all config items.
1147 With no args, print names and values of all config items.
1218
1148
1219 With one arg of the form section.name, print just the value of
1149 With one arg of the form section.name, print just the value of
1220 that config item.
1150 that config item.
1221
1151
1222 With multiple args, print names and values of all config items
1152 With multiple args, print names and values of all config items
1223 with matching section names."""
1153 with matching section names."""
1224
1154
1225 if values:
1155 if values:
1226 if len([v for v in values if '.' in v]) > 1:
1156 if len([v for v in values if '.' in v]) > 1:
1227 raise util.Abort(_('only one config item permitted'))
1157 raise util.Abort(_('only one config item permitted'))
1228 for section, name, value in ui.walkconfig():
1158 for section, name, value in ui.walkconfig():
1229 sectname = section + '.' + name
1159 sectname = section + '.' + name
1230 if values:
1160 if values:
1231 for v in values:
1161 for v in values:
1232 if v == section:
1162 if v == section:
1233 ui.write('%s=%s\n' % (sectname, value))
1163 ui.write('%s=%s\n' % (sectname, value))
1234 elif v == sectname:
1164 elif v == sectname:
1235 ui.write(value, '\n')
1165 ui.write(value, '\n')
1236 else:
1166 else:
1237 ui.write('%s=%s\n' % (sectname, value))
1167 ui.write('%s=%s\n' % (sectname, value))
1238
1168
1239 def debugsetparents(ui, repo, rev1, rev2=None):
1169 def debugsetparents(ui, repo, rev1, rev2=None):
1240 """manually set the parents of the current working directory
1170 """manually set the parents of the current working directory
1241
1171
1242 This is useful for writing repository conversion tools, but should
1172 This is useful for writing repository conversion tools, but should
1243 be used with care.
1173 be used with care.
1244 """
1174 """
1245
1175
1246 if not rev2:
1176 if not rev2:
1247 rev2 = hex(nullid)
1177 rev2 = hex(nullid)
1248
1178
1249 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1179 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1250
1180
1251 def debugstate(ui, repo):
1181 def debugstate(ui, repo):
1252 """show the contents of the current dirstate"""
1182 """show the contents of the current dirstate"""
1253 repo.dirstate.read()
1183 repo.dirstate.read()
1254 dc = repo.dirstate.map
1184 dc = repo.dirstate.map
1255 keys = dc.keys()
1185 keys = dc.keys()
1256 keys.sort()
1186 keys.sort()
1257 for file_ in keys:
1187 for file_ in keys:
1258 ui.write("%c %3o %10d %s %s\n"
1188 ui.write("%c %3o %10d %s %s\n"
1259 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1189 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1260 time.strftime("%x %X",
1190 time.strftime("%x %X",
1261 time.localtime(dc[file_][3])), file_))
1191 time.localtime(dc[file_][3])), file_))
1262 for f in repo.dirstate.copies:
1192 for f in repo.dirstate.copies:
1263 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1193 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1264
1194
1265 def debugdata(ui, file_, rev):
1195 def debugdata(ui, file_, rev):
1266 """dump the contents of an data file revision"""
1196 """dump the contents of an data file revision"""
1267 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1197 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1268 file_[:-2] + ".i", file_, 0)
1198 file_[:-2] + ".i", file_, 0)
1269 try:
1199 try:
1270 ui.write(r.revision(r.lookup(rev)))
1200 ui.write(r.revision(r.lookup(rev)))
1271 except KeyError:
1201 except KeyError:
1272 raise util.Abort(_('invalid revision identifier %s') % rev)
1202 raise util.Abort(_('invalid revision identifier %s') % rev)
1273
1203
1274 def debugindex(ui, file_):
1204 def debugindex(ui, file_):
1275 """dump the contents of an index file"""
1205 """dump the contents of an index file"""
1276 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1206 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1277 ui.write(" rev offset length base linkrev" +
1207 ui.write(" rev offset length base linkrev" +
1278 " nodeid p1 p2\n")
1208 " nodeid p1 p2\n")
1279 for i in range(r.count()):
1209 for i in range(r.count()):
1280 node = r.node(i)
1210 node = r.node(i)
1281 pp = r.parents(node)
1211 pp = r.parents(node)
1282 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1212 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1283 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1213 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1284 short(node), short(pp[0]), short(pp[1])))
1214 short(node), short(pp[0]), short(pp[1])))
1285
1215
1286 def debugindexdot(ui, file_):
1216 def debugindexdot(ui, file_):
1287 """dump an index DAG as a .dot file"""
1217 """dump an index DAG as a .dot file"""
1288 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1218 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1289 ui.write("digraph G {\n")
1219 ui.write("digraph G {\n")
1290 for i in range(r.count()):
1220 for i in range(r.count()):
1291 node = r.node(i)
1221 node = r.node(i)
1292 pp = r.parents(node)
1222 pp = r.parents(node)
1293 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1223 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1294 if pp[1] != nullid:
1224 if pp[1] != nullid:
1295 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1225 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1296 ui.write("}\n")
1226 ui.write("}\n")
1297
1227
1298 def debugrename(ui, repo, file, rev=None):
1228 def debugrename(ui, repo, file, rev=None):
1299 """dump rename information"""
1229 """dump rename information"""
1300 r = repo.file(relpath(repo, [file])[0])
1230 r = repo.file(relpath(repo, [file])[0])
1301 if rev:
1231 if rev:
1302 try:
1232 try:
1303 # assume all revision numbers are for changesets
1233 # assume all revision numbers are for changesets
1304 n = repo.lookup(rev)
1234 n = repo.lookup(rev)
1305 change = repo.changelog.read(n)
1235 change = repo.changelog.read(n)
1306 m = repo.manifest.read(change[0])
1236 m = repo.manifest.read(change[0])
1307 n = m[relpath(repo, [file])[0]]
1237 n = m[relpath(repo, [file])[0]]
1308 except (hg.RepoError, KeyError):
1238 except (hg.RepoError, KeyError):
1309 n = r.lookup(rev)
1239 n = r.lookup(rev)
1310 else:
1240 else:
1311 n = r.tip()
1241 n = r.tip()
1312 m = r.renamed(n)
1242 m = r.renamed(n)
1313 if m:
1243 if m:
1314 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1244 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1315 else:
1245 else:
1316 ui.write(_("not renamed\n"))
1246 ui.write(_("not renamed\n"))
1317
1247
1318 def debugwalk(ui, repo, *pats, **opts):
1248 def debugwalk(ui, repo, *pats, **opts):
1319 """show how files match on given patterns"""
1249 """show how files match on given patterns"""
1320 items = list(cmdutil.walk(repo, pats, opts))
1250 items = list(cmdutil.walk(repo, pats, opts))
1321 if not items:
1251 if not items:
1322 return
1252 return
1323 fmt = '%%s %%-%ds %%-%ds %%s' % (
1253 fmt = '%%s %%-%ds %%-%ds %%s' % (
1324 max([len(abs) for (src, abs, rel, exact) in items]),
1254 max([len(abs) for (src, abs, rel, exact) in items]),
1325 max([len(rel) for (src, abs, rel, exact) in items]))
1255 max([len(rel) for (src, abs, rel, exact) in items]))
1326 for src, abs, rel, exact in items:
1256 for src, abs, rel, exact in items:
1327 line = fmt % (src, abs, rel, exact and 'exact' or '')
1257 line = fmt % (src, abs, rel, exact and 'exact' or '')
1328 ui.write("%s\n" % line.rstrip())
1258 ui.write("%s\n" % line.rstrip())
1329
1259
1330 def diff(ui, repo, *pats, **opts):
1260 def diff(ui, repo, *pats, **opts):
1331 """diff repository (or selected files)
1261 """diff repository (or selected files)
1332
1262
1333 Show differences between revisions for the specified files.
1263 Show differences between revisions for the specified files.
1334
1264
1335 Differences between files are shown using the unified diff format.
1265 Differences between files are shown using the unified diff format.
1336
1266
1337 When two revision arguments are given, then changes are shown
1267 When two revision arguments are given, then changes are shown
1338 between those revisions. If only one revision is specified then
1268 between those revisions. If only one revision is specified then
1339 that revision is compared to the working directory, and, when no
1269 that revision is compared to the working directory, and, when no
1340 revisions are specified, the working directory files are compared
1270 revisions are specified, the working directory files are compared
1341 to its parent.
1271 to its parent.
1342
1272
1343 Without the -a option, diff will avoid generating diffs of files
1273 Without the -a option, diff will avoid generating diffs of files
1344 it detects as binary. With -a, diff will generate a diff anyway,
1274 it detects as binary. With -a, diff will generate a diff anyway,
1345 probably with undesirable results.
1275 probably with undesirable results.
1346 """
1276 """
1347 node1, node2 = revpair(ui, repo, opts['rev'])
1277 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
1348
1278
1349 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1279 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1350
1280
1351 patch.diff(repo, node1, node2, fns, match=matchfn,
1281 patch.diff(repo, node1, node2, fns, match=matchfn,
1352 opts=patch.diffopts(ui, opts))
1282 opts=patch.diffopts(ui, opts))
1353
1283
1354 def export(ui, repo, *changesets, **opts):
1284 def export(ui, repo, *changesets, **opts):
1355 """dump the header and diffs for one or more changesets
1285 """dump the header and diffs for one or more changesets
1356
1286
1357 Print the changeset header and diffs for one or more revisions.
1287 Print the changeset header and diffs for one or more revisions.
1358
1288
1359 The information shown in the changeset header is: author,
1289 The information shown in the changeset header is: author,
1360 changeset hash, parent and commit comment.
1290 changeset hash, parent and commit comment.
1361
1291
1362 Output may be to a file, in which case the name of the file is
1292 Output may be to a file, in which case the name of the file is
1363 given using a format string. The formatting rules are as follows:
1293 given using a format string. The formatting rules are as follows:
1364
1294
1365 %% literal "%" character
1295 %% literal "%" character
1366 %H changeset hash (40 bytes of hexadecimal)
1296 %H changeset hash (40 bytes of hexadecimal)
1367 %N number of patches being generated
1297 %N number of patches being generated
1368 %R changeset revision number
1298 %R changeset revision number
1369 %b basename of the exporting repository
1299 %b basename of the exporting repository
1370 %h short-form changeset hash (12 bytes of hexadecimal)
1300 %h short-form changeset hash (12 bytes of hexadecimal)
1371 %n zero-padded sequence number, starting at 1
1301 %n zero-padded sequence number, starting at 1
1372 %r zero-padded changeset revision number
1302 %r zero-padded changeset revision number
1373
1303
1374 Without the -a option, export will avoid generating diffs of files
1304 Without the -a option, export will avoid generating diffs of files
1375 it detects as binary. With -a, export will generate a diff anyway,
1305 it detects as binary. With -a, export will generate a diff anyway,
1376 probably with undesirable results.
1306 probably with undesirable results.
1377
1307
1378 With the --switch-parent option, the diff will be against the second
1308 With the --switch-parent option, the diff will be against the second
1379 parent. It can be useful to review a merge.
1309 parent. It can be useful to review a merge.
1380 """
1310 """
1381 if not changesets:
1311 if not changesets:
1382 raise util.Abort(_("export requires at least one changeset"))
1312 raise util.Abort(_("export requires at least one changeset"))
1383 revs = list(revrange(ui, repo, changesets))
1313 revs = list(cmdutil.revrange(ui, repo, changesets))
1384 if len(revs) > 1:
1314 if len(revs) > 1:
1385 ui.note(_('exporting patches:\n'))
1315 ui.note(_('exporting patches:\n'))
1386 else:
1316 else:
1387 ui.note(_('exporting patch:\n'))
1317 ui.note(_('exporting patch:\n'))
1388 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1318 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1389 switch_parent=opts['switch_parent'],
1319 switch_parent=opts['switch_parent'],
1390 opts=patch.diffopts(ui, opts))
1320 opts=patch.diffopts(ui, opts))
1391
1321
1392 def forget(ui, repo, *pats, **opts):
1322 def forget(ui, repo, *pats, **opts):
1393 """don't add the specified files on the next commit (DEPRECATED)
1323 """don't add the specified files on the next commit (DEPRECATED)
1394
1324
1395 (DEPRECATED)
1325 (DEPRECATED)
1396 Undo an 'hg add' scheduled for the next commit.
1326 Undo an 'hg add' scheduled for the next commit.
1397
1327
1398 This command is now deprecated and will be removed in a future
1328 This command is now deprecated and will be removed in a future
1399 release. Please use revert instead.
1329 release. Please use revert instead.
1400 """
1330 """
1401 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1331 ui.warn(_("(the forget command is deprecated; use revert instead)\n"))
1402 forget = []
1332 forget = []
1403 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1333 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
1404 if repo.dirstate.state(abs) == 'a':
1334 if repo.dirstate.state(abs) == 'a':
1405 forget.append(abs)
1335 forget.append(abs)
1406 if ui.verbose or not exact:
1336 if ui.verbose or not exact:
1407 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1337 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1408 repo.forget(forget)
1338 repo.forget(forget)
1409
1339
1410 def grep(ui, repo, pattern, *pats, **opts):
1340 def grep(ui, repo, pattern, *pats, **opts):
1411 """search for a pattern in specified files and revisions
1341 """search for a pattern in specified files and revisions
1412
1342
1413 Search revisions of files for a regular expression.
1343 Search revisions of files for a regular expression.
1414
1344
1415 This command behaves differently than Unix grep. It only accepts
1345 This command behaves differently than Unix grep. It only accepts
1416 Python/Perl regexps. It searches repository history, not the
1346 Python/Perl regexps. It searches repository history, not the
1417 working directory. It always prints the revision number in which
1347 working directory. It always prints the revision number in which
1418 a match appears.
1348 a match appears.
1419
1349
1420 By default, grep only prints output for the first revision of a
1350 By default, grep only prints output for the first revision of a
1421 file in which it finds a match. To get it to print every revision
1351 file in which it finds a match. To get it to print every revision
1422 that contains a change in match status ("-" for a match that
1352 that contains a change in match status ("-" for a match that
1423 becomes a non-match, or "+" for a non-match that becomes a match),
1353 becomes a non-match, or "+" for a non-match that becomes a match),
1424 use the --all flag.
1354 use the --all flag.
1425 """
1355 """
1426 reflags = 0
1356 reflags = 0
1427 if opts['ignore_case']:
1357 if opts['ignore_case']:
1428 reflags |= re.I
1358 reflags |= re.I
1429 regexp = re.compile(pattern, reflags)
1359 regexp = re.compile(pattern, reflags)
1430 sep, eol = ':', '\n'
1360 sep, eol = ':', '\n'
1431 if opts['print0']:
1361 if opts['print0']:
1432 sep = eol = '\0'
1362 sep = eol = '\0'
1433
1363
1434 fcache = {}
1364 fcache = {}
1435 def getfile(fn):
1365 def getfile(fn):
1436 if fn not in fcache:
1366 if fn not in fcache:
1437 fcache[fn] = repo.file(fn)
1367 fcache[fn] = repo.file(fn)
1438 return fcache[fn]
1368 return fcache[fn]
1439
1369
1440 def matchlines(body):
1370 def matchlines(body):
1441 begin = 0
1371 begin = 0
1442 linenum = 0
1372 linenum = 0
1443 while True:
1373 while True:
1444 match = regexp.search(body, begin)
1374 match = regexp.search(body, begin)
1445 if not match:
1375 if not match:
1446 break
1376 break
1447 mstart, mend = match.span()
1377 mstart, mend = match.span()
1448 linenum += body.count('\n', begin, mstart) + 1
1378 linenum += body.count('\n', begin, mstart) + 1
1449 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1379 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1450 lend = body.find('\n', mend)
1380 lend = body.find('\n', mend)
1451 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1381 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1452 begin = lend + 1
1382 begin = lend + 1
1453
1383
1454 class linestate(object):
1384 class linestate(object):
1455 def __init__(self, line, linenum, colstart, colend):
1385 def __init__(self, line, linenum, colstart, colend):
1456 self.line = line
1386 self.line = line
1457 self.linenum = linenum
1387 self.linenum = linenum
1458 self.colstart = colstart
1388 self.colstart = colstart
1459 self.colend = colend
1389 self.colend = colend
1460
1390
1461 def __eq__(self, other):
1391 def __eq__(self, other):
1462 return self.line == other.line
1392 return self.line == other.line
1463
1393
1464 matches = {}
1394 matches = {}
1465 copies = {}
1395 copies = {}
1466 def grepbody(fn, rev, body):
1396 def grepbody(fn, rev, body):
1467 matches[rev].setdefault(fn, [])
1397 matches[rev].setdefault(fn, [])
1468 m = matches[rev][fn]
1398 m = matches[rev][fn]
1469 for lnum, cstart, cend, line in matchlines(body):
1399 for lnum, cstart, cend, line in matchlines(body):
1470 s = linestate(line, lnum, cstart, cend)
1400 s = linestate(line, lnum, cstart, cend)
1471 m.append(s)
1401 m.append(s)
1472
1402
1473 def difflinestates(a, b):
1403 def difflinestates(a, b):
1474 sm = difflib.SequenceMatcher(None, a, b)
1404 sm = difflib.SequenceMatcher(None, a, b)
1475 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1405 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1476 if tag == 'insert':
1406 if tag == 'insert':
1477 for i in range(blo, bhi):
1407 for i in range(blo, bhi):
1478 yield ('+', b[i])
1408 yield ('+', b[i])
1479 elif tag == 'delete':
1409 elif tag == 'delete':
1480 for i in range(alo, ahi):
1410 for i in range(alo, ahi):
1481 yield ('-', a[i])
1411 yield ('-', a[i])
1482 elif tag == 'replace':
1412 elif tag == 'replace':
1483 for i in range(alo, ahi):
1413 for i in range(alo, ahi):
1484 yield ('-', a[i])
1414 yield ('-', a[i])
1485 for i in range(blo, bhi):
1415 for i in range(blo, bhi):
1486 yield ('+', b[i])
1416 yield ('+', b[i])
1487
1417
1488 prev = {}
1418 prev = {}
1489 ucache = {}
1419 ucache = {}
1490 def display(fn, rev, states, prevstates):
1420 def display(fn, rev, states, prevstates):
1491 counts = {'-': 0, '+': 0}
1421 counts = {'-': 0, '+': 0}
1492 filerevmatches = {}
1422 filerevmatches = {}
1493 if incrementing or not opts['all']:
1423 if incrementing or not opts['all']:
1494 a, b = prevstates, states
1424 a, b = prevstates, states
1495 else:
1425 else:
1496 a, b = states, prevstates
1426 a, b = states, prevstates
1497 for change, l in difflinestates(a, b):
1427 for change, l in difflinestates(a, b):
1498 if incrementing or not opts['all']:
1428 if incrementing or not opts['all']:
1499 r = rev
1429 r = rev
1500 else:
1430 else:
1501 r = prev[fn]
1431 r = prev[fn]
1502 cols = [fn, str(r)]
1432 cols = [fn, str(r)]
1503 if opts['line_number']:
1433 if opts['line_number']:
1504 cols.append(str(l.linenum))
1434 cols.append(str(l.linenum))
1505 if opts['all']:
1435 if opts['all']:
1506 cols.append(change)
1436 cols.append(change)
1507 if opts['user']:
1437 if opts['user']:
1508 cols.append(trimuser(ui, getchange(r)[1], rev,
1438 cols.append(trimuser(ui, getchange(r)[1], rev,
1509 ucache))
1439 ucache))
1510 if opts['files_with_matches']:
1440 if opts['files_with_matches']:
1511 c = (fn, rev)
1441 c = (fn, rev)
1512 if c in filerevmatches:
1442 if c in filerevmatches:
1513 continue
1443 continue
1514 filerevmatches[c] = 1
1444 filerevmatches[c] = 1
1515 else:
1445 else:
1516 cols.append(l.line)
1446 cols.append(l.line)
1517 ui.write(sep.join(cols), eol)
1447 ui.write(sep.join(cols), eol)
1518 counts[change] += 1
1448 counts[change] += 1
1519 return counts['+'], counts['-']
1449 return counts['+'], counts['-']
1520
1450
1521 fstate = {}
1451 fstate = {}
1522 skip = {}
1452 skip = {}
1523 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1453 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1524 count = 0
1454 count = 0
1525 incrementing = False
1455 incrementing = False
1526 follow = opts.get('follow')
1456 follow = opts.get('follow')
1527 for st, rev, fns in changeiter:
1457 for st, rev, fns in changeiter:
1528 if st == 'window':
1458 if st == 'window':
1529 incrementing = rev
1459 incrementing = rev
1530 matches.clear()
1460 matches.clear()
1531 elif st == 'add':
1461 elif st == 'add':
1532 change = repo.changelog.read(repo.lookup(str(rev)))
1462 change = repo.changelog.read(repo.lookup(str(rev)))
1533 mf = repo.manifest.read(change[0])
1463 mf = repo.manifest.read(change[0])
1534 matches[rev] = {}
1464 matches[rev] = {}
1535 for fn in fns:
1465 for fn in fns:
1536 if fn in skip:
1466 if fn in skip:
1537 continue
1467 continue
1538 fstate.setdefault(fn, {})
1468 fstate.setdefault(fn, {})
1539 try:
1469 try:
1540 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1470 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1541 if follow:
1471 if follow:
1542 copied = getfile(fn).renamed(mf[fn])
1472 copied = getfile(fn).renamed(mf[fn])
1543 if copied:
1473 if copied:
1544 copies.setdefault(rev, {})[fn] = copied[0]
1474 copies.setdefault(rev, {})[fn] = copied[0]
1545 except KeyError:
1475 except KeyError:
1546 pass
1476 pass
1547 elif st == 'iter':
1477 elif st == 'iter':
1548 states = matches[rev].items()
1478 states = matches[rev].items()
1549 states.sort()
1479 states.sort()
1550 for fn, m in states:
1480 for fn, m in states:
1551 copy = copies.get(rev, {}).get(fn)
1481 copy = copies.get(rev, {}).get(fn)
1552 if fn in skip:
1482 if fn in skip:
1553 if copy:
1483 if copy:
1554 skip[copy] = True
1484 skip[copy] = True
1555 continue
1485 continue
1556 if incrementing or not opts['all'] or fstate[fn]:
1486 if incrementing or not opts['all'] or fstate[fn]:
1557 pos, neg = display(fn, rev, m, fstate[fn])
1487 pos, neg = display(fn, rev, m, fstate[fn])
1558 count += pos + neg
1488 count += pos + neg
1559 if pos and not opts['all']:
1489 if pos and not opts['all']:
1560 skip[fn] = True
1490 skip[fn] = True
1561 if copy:
1491 if copy:
1562 skip[copy] = True
1492 skip[copy] = True
1563 fstate[fn] = m
1493 fstate[fn] = m
1564 if copy:
1494 if copy:
1565 fstate[copy] = m
1495 fstate[copy] = m
1566 prev[fn] = rev
1496 prev[fn] = rev
1567
1497
1568 if not incrementing:
1498 if not incrementing:
1569 fstate = fstate.items()
1499 fstate = fstate.items()
1570 fstate.sort()
1500 fstate.sort()
1571 for fn, state in fstate:
1501 for fn, state in fstate:
1572 if fn in skip:
1502 if fn in skip:
1573 continue
1503 continue
1574 if fn not in copies.get(prev[fn], {}):
1504 if fn not in copies.get(prev[fn], {}):
1575 display(fn, rev, {}, state)
1505 display(fn, rev, {}, state)
1576 return (count == 0 and 1) or 0
1506 return (count == 0 and 1) or 0
1577
1507
1578 def heads(ui, repo, **opts):
1508 def heads(ui, repo, **opts):
1579 """show current repository heads
1509 """show current repository heads
1580
1510
1581 Show all repository head changesets.
1511 Show all repository head changesets.
1582
1512
1583 Repository "heads" are changesets that don't have children
1513 Repository "heads" are changesets that don't have children
1584 changesets. They are where development generally takes place and
1514 changesets. They are where development generally takes place and
1585 are the usual targets for update and merge operations.
1515 are the usual targets for update and merge operations.
1586 """
1516 """
1587 if opts['rev']:
1517 if opts['rev']:
1588 heads = repo.heads(repo.lookup(opts['rev']))
1518 heads = repo.heads(repo.lookup(opts['rev']))
1589 else:
1519 else:
1590 heads = repo.heads()
1520 heads = repo.heads()
1591 br = None
1521 br = None
1592 if opts['branches']:
1522 if opts['branches']:
1593 br = repo.branchlookup(heads)
1523 br = repo.branchlookup(heads)
1594 displayer = show_changeset(ui, repo, opts)
1524 displayer = show_changeset(ui, repo, opts)
1595 for n in heads:
1525 for n in heads:
1596 displayer.show(changenode=n, brinfo=br)
1526 displayer.show(changenode=n, brinfo=br)
1597
1527
1598 def identify(ui, repo):
1528 def identify(ui, repo):
1599 """print information about the working copy
1529 """print information about the working copy
1600
1530
1601 Print a short summary of the current state of the repo.
1531 Print a short summary of the current state of the repo.
1602
1532
1603 This summary identifies the repository state using one or two parent
1533 This summary identifies the repository state using one or two parent
1604 hash identifiers, followed by a "+" if there are uncommitted changes
1534 hash identifiers, followed by a "+" if there are uncommitted changes
1605 in the working directory, followed by a list of tags for this revision.
1535 in the working directory, followed by a list of tags for this revision.
1606 """
1536 """
1607 parents = [p for p in repo.dirstate.parents() if p != nullid]
1537 parents = [p for p in repo.dirstate.parents() if p != nullid]
1608 if not parents:
1538 if not parents:
1609 ui.write(_("unknown\n"))
1539 ui.write(_("unknown\n"))
1610 return
1540 return
1611
1541
1612 hexfunc = ui.debugflag and hex or short
1542 hexfunc = ui.debugflag and hex or short
1613 modified, added, removed, deleted = repo.status()[:4]
1543 modified, added, removed, deleted = repo.status()[:4]
1614 output = ["%s%s" %
1544 output = ["%s%s" %
1615 ('+'.join([hexfunc(parent) for parent in parents]),
1545 ('+'.join([hexfunc(parent) for parent in parents]),
1616 (modified or added or removed or deleted) and "+" or "")]
1546 (modified or added or removed or deleted) and "+" or "")]
1617
1547
1618 if not ui.quiet:
1548 if not ui.quiet:
1619 # multiple tags for a single parent separated by '/'
1549 # multiple tags for a single parent separated by '/'
1620 parenttags = ['/'.join(tags)
1550 parenttags = ['/'.join(tags)
1621 for tags in map(repo.nodetags, parents) if tags]
1551 for tags in map(repo.nodetags, parents) if tags]
1622 # tags for multiple parents separated by ' + '
1552 # tags for multiple parents separated by ' + '
1623 if parenttags:
1553 if parenttags:
1624 output.append(' + '.join(parenttags))
1554 output.append(' + '.join(parenttags))
1625
1555
1626 ui.write("%s\n" % ' '.join(output))
1556 ui.write("%s\n" % ' '.join(output))
1627
1557
1628 def import_(ui, repo, patch1, *patches, **opts):
1558 def import_(ui, repo, patch1, *patches, **opts):
1629 """import an ordered set of patches
1559 """import an ordered set of patches
1630
1560
1631 Import a list of patches and commit them individually.
1561 Import a list of patches and commit them individually.
1632
1562
1633 If there are outstanding changes in the working directory, import
1563 If there are outstanding changes in the working directory, import
1634 will abort unless given the -f flag.
1564 will abort unless given the -f flag.
1635
1565
1636 You can import a patch straight from a mail message. Even patches
1566 You can import a patch straight from a mail message. Even patches
1637 as attachments work (body part must be type text/plain or
1567 as attachments work (body part must be type text/plain or
1638 text/x-patch to be used). From and Subject headers of email
1568 text/x-patch to be used). From and Subject headers of email
1639 message are used as default committer and commit message. All
1569 message are used as default committer and commit message. All
1640 text/plain body parts before first diff are added to commit
1570 text/plain body parts before first diff are added to commit
1641 message.
1571 message.
1642
1572
1643 If imported patch was generated by hg export, user and description
1573 If imported patch was generated by hg export, user and description
1644 from patch override values from message headers and body. Values
1574 from patch override values from message headers and body. Values
1645 given on command line with -m and -u override these.
1575 given on command line with -m and -u override these.
1646
1576
1647 To read a patch from standard input, use patch name "-".
1577 To read a patch from standard input, use patch name "-".
1648 """
1578 """
1649 patches = (patch1,) + patches
1579 patches = (patch1,) + patches
1650
1580
1651 if not opts['force']:
1581 if not opts['force']:
1652 bail_if_changed(repo)
1582 bail_if_changed(repo)
1653
1583
1654 d = opts["base"]
1584 d = opts["base"]
1655 strip = opts["strip"]
1585 strip = opts["strip"]
1656
1586
1657 wlock = repo.wlock()
1587 wlock = repo.wlock()
1658 lock = repo.lock()
1588 lock = repo.lock()
1659
1589
1660 for p in patches:
1590 for p in patches:
1661 pf = os.path.join(d, p)
1591 pf = os.path.join(d, p)
1662
1592
1663 if pf == '-':
1593 if pf == '-':
1664 ui.status(_("applying patch from stdin\n"))
1594 ui.status(_("applying patch from stdin\n"))
1665 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1595 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1666 else:
1596 else:
1667 ui.status(_("applying %s\n") % p)
1597 ui.status(_("applying %s\n") % p)
1668 tmpname, message, user, date = patch.extract(ui, file(pf))
1598 tmpname, message, user, date = patch.extract(ui, file(pf))
1669
1599
1670 if tmpname is None:
1600 if tmpname is None:
1671 raise util.Abort(_('no diffs found'))
1601 raise util.Abort(_('no diffs found'))
1672
1602
1673 try:
1603 try:
1674 if opts['message']:
1604 if opts['message']:
1675 # pickup the cmdline msg
1605 # pickup the cmdline msg
1676 message = opts['message']
1606 message = opts['message']
1677 elif message:
1607 elif message:
1678 # pickup the patch msg
1608 # pickup the patch msg
1679 message = message.strip()
1609 message = message.strip()
1680 else:
1610 else:
1681 # launch the editor
1611 # launch the editor
1682 message = None
1612 message = None
1683 ui.debug(_('message:\n%s\n') % message)
1613 ui.debug(_('message:\n%s\n') % message)
1684
1614
1685 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1615 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root)
1686 files = patch.updatedir(ui, repo, files, wlock=wlock)
1616 files = patch.updatedir(ui, repo, files, wlock=wlock)
1687 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1617 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1688 finally:
1618 finally:
1689 os.unlink(tmpname)
1619 os.unlink(tmpname)
1690
1620
1691 def incoming(ui, repo, source="default", **opts):
1621 def incoming(ui, repo, source="default", **opts):
1692 """show new changesets found in source
1622 """show new changesets found in source
1693
1623
1694 Show new changesets found in the specified path/URL or the default
1624 Show new changesets found in the specified path/URL or the default
1695 pull location. These are the changesets that would be pulled if a pull
1625 pull location. These are the changesets that would be pulled if a pull
1696 was requested.
1626 was requested.
1697
1627
1698 For remote repository, using --bundle avoids downloading the changesets
1628 For remote repository, using --bundle avoids downloading the changesets
1699 twice if the incoming is followed by a pull.
1629 twice if the incoming is followed by a pull.
1700
1630
1701 See pull for valid source format details.
1631 See pull for valid source format details.
1702 """
1632 """
1703 source = ui.expandpath(source)
1633 source = ui.expandpath(source)
1704 setremoteconfig(ui, opts)
1634 setremoteconfig(ui, opts)
1705
1635
1706 other = hg.repository(ui, source)
1636 other = hg.repository(ui, source)
1707 incoming = repo.findincoming(other, force=opts["force"])
1637 incoming = repo.findincoming(other, force=opts["force"])
1708 if not incoming:
1638 if not incoming:
1709 ui.status(_("no changes found\n"))
1639 ui.status(_("no changes found\n"))
1710 return
1640 return
1711
1641
1712 cleanup = None
1642 cleanup = None
1713 try:
1643 try:
1714 fname = opts["bundle"]
1644 fname = opts["bundle"]
1715 if fname or not other.local():
1645 if fname or not other.local():
1716 # create a bundle (uncompressed if other repo is not local)
1646 # create a bundle (uncompressed if other repo is not local)
1717 cg = other.changegroup(incoming, "incoming")
1647 cg = other.changegroup(incoming, "incoming")
1718 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1648 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1719 # keep written bundle?
1649 # keep written bundle?
1720 if opts["bundle"]:
1650 if opts["bundle"]:
1721 cleanup = None
1651 cleanup = None
1722 if not other.local():
1652 if not other.local():
1723 # use the created uncompressed bundlerepo
1653 # use the created uncompressed bundlerepo
1724 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1654 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1725
1655
1726 revs = None
1656 revs = None
1727 if opts['rev']:
1657 if opts['rev']:
1728 revs = [other.lookup(rev) for rev in opts['rev']]
1658 revs = [other.lookup(rev) for rev in opts['rev']]
1729 o = other.changelog.nodesbetween(incoming, revs)[0]
1659 o = other.changelog.nodesbetween(incoming, revs)[0]
1730 if opts['newest_first']:
1660 if opts['newest_first']:
1731 o.reverse()
1661 o.reverse()
1732 displayer = show_changeset(ui, other, opts)
1662 displayer = show_changeset(ui, other, opts)
1733 for n in o:
1663 for n in o:
1734 parents = [p for p in other.changelog.parents(n) if p != nullid]
1664 parents = [p for p in other.changelog.parents(n) if p != nullid]
1735 if opts['no_merges'] and len(parents) == 2:
1665 if opts['no_merges'] and len(parents) == 2:
1736 continue
1666 continue
1737 displayer.show(changenode=n)
1667 displayer.show(changenode=n)
1738 if opts['patch']:
1668 if opts['patch']:
1739 prev = (parents and parents[0]) or nullid
1669 prev = (parents and parents[0]) or nullid
1740 patch.diff(other, prev, n, fp=repo.ui)
1670 patch.diff(other, prev, n, fp=repo.ui)
1741 ui.write("\n")
1671 ui.write("\n")
1742 finally:
1672 finally:
1743 if hasattr(other, 'close'):
1673 if hasattr(other, 'close'):
1744 other.close()
1674 other.close()
1745 if cleanup:
1675 if cleanup:
1746 os.unlink(cleanup)
1676 os.unlink(cleanup)
1747
1677
1748 def init(ui, dest=".", **opts):
1678 def init(ui, dest=".", **opts):
1749 """create a new repository in the given directory
1679 """create a new repository in the given directory
1750
1680
1751 Initialize a new repository in the given directory. If the given
1681 Initialize a new repository in the given directory. If the given
1752 directory does not exist, it is created.
1682 directory does not exist, it is created.
1753
1683
1754 If no directory is given, the current directory is used.
1684 If no directory is given, the current directory is used.
1755
1685
1756 It is possible to specify an ssh:// URL as the destination.
1686 It is possible to specify an ssh:// URL as the destination.
1757 Look at the help text for the pull command for important details
1687 Look at the help text for the pull command for important details
1758 about ssh:// URLs.
1688 about ssh:// URLs.
1759 """
1689 """
1760 setremoteconfig(ui, opts)
1690 setremoteconfig(ui, opts)
1761 hg.repository(ui, dest, create=1)
1691 hg.repository(ui, dest, create=1)
1762
1692
1763 def locate(ui, repo, *pats, **opts):
1693 def locate(ui, repo, *pats, **opts):
1764 """locate files matching specific patterns
1694 """locate files matching specific patterns
1765
1695
1766 Print all files under Mercurial control whose names match the
1696 Print all files under Mercurial control whose names match the
1767 given patterns.
1697 given patterns.
1768
1698
1769 This command searches the current directory and its
1699 This command searches the current directory and its
1770 subdirectories. To search an entire repository, move to the root
1700 subdirectories. To search an entire repository, move to the root
1771 of the repository.
1701 of the repository.
1772
1702
1773 If no patterns are given to match, this command prints all file
1703 If no patterns are given to match, this command prints all file
1774 names.
1704 names.
1775
1705
1776 If you want to feed the output of this command into the "xargs"
1706 If you want to feed the output of this command into the "xargs"
1777 command, use the "-0" option to both this command and "xargs".
1707 command, use the "-0" option to both this command and "xargs".
1778 This will avoid the problem of "xargs" treating single filenames
1708 This will avoid the problem of "xargs" treating single filenames
1779 that contain white space as multiple filenames.
1709 that contain white space as multiple filenames.
1780 """
1710 """
1781 end = opts['print0'] and '\0' or '\n'
1711 end = opts['print0'] and '\0' or '\n'
1782 rev = opts['rev']
1712 rev = opts['rev']
1783 if rev:
1713 if rev:
1784 node = repo.lookup(rev)
1714 node = repo.lookup(rev)
1785 else:
1715 else:
1786 node = None
1716 node = None
1787
1717
1788 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1718 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1789 head='(?:.*/|)'):
1719 head='(?:.*/|)'):
1790 if not node and repo.dirstate.state(abs) == '?':
1720 if not node and repo.dirstate.state(abs) == '?':
1791 continue
1721 continue
1792 if opts['fullpath']:
1722 if opts['fullpath']:
1793 ui.write(os.path.join(repo.root, abs), end)
1723 ui.write(os.path.join(repo.root, abs), end)
1794 else:
1724 else:
1795 ui.write(((pats and rel) or abs), end)
1725 ui.write(((pats and rel) or abs), end)
1796
1726
1797 def log(ui, repo, *pats, **opts):
1727 def log(ui, repo, *pats, **opts):
1798 """show revision history of entire repository or files
1728 """show revision history of entire repository or files
1799
1729
1800 Print the revision history of the specified files or the entire
1730 Print the revision history of the specified files or the entire
1801 project.
1731 project.
1802
1732
1803 File history is shown without following rename or copy history of
1733 File history is shown without following rename or copy history of
1804 files. Use -f/--follow with a file name to follow history across
1734 files. Use -f/--follow with a file name to follow history across
1805 renames and copies. --follow without a file name will only show
1735 renames and copies. --follow without a file name will only show
1806 ancestors or descendants of the starting revision. --follow-first
1736 ancestors or descendants of the starting revision. --follow-first
1807 only follows the first parent of merge revisions.
1737 only follows the first parent of merge revisions.
1808
1738
1809 If no revision range is specified, the default is tip:0 unless
1739 If no revision range is specified, the default is tip:0 unless
1810 --follow is set, in which case the working directory parent is
1740 --follow is set, in which case the working directory parent is
1811 used as the starting revision.
1741 used as the starting revision.
1812
1742
1813 By default this command outputs: changeset id and hash, tags,
1743 By default this command outputs: changeset id and hash, tags,
1814 non-trivial parents, user, date and time, and a summary for each
1744 non-trivial parents, user, date and time, and a summary for each
1815 commit. When the -v/--verbose switch is used, the list of changed
1745 commit. When the -v/--verbose switch is used, the list of changed
1816 files and full commit message is shown.
1746 files and full commit message is shown.
1817 """
1747 """
1818 class dui(object):
1748 class dui(object):
1819 # Implement and delegate some ui protocol. Save hunks of
1749 # Implement and delegate some ui protocol. Save hunks of
1820 # output for later display in the desired order.
1750 # output for later display in the desired order.
1821 def __init__(self, ui):
1751 def __init__(self, ui):
1822 self.ui = ui
1752 self.ui = ui
1823 self.hunk = {}
1753 self.hunk = {}
1824 self.header = {}
1754 self.header = {}
1825 def bump(self, rev):
1755 def bump(self, rev):
1826 self.rev = rev
1756 self.rev = rev
1827 self.hunk[rev] = []
1757 self.hunk[rev] = []
1828 self.header[rev] = []
1758 self.header[rev] = []
1829 def note(self, *args):
1759 def note(self, *args):
1830 if self.verbose:
1760 if self.verbose:
1831 self.write(*args)
1761 self.write(*args)
1832 def status(self, *args):
1762 def status(self, *args):
1833 if not self.quiet:
1763 if not self.quiet:
1834 self.write(*args)
1764 self.write(*args)
1835 def write(self, *args):
1765 def write(self, *args):
1836 self.hunk[self.rev].append(args)
1766 self.hunk[self.rev].append(args)
1837 def write_header(self, *args):
1767 def write_header(self, *args):
1838 self.header[self.rev].append(args)
1768 self.header[self.rev].append(args)
1839 def debug(self, *args):
1769 def debug(self, *args):
1840 if self.debugflag:
1770 if self.debugflag:
1841 self.write(*args)
1771 self.write(*args)
1842 def __getattr__(self, key):
1772 def __getattr__(self, key):
1843 return getattr(self.ui, key)
1773 return getattr(self.ui, key)
1844
1774
1845 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1775 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1846
1776
1847 if opts['limit']:
1777 if opts['limit']:
1848 try:
1778 try:
1849 limit = int(opts['limit'])
1779 limit = int(opts['limit'])
1850 except ValueError:
1780 except ValueError:
1851 raise util.Abort(_('limit must be a positive integer'))
1781 raise util.Abort(_('limit must be a positive integer'))
1852 if limit <= 0: raise util.Abort(_('limit must be positive'))
1782 if limit <= 0: raise util.Abort(_('limit must be positive'))
1853 else:
1783 else:
1854 limit = sys.maxint
1784 limit = sys.maxint
1855 count = 0
1785 count = 0
1856
1786
1857 displayer = show_changeset(ui, repo, opts)
1787 displayer = show_changeset(ui, repo, opts)
1858 for st, rev, fns in changeiter:
1788 for st, rev, fns in changeiter:
1859 if st == 'window':
1789 if st == 'window':
1860 du = dui(ui)
1790 du = dui(ui)
1861 displayer.ui = du
1791 displayer.ui = du
1862 elif st == 'add':
1792 elif st == 'add':
1863 du.bump(rev)
1793 du.bump(rev)
1864 changenode = repo.changelog.node(rev)
1794 changenode = repo.changelog.node(rev)
1865 parents = [p for p in repo.changelog.parents(changenode)
1795 parents = [p for p in repo.changelog.parents(changenode)
1866 if p != nullid]
1796 if p != nullid]
1867 if opts['no_merges'] and len(parents) == 2:
1797 if opts['no_merges'] and len(parents) == 2:
1868 continue
1798 continue
1869 if opts['only_merges'] and len(parents) != 2:
1799 if opts['only_merges'] and len(parents) != 2:
1870 continue
1800 continue
1871
1801
1872 if opts['keyword']:
1802 if opts['keyword']:
1873 changes = getchange(rev)
1803 changes = getchange(rev)
1874 miss = 0
1804 miss = 0
1875 for k in [kw.lower() for kw in opts['keyword']]:
1805 for k in [kw.lower() for kw in opts['keyword']]:
1876 if not (k in changes[1].lower() or
1806 if not (k in changes[1].lower() or
1877 k in changes[4].lower() or
1807 k in changes[4].lower() or
1878 k in " ".join(changes[3][:20]).lower()):
1808 k in " ".join(changes[3][:20]).lower()):
1879 miss = 1
1809 miss = 1
1880 break
1810 break
1881 if miss:
1811 if miss:
1882 continue
1812 continue
1883
1813
1884 br = None
1814 br = None
1885 if opts['branches']:
1815 if opts['branches']:
1886 br = repo.branchlookup([repo.changelog.node(rev)])
1816 br = repo.branchlookup([repo.changelog.node(rev)])
1887
1817
1888 displayer.show(rev, brinfo=br)
1818 displayer.show(rev, brinfo=br)
1889 if opts['patch']:
1819 if opts['patch']:
1890 prev = (parents and parents[0]) or nullid
1820 prev = (parents and parents[0]) or nullid
1891 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1821 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1892 du.write("\n\n")
1822 du.write("\n\n")
1893 elif st == 'iter':
1823 elif st == 'iter':
1894 if count == limit: break
1824 if count == limit: break
1895 if du.header[rev]:
1825 if du.header[rev]:
1896 for args in du.header[rev]:
1826 for args in du.header[rev]:
1897 ui.write_header(*args)
1827 ui.write_header(*args)
1898 if du.hunk[rev]:
1828 if du.hunk[rev]:
1899 count += 1
1829 count += 1
1900 for args in du.hunk[rev]:
1830 for args in du.hunk[rev]:
1901 ui.write(*args)
1831 ui.write(*args)
1902
1832
1903 def manifest(ui, repo, rev=None):
1833 def manifest(ui, repo, rev=None):
1904 """output the latest or given revision of the project manifest
1834 """output the latest or given revision of the project manifest
1905
1835
1906 Print a list of version controlled files for the given revision.
1836 Print a list of version controlled files for the given revision.
1907
1837
1908 The manifest is the list of files being version controlled. If no revision
1838 The manifest is the list of files being version controlled. If no revision
1909 is given then the tip is used.
1839 is given then the tip is used.
1910 """
1840 """
1911 if rev:
1841 if rev:
1912 try:
1842 try:
1913 # assume all revision numbers are for changesets
1843 # assume all revision numbers are for changesets
1914 n = repo.lookup(rev)
1844 n = repo.lookup(rev)
1915 change = repo.changelog.read(n)
1845 change = repo.changelog.read(n)
1916 n = change[0]
1846 n = change[0]
1917 except hg.RepoError:
1847 except hg.RepoError:
1918 n = repo.manifest.lookup(rev)
1848 n = repo.manifest.lookup(rev)
1919 else:
1849 else:
1920 n = repo.manifest.tip()
1850 n = repo.manifest.tip()
1921 m = repo.manifest.read(n)
1851 m = repo.manifest.read(n)
1922 files = m.keys()
1852 files = m.keys()
1923 files.sort()
1853 files.sort()
1924
1854
1925 for f in files:
1855 for f in files:
1926 ui.write("%40s %3s %s\n" % (hex(m[f]),
1856 ui.write("%40s %3s %s\n" % (hex(m[f]),
1927 m.execf(f) and "755" or "644", f))
1857 m.execf(f) and "755" or "644", f))
1928
1858
1929 def merge(ui, repo, node=None, force=None, branch=None):
1859 def merge(ui, repo, node=None, force=None, branch=None):
1930 """Merge working directory with another revision
1860 """Merge working directory with another revision
1931
1861
1932 Merge the contents of the current working directory and the
1862 Merge the contents of the current working directory and the
1933 requested revision. Files that changed between either parent are
1863 requested revision. Files that changed between either parent are
1934 marked as changed for the next commit and a commit must be
1864 marked as changed for the next commit and a commit must be
1935 performed before any further updates are allowed.
1865 performed before any further updates are allowed.
1936
1866
1937 If no revision is specified, the working directory's parent is a
1867 If no revision is specified, the working directory's parent is a
1938 head revision, and the repository contains exactly one other head,
1868 head revision, and the repository contains exactly one other head,
1939 the other head is merged with by default. Otherwise, an explicit
1869 the other head is merged with by default. Otherwise, an explicit
1940 revision to merge with must be provided.
1870 revision to merge with must be provided.
1941 """
1871 """
1942
1872
1943 if node or branch:
1873 if node or branch:
1944 node = _lookup(repo, node, branch)
1874 node = _lookup(repo, node, branch)
1945 else:
1875 else:
1946 heads = repo.heads()
1876 heads = repo.heads()
1947 if len(heads) > 2:
1877 if len(heads) > 2:
1948 raise util.Abort(_('repo has %d heads - '
1878 raise util.Abort(_('repo has %d heads - '
1949 'please merge with an explicit rev') %
1879 'please merge with an explicit rev') %
1950 len(heads))
1880 len(heads))
1951 if len(heads) == 1:
1881 if len(heads) == 1:
1952 raise util.Abort(_('there is nothing to merge - '
1882 raise util.Abort(_('there is nothing to merge - '
1953 'use "hg update" instead'))
1883 'use "hg update" instead'))
1954 parent = repo.dirstate.parents()[0]
1884 parent = repo.dirstate.parents()[0]
1955 if parent not in heads:
1885 if parent not in heads:
1956 raise util.Abort(_('working dir not at a head rev - '
1886 raise util.Abort(_('working dir not at a head rev - '
1957 'use "hg update" or merge with an explicit rev'))
1887 'use "hg update" or merge with an explicit rev'))
1958 node = parent == heads[0] and heads[-1] or heads[0]
1888 node = parent == heads[0] and heads[-1] or heads[0]
1959 return hg.merge(repo, node, force=force)
1889 return hg.merge(repo, node, force=force)
1960
1890
1961 def outgoing(ui, repo, dest=None, **opts):
1891 def outgoing(ui, repo, dest=None, **opts):
1962 """show changesets not found in destination
1892 """show changesets not found in destination
1963
1893
1964 Show changesets not found in the specified destination repository or
1894 Show changesets not found in the specified destination repository or
1965 the default push location. These are the changesets that would be pushed
1895 the default push location. These are the changesets that would be pushed
1966 if a push was requested.
1896 if a push was requested.
1967
1897
1968 See pull for valid destination format details.
1898 See pull for valid destination format details.
1969 """
1899 """
1970 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1900 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1971 setremoteconfig(ui, opts)
1901 setremoteconfig(ui, opts)
1972 revs = None
1902 revs = None
1973 if opts['rev']:
1903 if opts['rev']:
1974 revs = [repo.lookup(rev) for rev in opts['rev']]
1904 revs = [repo.lookup(rev) for rev in opts['rev']]
1975
1905
1976 other = hg.repository(ui, dest)
1906 other = hg.repository(ui, dest)
1977 o = repo.findoutgoing(other, force=opts['force'])
1907 o = repo.findoutgoing(other, force=opts['force'])
1978 if not o:
1908 if not o:
1979 ui.status(_("no changes found\n"))
1909 ui.status(_("no changes found\n"))
1980 return
1910 return
1981 o = repo.changelog.nodesbetween(o, revs)[0]
1911 o = repo.changelog.nodesbetween(o, revs)[0]
1982 if opts['newest_first']:
1912 if opts['newest_first']:
1983 o.reverse()
1913 o.reverse()
1984 displayer = show_changeset(ui, repo, opts)
1914 displayer = show_changeset(ui, repo, opts)
1985 for n in o:
1915 for n in o:
1986 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1916 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1987 if opts['no_merges'] and len(parents) == 2:
1917 if opts['no_merges'] and len(parents) == 2:
1988 continue
1918 continue
1989 displayer.show(changenode=n)
1919 displayer.show(changenode=n)
1990 if opts['patch']:
1920 if opts['patch']:
1991 prev = (parents and parents[0]) or nullid
1921 prev = (parents and parents[0]) or nullid
1992 patch.diff(repo, prev, n)
1922 patch.diff(repo, prev, n)
1993 ui.write("\n")
1923 ui.write("\n")
1994
1924
1995 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1925 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1996 """show the parents of the working dir or revision
1926 """show the parents of the working dir or revision
1997
1927
1998 Print the working directory's parent revisions.
1928 Print the working directory's parent revisions.
1999 """
1929 """
2000 # legacy
1930 # legacy
2001 if file_ and not rev:
1931 if file_ and not rev:
2002 try:
1932 try:
2003 rev = repo.lookup(file_)
1933 rev = repo.lookup(file_)
2004 file_ = None
1934 file_ = None
2005 except hg.RepoError:
1935 except hg.RepoError:
2006 pass
1936 pass
2007 else:
1937 else:
2008 ui.warn(_("'hg parent REV' is deprecated, "
1938 ui.warn(_("'hg parent REV' is deprecated, "
2009 "please use 'hg parents -r REV instead\n"))
1939 "please use 'hg parents -r REV instead\n"))
2010
1940
2011 if rev:
1941 if rev:
2012 if file_:
1942 if file_:
2013 ctx = repo.filectx(file_, changeid=rev)
1943 ctx = repo.filectx(file_, changeid=rev)
2014 else:
1944 else:
2015 ctx = repo.changectx(rev)
1945 ctx = repo.changectx(rev)
2016 p = [cp.node() for cp in ctx.parents()]
1946 p = [cp.node() for cp in ctx.parents()]
2017 else:
1947 else:
2018 p = repo.dirstate.parents()
1948 p = repo.dirstate.parents()
2019
1949
2020 br = None
1950 br = None
2021 if branches is not None:
1951 if branches is not None:
2022 br = repo.branchlookup(p)
1952 br = repo.branchlookup(p)
2023 displayer = show_changeset(ui, repo, opts)
1953 displayer = show_changeset(ui, repo, opts)
2024 for n in p:
1954 for n in p:
2025 if n != nullid:
1955 if n != nullid:
2026 displayer.show(changenode=n, brinfo=br)
1956 displayer.show(changenode=n, brinfo=br)
2027
1957
2028 def paths(ui, repo, search=None):
1958 def paths(ui, repo, search=None):
2029 """show definition of symbolic path names
1959 """show definition of symbolic path names
2030
1960
2031 Show definition of symbolic path name NAME. If no name is given, show
1961 Show definition of symbolic path name NAME. If no name is given, show
2032 definition of available names.
1962 definition of available names.
2033
1963
2034 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1964 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2035 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1965 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2036 """
1966 """
2037 if search:
1967 if search:
2038 for name, path in ui.configitems("paths"):
1968 for name, path in ui.configitems("paths"):
2039 if name == search:
1969 if name == search:
2040 ui.write("%s\n" % path)
1970 ui.write("%s\n" % path)
2041 return
1971 return
2042 ui.warn(_("not found!\n"))
1972 ui.warn(_("not found!\n"))
2043 return 1
1973 return 1
2044 else:
1974 else:
2045 for name, path in ui.configitems("paths"):
1975 for name, path in ui.configitems("paths"):
2046 ui.write("%s = %s\n" % (name, path))
1976 ui.write("%s = %s\n" % (name, path))
2047
1977
2048 def postincoming(ui, repo, modheads, optupdate):
1978 def postincoming(ui, repo, modheads, optupdate):
2049 if modheads == 0:
1979 if modheads == 0:
2050 return
1980 return
2051 if optupdate:
1981 if optupdate:
2052 if modheads == 1:
1982 if modheads == 1:
2053 return hg.update(repo, repo.changelog.tip()) # update
1983 return hg.update(repo, repo.changelog.tip()) # update
2054 else:
1984 else:
2055 ui.status(_("not updating, since new heads added\n"))
1985 ui.status(_("not updating, since new heads added\n"))
2056 if modheads > 1:
1986 if modheads > 1:
2057 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1987 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2058 else:
1988 else:
2059 ui.status(_("(run 'hg update' to get a working copy)\n"))
1989 ui.status(_("(run 'hg update' to get a working copy)\n"))
2060
1990
2061 def pull(ui, repo, source="default", **opts):
1991 def pull(ui, repo, source="default", **opts):
2062 """pull changes from the specified source
1992 """pull changes from the specified source
2063
1993
2064 Pull changes from a remote repository to a local one.
1994 Pull changes from a remote repository to a local one.
2065
1995
2066 This finds all changes from the repository at the specified path
1996 This finds all changes from the repository at the specified path
2067 or URL and adds them to the local repository. By default, this
1997 or URL and adds them to the local repository. By default, this
2068 does not update the copy of the project in the working directory.
1998 does not update the copy of the project in the working directory.
2069
1999
2070 Valid URLs are of the form:
2000 Valid URLs are of the form:
2071
2001
2072 local/filesystem/path
2002 local/filesystem/path
2073 http://[user@]host[:port]/[path]
2003 http://[user@]host[:port]/[path]
2074 https://[user@]host[:port]/[path]
2004 https://[user@]host[:port]/[path]
2075 ssh://[user@]host[:port]/[path]
2005 ssh://[user@]host[:port]/[path]
2076
2006
2077 Some notes about using SSH with Mercurial:
2007 Some notes about using SSH with Mercurial:
2078 - SSH requires an accessible shell account on the destination machine
2008 - SSH requires an accessible shell account on the destination machine
2079 and a copy of hg in the remote path or specified with as remotecmd.
2009 and a copy of hg in the remote path or specified with as remotecmd.
2080 - path is relative to the remote user's home directory by default.
2010 - path is relative to the remote user's home directory by default.
2081 Use an extra slash at the start of a path to specify an absolute path:
2011 Use an extra slash at the start of a path to specify an absolute path:
2082 ssh://example.com//tmp/repository
2012 ssh://example.com//tmp/repository
2083 - Mercurial doesn't use its own compression via SSH; the right thing
2013 - Mercurial doesn't use its own compression via SSH; the right thing
2084 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2014 to do is to configure it in your ~/.ssh/ssh_config, e.g.:
2085 Host *.mylocalnetwork.example.com
2015 Host *.mylocalnetwork.example.com
2086 Compression off
2016 Compression off
2087 Host *
2017 Host *
2088 Compression on
2018 Compression on
2089 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2019 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2090 with the --ssh command line option.
2020 with the --ssh command line option.
2091 """
2021 """
2092 source = ui.expandpath(source)
2022 source = ui.expandpath(source)
2093 setremoteconfig(ui, opts)
2023 setremoteconfig(ui, opts)
2094
2024
2095 other = hg.repository(ui, source)
2025 other = hg.repository(ui, source)
2096 ui.status(_('pulling from %s\n') % (source))
2026 ui.status(_('pulling from %s\n') % (source))
2097 revs = None
2027 revs = None
2098 if opts['rev'] and not other.local():
2028 if opts['rev'] and not other.local():
2099 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2029 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
2100 elif opts['rev']:
2030 elif opts['rev']:
2101 revs = [other.lookup(rev) for rev in opts['rev']]
2031 revs = [other.lookup(rev) for rev in opts['rev']]
2102 modheads = repo.pull(other, heads=revs, force=opts['force'])
2032 modheads = repo.pull(other, heads=revs, force=opts['force'])
2103 return postincoming(ui, repo, modheads, opts['update'])
2033 return postincoming(ui, repo, modheads, opts['update'])
2104
2034
2105 def push(ui, repo, dest=None, **opts):
2035 def push(ui, repo, dest=None, **opts):
2106 """push changes to the specified destination
2036 """push changes to the specified destination
2107
2037
2108 Push changes from the local repository to the given destination.
2038 Push changes from the local repository to the given destination.
2109
2039
2110 This is the symmetrical operation for pull. It helps to move
2040 This is the symmetrical operation for pull. It helps to move
2111 changes from the current repository to a different one. If the
2041 changes from the current repository to a different one. If the
2112 destination is local this is identical to a pull in that directory
2042 destination is local this is identical to a pull in that directory
2113 from the current one.
2043 from the current one.
2114
2044
2115 By default, push will refuse to run if it detects the result would
2045 By default, push will refuse to run if it detects the result would
2116 increase the number of remote heads. This generally indicates the
2046 increase the number of remote heads. This generally indicates the
2117 the client has forgotten to sync and merge before pushing.
2047 the client has forgotten to sync and merge before pushing.
2118
2048
2119 Valid URLs are of the form:
2049 Valid URLs are of the form:
2120
2050
2121 local/filesystem/path
2051 local/filesystem/path
2122 ssh://[user@]host[:port]/[path]
2052 ssh://[user@]host[:port]/[path]
2123
2053
2124 Look at the help text for the pull command for important details
2054 Look at the help text for the pull command for important details
2125 about ssh:// URLs.
2055 about ssh:// URLs.
2126
2056
2127 Pushing to http:// and https:// URLs is possible, too, if this
2057 Pushing to http:// and https:// URLs is possible, too, if this
2128 feature is enabled on the remote Mercurial server.
2058 feature is enabled on the remote Mercurial server.
2129 """
2059 """
2130 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2060 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2131 setremoteconfig(ui, opts)
2061 setremoteconfig(ui, opts)
2132
2062
2133 other = hg.repository(ui, dest)
2063 other = hg.repository(ui, dest)
2134 ui.status('pushing to %s\n' % (dest))
2064 ui.status('pushing to %s\n' % (dest))
2135 revs = None
2065 revs = None
2136 if opts['rev']:
2066 if opts['rev']:
2137 revs = [repo.lookup(rev) for rev in opts['rev']]
2067 revs = [repo.lookup(rev) for rev in opts['rev']]
2138 r = repo.push(other, opts['force'], revs=revs)
2068 r = repo.push(other, opts['force'], revs=revs)
2139 return r == 0
2069 return r == 0
2140
2070
2141 def rawcommit(ui, repo, *flist, **rc):
2071 def rawcommit(ui, repo, *flist, **rc):
2142 """raw commit interface (DEPRECATED)
2072 """raw commit interface (DEPRECATED)
2143
2073
2144 (DEPRECATED)
2074 (DEPRECATED)
2145 Lowlevel commit, for use in helper scripts.
2075 Lowlevel commit, for use in helper scripts.
2146
2076
2147 This command is not intended to be used by normal users, as it is
2077 This command is not intended to be used by normal users, as it is
2148 primarily useful for importing from other SCMs.
2078 primarily useful for importing from other SCMs.
2149
2079
2150 This command is now deprecated and will be removed in a future
2080 This command is now deprecated and will be removed in a future
2151 release, please use debugsetparents and commit instead.
2081 release, please use debugsetparents and commit instead.
2152 """
2082 """
2153
2083
2154 ui.warn(_("(the rawcommit command is deprecated)\n"))
2084 ui.warn(_("(the rawcommit command is deprecated)\n"))
2155
2085
2156 message = rc['message']
2086 message = rc['message']
2157 if not message and rc['logfile']:
2087 if not message and rc['logfile']:
2158 try:
2088 try:
2159 message = open(rc['logfile']).read()
2089 message = open(rc['logfile']).read()
2160 except IOError:
2090 except IOError:
2161 pass
2091 pass
2162 if not message and not rc['logfile']:
2092 if not message and not rc['logfile']:
2163 raise util.Abort(_("missing commit message"))
2093 raise util.Abort(_("missing commit message"))
2164
2094
2165 files = relpath(repo, list(flist))
2095 files = relpath(repo, list(flist))
2166 if rc['files']:
2096 if rc['files']:
2167 files += open(rc['files']).read().splitlines()
2097 files += open(rc['files']).read().splitlines()
2168
2098
2169 rc['parent'] = map(repo.lookup, rc['parent'])
2099 rc['parent'] = map(repo.lookup, rc['parent'])
2170
2100
2171 try:
2101 try:
2172 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2102 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2173 except ValueError, inst:
2103 except ValueError, inst:
2174 raise util.Abort(str(inst))
2104 raise util.Abort(str(inst))
2175
2105
2176 def recover(ui, repo):
2106 def recover(ui, repo):
2177 """roll back an interrupted transaction
2107 """roll back an interrupted transaction
2178
2108
2179 Recover from an interrupted commit or pull.
2109 Recover from an interrupted commit or pull.
2180
2110
2181 This command tries to fix the repository status after an interrupted
2111 This command tries to fix the repository status after an interrupted
2182 operation. It should only be necessary when Mercurial suggests it.
2112 operation. It should only be necessary when Mercurial suggests it.
2183 """
2113 """
2184 if repo.recover():
2114 if repo.recover():
2185 return hg.verify(repo)
2115 return hg.verify(repo)
2186 return 1
2116 return 1
2187
2117
2188 def remove(ui, repo, *pats, **opts):
2118 def remove(ui, repo, *pats, **opts):
2189 """remove the specified files on the next commit
2119 """remove the specified files on the next commit
2190
2120
2191 Schedule the indicated files for removal from the repository.
2121 Schedule the indicated files for removal from the repository.
2192
2122
2193 This command schedules the files to be removed at the next commit.
2123 This command schedules the files to be removed at the next commit.
2194 This only removes files from the current branch, not from the
2124 This only removes files from the current branch, not from the
2195 entire project history. If the files still exist in the working
2125 entire project history. If the files still exist in the working
2196 directory, they will be deleted from it. If invoked with --after,
2126 directory, they will be deleted from it. If invoked with --after,
2197 files that have been manually deleted are marked as removed.
2127 files that have been manually deleted are marked as removed.
2198
2128
2199 Modified files and added files are not removed by default. To
2129 Modified files and added files are not removed by default. To
2200 remove them, use the -f/--force option.
2130 remove them, use the -f/--force option.
2201 """
2131 """
2202 names = []
2132 names = []
2203 if not opts['after'] and not pats:
2133 if not opts['after'] and not pats:
2204 raise util.Abort(_('no files specified'))
2134 raise util.Abort(_('no files specified'))
2205 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2135 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2206 exact = dict.fromkeys(files)
2136 exact = dict.fromkeys(files)
2207 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2137 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2208 modified, added, removed, deleted, unknown = mardu
2138 modified, added, removed, deleted, unknown = mardu
2209 remove, forget = [], []
2139 remove, forget = [], []
2210 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2140 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2211 reason = None
2141 reason = None
2212 if abs not in deleted and opts['after']:
2142 if abs not in deleted and opts['after']:
2213 reason = _('is still present')
2143 reason = _('is still present')
2214 elif abs in modified and not opts['force']:
2144 elif abs in modified and not opts['force']:
2215 reason = _('is modified (use -f to force removal)')
2145 reason = _('is modified (use -f to force removal)')
2216 elif abs in added:
2146 elif abs in added:
2217 if opts['force']:
2147 if opts['force']:
2218 forget.append(abs)
2148 forget.append(abs)
2219 continue
2149 continue
2220 reason = _('has been marked for add (use -f to force removal)')
2150 reason = _('has been marked for add (use -f to force removal)')
2221 elif abs in unknown:
2151 elif abs in unknown:
2222 reason = _('is not managed')
2152 reason = _('is not managed')
2223 elif abs in removed:
2153 elif abs in removed:
2224 continue
2154 continue
2225 if reason:
2155 if reason:
2226 if exact:
2156 if exact:
2227 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2157 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2228 else:
2158 else:
2229 if ui.verbose or not exact:
2159 if ui.verbose or not exact:
2230 ui.status(_('removing %s\n') % rel)
2160 ui.status(_('removing %s\n') % rel)
2231 remove.append(abs)
2161 remove.append(abs)
2232 repo.forget(forget)
2162 repo.forget(forget)
2233 repo.remove(remove, unlink=not opts['after'])
2163 repo.remove(remove, unlink=not opts['after'])
2234
2164
2235 def rename(ui, repo, *pats, **opts):
2165 def rename(ui, repo, *pats, **opts):
2236 """rename files; equivalent of copy + remove
2166 """rename files; equivalent of copy + remove
2237
2167
2238 Mark dest as copies of sources; mark sources for deletion. If
2168 Mark dest as copies of sources; mark sources for deletion. If
2239 dest is a directory, copies are put in that directory. If dest is
2169 dest is a directory, copies are put in that directory. If dest is
2240 a file, there can only be one source.
2170 a file, there can only be one source.
2241
2171
2242 By default, this command copies the contents of files as they
2172 By default, this command copies the contents of files as they
2243 stand in the working directory. If invoked with --after, the
2173 stand in the working directory. If invoked with --after, the
2244 operation is recorded, but no copying is performed.
2174 operation is recorded, but no copying is performed.
2245
2175
2246 This command takes effect in the next commit.
2176 This command takes effect in the next commit.
2247
2177
2248 NOTE: This command should be treated as experimental. While it
2178 NOTE: This command should be treated as experimental. While it
2249 should properly record rename files, this information is not yet
2179 should properly record rename files, this information is not yet
2250 fully used by merge, nor fully reported by log.
2180 fully used by merge, nor fully reported by log.
2251 """
2181 """
2252 wlock = repo.wlock(0)
2182 wlock = repo.wlock(0)
2253 errs, copied = docopy(ui, repo, pats, opts, wlock)
2183 errs, copied = docopy(ui, repo, pats, opts, wlock)
2254 names = []
2184 names = []
2255 for abs, rel, exact in copied:
2185 for abs, rel, exact in copied:
2256 if ui.verbose or not exact:
2186 if ui.verbose or not exact:
2257 ui.status(_('removing %s\n') % rel)
2187 ui.status(_('removing %s\n') % rel)
2258 names.append(abs)
2188 names.append(abs)
2259 if not opts.get('dry_run'):
2189 if not opts.get('dry_run'):
2260 repo.remove(names, True, wlock)
2190 repo.remove(names, True, wlock)
2261 return errs
2191 return errs
2262
2192
2263 def revert(ui, repo, *pats, **opts):
2193 def revert(ui, repo, *pats, **opts):
2264 """revert files or dirs to their states as of some revision
2194 """revert files or dirs to their states as of some revision
2265
2195
2266 With no revision specified, revert the named files or directories
2196 With no revision specified, revert the named files or directories
2267 to the contents they had in the parent of the working directory.
2197 to the contents they had in the parent of the working directory.
2268 This restores the contents of the affected files to an unmodified
2198 This restores the contents of the affected files to an unmodified
2269 state. If the working directory has two parents, you must
2199 state. If the working directory has two parents, you must
2270 explicitly specify the revision to revert to.
2200 explicitly specify the revision to revert to.
2271
2201
2272 Modified files are saved with a .orig suffix before reverting.
2202 Modified files are saved with a .orig suffix before reverting.
2273 To disable these backups, use --no-backup.
2203 To disable these backups, use --no-backup.
2274
2204
2275 Using the -r option, revert the given files or directories to their
2205 Using the -r option, revert the given files or directories to their
2276 contents as of a specific revision. This can be helpful to "roll
2206 contents as of a specific revision. This can be helpful to "roll
2277 back" some or all of a change that should not have been committed.
2207 back" some or all of a change that should not have been committed.
2278
2208
2279 Revert modifies the working directory. It does not commit any
2209 Revert modifies the working directory. It does not commit any
2280 changes, or change the parent of the working directory. If you
2210 changes, or change the parent of the working directory. If you
2281 revert to a revision other than the parent of the working
2211 revert to a revision other than the parent of the working
2282 directory, the reverted files will thus appear modified
2212 directory, the reverted files will thus appear modified
2283 afterwards.
2213 afterwards.
2284
2214
2285 If a file has been deleted, it is recreated. If the executable
2215 If a file has been deleted, it is recreated. If the executable
2286 mode of a file was changed, it is reset.
2216 mode of a file was changed, it is reset.
2287
2217
2288 If names are given, all files matching the names are reverted.
2218 If names are given, all files matching the names are reverted.
2289
2219
2290 If no arguments are given, no files are reverted.
2220 If no arguments are given, no files are reverted.
2291 """
2221 """
2292
2222
2293 if not pats and not opts['all']:
2223 if not pats and not opts['all']:
2294 raise util.Abort(_('no files or directories specified; '
2224 raise util.Abort(_('no files or directories specified; '
2295 'use --all to revert the whole repo'))
2225 'use --all to revert the whole repo'))
2296
2226
2297 parent, p2 = repo.dirstate.parents()
2227 parent, p2 = repo.dirstate.parents()
2298 if opts['rev']:
2228 if opts['rev']:
2299 node = repo.lookup(opts['rev'])
2229 node = repo.lookup(opts['rev'])
2300 elif p2 != nullid:
2230 elif p2 != nullid:
2301 raise util.Abort(_('working dir has two parents; '
2231 raise util.Abort(_('working dir has two parents; '
2302 'you must specify the revision to revert to'))
2232 'you must specify the revision to revert to'))
2303 else:
2233 else:
2304 node = parent
2234 node = parent
2305 mf = repo.manifest.read(repo.changelog.read(node)[0])
2235 mf = repo.manifest.read(repo.changelog.read(node)[0])
2306 if node == parent:
2236 if node == parent:
2307 pmf = mf
2237 pmf = mf
2308 else:
2238 else:
2309 pmf = None
2239 pmf = None
2310
2240
2311 wlock = repo.wlock()
2241 wlock = repo.wlock()
2312
2242
2313 # need all matching names in dirstate and manifest of target rev,
2243 # need all matching names in dirstate and manifest of target rev,
2314 # so have to walk both. do not print errors if files exist in one
2244 # so have to walk both. do not print errors if files exist in one
2315 # but not other.
2245 # but not other.
2316
2246
2317 names = {}
2247 names = {}
2318 target_only = {}
2248 target_only = {}
2319
2249
2320 # walk dirstate.
2250 # walk dirstate.
2321
2251
2322 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2252 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2323 badmatch=mf.has_key):
2253 badmatch=mf.has_key):
2324 names[abs] = (rel, exact)
2254 names[abs] = (rel, exact)
2325 if src == 'b':
2255 if src == 'b':
2326 target_only[abs] = True
2256 target_only[abs] = True
2327
2257
2328 # walk target manifest.
2258 # walk target manifest.
2329
2259
2330 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2260 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2331 badmatch=names.has_key):
2261 badmatch=names.has_key):
2332 if abs in names: continue
2262 if abs in names: continue
2333 names[abs] = (rel, exact)
2263 names[abs] = (rel, exact)
2334 target_only[abs] = True
2264 target_only[abs] = True
2335
2265
2336 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2266 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2337 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2267 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2338
2268
2339 revert = ([], _('reverting %s\n'))
2269 revert = ([], _('reverting %s\n'))
2340 add = ([], _('adding %s\n'))
2270 add = ([], _('adding %s\n'))
2341 remove = ([], _('removing %s\n'))
2271 remove = ([], _('removing %s\n'))
2342 forget = ([], _('forgetting %s\n'))
2272 forget = ([], _('forgetting %s\n'))
2343 undelete = ([], _('undeleting %s\n'))
2273 undelete = ([], _('undeleting %s\n'))
2344 update = {}
2274 update = {}
2345
2275
2346 disptable = (
2276 disptable = (
2347 # dispatch table:
2277 # dispatch table:
2348 # file state
2278 # file state
2349 # action if in target manifest
2279 # action if in target manifest
2350 # action if not in target manifest
2280 # action if not in target manifest
2351 # make backup if in target manifest
2281 # make backup if in target manifest
2352 # make backup if not in target manifest
2282 # make backup if not in target manifest
2353 (modified, revert, remove, True, True),
2283 (modified, revert, remove, True, True),
2354 (added, revert, forget, True, False),
2284 (added, revert, forget, True, False),
2355 (removed, undelete, None, False, False),
2285 (removed, undelete, None, False, False),
2356 (deleted, revert, remove, False, False),
2286 (deleted, revert, remove, False, False),
2357 (unknown, add, None, True, False),
2287 (unknown, add, None, True, False),
2358 (target_only, add, None, False, False),
2288 (target_only, add, None, False, False),
2359 )
2289 )
2360
2290
2361 entries = names.items()
2291 entries = names.items()
2362 entries.sort()
2292 entries.sort()
2363
2293
2364 for abs, (rel, exact) in entries:
2294 for abs, (rel, exact) in entries:
2365 mfentry = mf.get(abs)
2295 mfentry = mf.get(abs)
2366 def handle(xlist, dobackup):
2296 def handle(xlist, dobackup):
2367 xlist[0].append(abs)
2297 xlist[0].append(abs)
2368 update[abs] = 1
2298 update[abs] = 1
2369 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2299 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2370 bakname = "%s.orig" % rel
2300 bakname = "%s.orig" % rel
2371 ui.note(_('saving current version of %s as %s\n') %
2301 ui.note(_('saving current version of %s as %s\n') %
2372 (rel, bakname))
2302 (rel, bakname))
2373 if not opts.get('dry_run'):
2303 if not opts.get('dry_run'):
2374 shutil.copyfile(rel, bakname)
2304 shutil.copyfile(rel, bakname)
2375 shutil.copymode(rel, bakname)
2305 shutil.copymode(rel, bakname)
2376 if ui.verbose or not exact:
2306 if ui.verbose or not exact:
2377 ui.status(xlist[1] % rel)
2307 ui.status(xlist[1] % rel)
2378 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2308 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2379 if abs not in table: continue
2309 if abs not in table: continue
2380 # file has changed in dirstate
2310 # file has changed in dirstate
2381 if mfentry:
2311 if mfentry:
2382 handle(hitlist, backuphit)
2312 handle(hitlist, backuphit)
2383 elif misslist is not None:
2313 elif misslist is not None:
2384 handle(misslist, backupmiss)
2314 handle(misslist, backupmiss)
2385 else:
2315 else:
2386 if exact: ui.warn(_('file not managed: %s\n' % rel))
2316 if exact: ui.warn(_('file not managed: %s\n' % rel))
2387 break
2317 break
2388 else:
2318 else:
2389 # file has not changed in dirstate
2319 # file has not changed in dirstate
2390 if node == parent:
2320 if node == parent:
2391 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2321 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2392 continue
2322 continue
2393 if pmf is None:
2323 if pmf is None:
2394 # only need parent manifest in this unlikely case,
2324 # only need parent manifest in this unlikely case,
2395 # so do not read by default
2325 # so do not read by default
2396 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2326 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2397 if abs in pmf:
2327 if abs in pmf:
2398 if mfentry:
2328 if mfentry:
2399 # if version of file is same in parent and target
2329 # if version of file is same in parent and target
2400 # manifests, do nothing
2330 # manifests, do nothing
2401 if pmf[abs] != mfentry:
2331 if pmf[abs] != mfentry:
2402 handle(revert, False)
2332 handle(revert, False)
2403 else:
2333 else:
2404 handle(remove, False)
2334 handle(remove, False)
2405
2335
2406 if not opts.get('dry_run'):
2336 if not opts.get('dry_run'):
2407 repo.dirstate.forget(forget[0])
2337 repo.dirstate.forget(forget[0])
2408 r = hg.revert(repo, node, update.has_key, wlock)
2338 r = hg.revert(repo, node, update.has_key, wlock)
2409 repo.dirstate.update(add[0], 'a')
2339 repo.dirstate.update(add[0], 'a')
2410 repo.dirstate.update(undelete[0], 'n')
2340 repo.dirstate.update(undelete[0], 'n')
2411 repo.dirstate.update(remove[0], 'r')
2341 repo.dirstate.update(remove[0], 'r')
2412 return r
2342 return r
2413
2343
2414 def rollback(ui, repo):
2344 def rollback(ui, repo):
2415 """roll back the last transaction in this repository
2345 """roll back the last transaction in this repository
2416
2346
2417 Roll back the last transaction in this repository, restoring the
2347 Roll back the last transaction in this repository, restoring the
2418 project to its state prior to the transaction.
2348 project to its state prior to the transaction.
2419
2349
2420 Transactions are used to encapsulate the effects of all commands
2350 Transactions are used to encapsulate the effects of all commands
2421 that create new changesets or propagate existing changesets into a
2351 that create new changesets or propagate existing changesets into a
2422 repository. For example, the following commands are transactional,
2352 repository. For example, the following commands are transactional,
2423 and their effects can be rolled back:
2353 and their effects can be rolled back:
2424
2354
2425 commit
2355 commit
2426 import
2356 import
2427 pull
2357 pull
2428 push (with this repository as destination)
2358 push (with this repository as destination)
2429 unbundle
2359 unbundle
2430
2360
2431 This command should be used with care. There is only one level of
2361 This command should be used with care. There is only one level of
2432 rollback, and there is no way to undo a rollback.
2362 rollback, and there is no way to undo a rollback.
2433
2363
2434 This command is not intended for use on public repositories. Once
2364 This command is not intended for use on public repositories. Once
2435 changes are visible for pull by other users, rolling a transaction
2365 changes are visible for pull by other users, rolling a transaction
2436 back locally is ineffective (someone else may already have pulled
2366 back locally is ineffective (someone else may already have pulled
2437 the changes). Furthermore, a race is possible with readers of the
2367 the changes). Furthermore, a race is possible with readers of the
2438 repository; for example an in-progress pull from the repository
2368 repository; for example an in-progress pull from the repository
2439 may fail if a rollback is performed.
2369 may fail if a rollback is performed.
2440 """
2370 """
2441 repo.rollback()
2371 repo.rollback()
2442
2372
2443 def root(ui, repo):
2373 def root(ui, repo):
2444 """print the root (top) of the current working dir
2374 """print the root (top) of the current working dir
2445
2375
2446 Print the root directory of the current repository.
2376 Print the root directory of the current repository.
2447 """
2377 """
2448 ui.write(repo.root + "\n")
2378 ui.write(repo.root + "\n")
2449
2379
2450 def serve(ui, repo, **opts):
2380 def serve(ui, repo, **opts):
2451 """export the repository via HTTP
2381 """export the repository via HTTP
2452
2382
2453 Start a local HTTP repository browser and pull server.
2383 Start a local HTTP repository browser and pull server.
2454
2384
2455 By default, the server logs accesses to stdout and errors to
2385 By default, the server logs accesses to stdout and errors to
2456 stderr. Use the "-A" and "-E" options to log to files.
2386 stderr. Use the "-A" and "-E" options to log to files.
2457 """
2387 """
2458
2388
2459 if opts["stdio"]:
2389 if opts["stdio"]:
2460 if repo is None:
2390 if repo is None:
2461 raise hg.RepoError(_("There is no Mercurial repository here"
2391 raise hg.RepoError(_("There is no Mercurial repository here"
2462 " (.hg not found)"))
2392 " (.hg not found)"))
2463 s = sshserver.sshserver(ui, repo)
2393 s = sshserver.sshserver(ui, repo)
2464 s.serve_forever()
2394 s.serve_forever()
2465
2395
2466 optlist = ("name templates style address port ipv6"
2396 optlist = ("name templates style address port ipv6"
2467 " accesslog errorlog webdir_conf")
2397 " accesslog errorlog webdir_conf")
2468 for o in optlist.split():
2398 for o in optlist.split():
2469 if opts[o]:
2399 if opts[o]:
2470 ui.setconfig("web", o, opts[o])
2400 ui.setconfig("web", o, opts[o])
2471
2401
2472 if repo is None and not ui.config("web", "webdir_conf"):
2402 if repo is None and not ui.config("web", "webdir_conf"):
2473 raise hg.RepoError(_("There is no Mercurial repository here"
2403 raise hg.RepoError(_("There is no Mercurial repository here"
2474 " (.hg not found)"))
2404 " (.hg not found)"))
2475
2405
2476 if opts['daemon'] and not opts['daemon_pipefds']:
2406 if opts['daemon'] and not opts['daemon_pipefds']:
2477 rfd, wfd = os.pipe()
2407 rfd, wfd = os.pipe()
2478 args = sys.argv[:]
2408 args = sys.argv[:]
2479 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2409 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2480 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2410 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2481 args[0], args)
2411 args[0], args)
2482 os.close(wfd)
2412 os.close(wfd)
2483 os.read(rfd, 1)
2413 os.read(rfd, 1)
2484 os._exit(0)
2414 os._exit(0)
2485
2415
2486 try:
2416 try:
2487 httpd = hgweb.server.create_server(ui, repo)
2417 httpd = hgweb.server.create_server(ui, repo)
2488 except socket.error, inst:
2418 except socket.error, inst:
2489 raise util.Abort(_('cannot start server: %s') % inst.args[1])
2419 raise util.Abort(_('cannot start server: %s') % inst.args[1])
2490
2420
2491 if ui.verbose:
2421 if ui.verbose:
2492 addr, port = httpd.socket.getsockname()
2422 addr, port = httpd.socket.getsockname()
2493 if addr == '0.0.0.0':
2423 if addr == '0.0.0.0':
2494 addr = socket.gethostname()
2424 addr = socket.gethostname()
2495 else:
2425 else:
2496 try:
2426 try:
2497 addr = socket.gethostbyaddr(addr)[0]
2427 addr = socket.gethostbyaddr(addr)[0]
2498 except socket.error:
2428 except socket.error:
2499 pass
2429 pass
2500 if port != 80:
2430 if port != 80:
2501 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2431 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2502 else:
2432 else:
2503 ui.status(_('listening at http://%s/\n') % addr)
2433 ui.status(_('listening at http://%s/\n') % addr)
2504
2434
2505 if opts['pid_file']:
2435 if opts['pid_file']:
2506 fp = open(opts['pid_file'], 'w')
2436 fp = open(opts['pid_file'], 'w')
2507 fp.write(str(os.getpid()) + '\n')
2437 fp.write(str(os.getpid()) + '\n')
2508 fp.close()
2438 fp.close()
2509
2439
2510 if opts['daemon_pipefds']:
2440 if opts['daemon_pipefds']:
2511 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2441 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2512 os.close(rfd)
2442 os.close(rfd)
2513 os.write(wfd, 'y')
2443 os.write(wfd, 'y')
2514 os.close(wfd)
2444 os.close(wfd)
2515 sys.stdout.flush()
2445 sys.stdout.flush()
2516 sys.stderr.flush()
2446 sys.stderr.flush()
2517 fd = os.open(util.nulldev, os.O_RDWR)
2447 fd = os.open(util.nulldev, os.O_RDWR)
2518 if fd != 0: os.dup2(fd, 0)
2448 if fd != 0: os.dup2(fd, 0)
2519 if fd != 1: os.dup2(fd, 1)
2449 if fd != 1: os.dup2(fd, 1)
2520 if fd != 2: os.dup2(fd, 2)
2450 if fd != 2: os.dup2(fd, 2)
2521 if fd not in (0, 1, 2): os.close(fd)
2451 if fd not in (0, 1, 2): os.close(fd)
2522
2452
2523 httpd.serve_forever()
2453 httpd.serve_forever()
2524
2454
2525 def status(ui, repo, *pats, **opts):
2455 def status(ui, repo, *pats, **opts):
2526 """show changed files in the working directory
2456 """show changed files in the working directory
2527
2457
2528 Show status of files in the repository. If names are given, only
2458 Show status of files in the repository. If names are given, only
2529 files that match are shown. Files that are clean or ignored, are
2459 files that match are shown. Files that are clean or ignored, are
2530 not listed unless -c (clean), -i (ignored) or -A is given.
2460 not listed unless -c (clean), -i (ignored) or -A is given.
2531
2461
2532 The codes used to show the status of files are:
2462 The codes used to show the status of files are:
2533 M = modified
2463 M = modified
2534 A = added
2464 A = added
2535 R = removed
2465 R = removed
2536 C = clean
2466 C = clean
2537 ! = deleted, but still tracked
2467 ! = deleted, but still tracked
2538 ? = not tracked
2468 ? = not tracked
2539 I = ignored (not shown by default)
2469 I = ignored (not shown by default)
2540 = the previous added file was copied from here
2470 = the previous added file was copied from here
2541 """
2471 """
2542
2472
2543 all = opts['all']
2473 all = opts['all']
2544
2474
2545 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2475 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2546 cwd = (pats and repo.getcwd()) or ''
2476 cwd = (pats and repo.getcwd()) or ''
2547 modified, added, removed, deleted, unknown, ignored, clean = [
2477 modified, added, removed, deleted, unknown, ignored, clean = [
2548 [util.pathto(cwd, x) for x in n]
2478 [util.pathto(cwd, x) for x in n]
2549 for n in repo.status(files=files, match=matchfn,
2479 for n in repo.status(files=files, match=matchfn,
2550 list_ignored=all or opts['ignored'],
2480 list_ignored=all or opts['ignored'],
2551 list_clean=all or opts['clean'])]
2481 list_clean=all or opts['clean'])]
2552
2482
2553 changetypes = (('modified', 'M', modified),
2483 changetypes = (('modified', 'M', modified),
2554 ('added', 'A', added),
2484 ('added', 'A', added),
2555 ('removed', 'R', removed),
2485 ('removed', 'R', removed),
2556 ('deleted', '!', deleted),
2486 ('deleted', '!', deleted),
2557 ('unknown', '?', unknown),
2487 ('unknown', '?', unknown),
2558 ('ignored', 'I', ignored))
2488 ('ignored', 'I', ignored))
2559
2489
2560 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2490 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2561
2491
2562 end = opts['print0'] and '\0' or '\n'
2492 end = opts['print0'] and '\0' or '\n'
2563
2493
2564 for opt, char, changes in ([ct for ct in explicit_changetypes
2494 for opt, char, changes in ([ct for ct in explicit_changetypes
2565 if all or opts[ct[0]]]
2495 if all or opts[ct[0]]]
2566 or changetypes):
2496 or changetypes):
2567 if opts['no_status']:
2497 if opts['no_status']:
2568 format = "%%s%s" % end
2498 format = "%%s%s" % end
2569 else:
2499 else:
2570 format = "%s %%s%s" % (char, end)
2500 format = "%s %%s%s" % (char, end)
2571
2501
2572 for f in changes:
2502 for f in changes:
2573 ui.write(format % f)
2503 ui.write(format % f)
2574 if ((all or opts.get('copies')) and not opts.get('no_status')
2504 if ((all or opts.get('copies')) and not opts.get('no_status')
2575 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2505 and opt == 'added' and repo.dirstate.copies.has_key(f)):
2576 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2506 ui.write(' %s%s' % (repo.dirstate.copies[f], end))
2577
2507
2578 def tag(ui, repo, name, rev_=None, **opts):
2508 def tag(ui, repo, name, rev_=None, **opts):
2579 """add a tag for the current tip or a given revision
2509 """add a tag for the current tip or a given revision
2580
2510
2581 Name a particular revision using <name>.
2511 Name a particular revision using <name>.
2582
2512
2583 Tags are used to name particular revisions of the repository and are
2513 Tags are used to name particular revisions of the repository and are
2584 very useful to compare different revision, to go back to significant
2514 very useful to compare different revision, to go back to significant
2585 earlier versions or to mark branch points as releases, etc.
2515 earlier versions or to mark branch points as releases, etc.
2586
2516
2587 If no revision is given, the parent of the working directory is used.
2517 If no revision is given, the parent of the working directory is used.
2588
2518
2589 To facilitate version control, distribution, and merging of tags,
2519 To facilitate version control, distribution, and merging of tags,
2590 they are stored as a file named ".hgtags" which is managed
2520 they are stored as a file named ".hgtags" which is managed
2591 similarly to other project files and can be hand-edited if
2521 similarly to other project files and can be hand-edited if
2592 necessary. The file '.hg/localtags' is used for local tags (not
2522 necessary. The file '.hg/localtags' is used for local tags (not
2593 shared among repositories).
2523 shared among repositories).
2594 """
2524 """
2595 if name in ['tip', '.']:
2525 if name in ['tip', '.']:
2596 raise util.Abort(_("the name '%s' is reserved") % name)
2526 raise util.Abort(_("the name '%s' is reserved") % name)
2597 if rev_ is not None:
2527 if rev_ is not None:
2598 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2528 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2599 "please use 'hg tag [-r REV] NAME' instead\n"))
2529 "please use 'hg tag [-r REV] NAME' instead\n"))
2600 if opts['rev']:
2530 if opts['rev']:
2601 raise util.Abort(_("use only one form to specify the revision"))
2531 raise util.Abort(_("use only one form to specify the revision"))
2602 if opts['rev']:
2532 if opts['rev']:
2603 rev_ = opts['rev']
2533 rev_ = opts['rev']
2604 if rev_:
2534 if rev_:
2605 r = repo.lookup(rev_)
2535 r = repo.lookup(rev_)
2606 else:
2536 else:
2607 p1, p2 = repo.dirstate.parents()
2537 p1, p2 = repo.dirstate.parents()
2608 if p1 == nullid:
2538 if p1 == nullid:
2609 raise util.Abort(_('no revision to tag'))
2539 raise util.Abort(_('no revision to tag'))
2610 if p2 != nullid:
2540 if p2 != nullid:
2611 raise util.Abort(_('outstanding uncommitted merges'))
2541 raise util.Abort(_('outstanding uncommitted merges'))
2612 r = p1
2542 r = p1
2613
2543
2614 message = opts['message']
2544 message = opts['message']
2615 if not message:
2545 if not message:
2616 message = _('Added tag %s for changeset %s') % (name, short(r))
2546 message = _('Added tag %s for changeset %s') % (name, short(r))
2617
2547
2618 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2548 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2619
2549
2620 def tags(ui, repo):
2550 def tags(ui, repo):
2621 """list repository tags
2551 """list repository tags
2622
2552
2623 List the repository tags.
2553 List the repository tags.
2624
2554
2625 This lists both regular and local tags.
2555 This lists both regular and local tags.
2626 """
2556 """
2627
2557
2628 l = repo.tagslist()
2558 l = repo.tagslist()
2629 l.reverse()
2559 l.reverse()
2630 hexfunc = ui.debugflag and hex or short
2560 hexfunc = ui.debugflag and hex or short
2631 for t, n in l:
2561 for t, n in l:
2632 try:
2562 try:
2633 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2563 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2634 except KeyError:
2564 except KeyError:
2635 r = " ?:?"
2565 r = " ?:?"
2636 if ui.quiet:
2566 if ui.quiet:
2637 ui.write("%s\n" % t)
2567 ui.write("%s\n" % t)
2638 else:
2568 else:
2639 ui.write("%-30s %s\n" % (t, r))
2569 ui.write("%-30s %s\n" % (t, r))
2640
2570
2641 def tip(ui, repo, **opts):
2571 def tip(ui, repo, **opts):
2642 """show the tip revision
2572 """show the tip revision
2643
2573
2644 Show the tip revision.
2574 Show the tip revision.
2645 """
2575 """
2646 n = repo.changelog.tip()
2576 n = repo.changelog.tip()
2647 br = None
2577 br = None
2648 if opts['branches']:
2578 if opts['branches']:
2649 br = repo.branchlookup([n])
2579 br = repo.branchlookup([n])
2650 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2580 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2651 if opts['patch']:
2581 if opts['patch']:
2652 patch.diff(repo, repo.changelog.parents(n)[0], n)
2582 patch.diff(repo, repo.changelog.parents(n)[0], n)
2653
2583
2654 def unbundle(ui, repo, fname, **opts):
2584 def unbundle(ui, repo, fname, **opts):
2655 """apply a changegroup file
2585 """apply a changegroup file
2656
2586
2657 Apply a compressed changegroup file generated by the bundle
2587 Apply a compressed changegroup file generated by the bundle
2658 command.
2588 command.
2659 """
2589 """
2660 f = urllib.urlopen(fname)
2590 f = urllib.urlopen(fname)
2661
2591
2662 header = f.read(6)
2592 header = f.read(6)
2663 if not header.startswith("HG"):
2593 if not header.startswith("HG"):
2664 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2594 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2665 elif not header.startswith("HG10"):
2595 elif not header.startswith("HG10"):
2666 raise util.Abort(_("%s: unknown bundle version") % fname)
2596 raise util.Abort(_("%s: unknown bundle version") % fname)
2667 elif header == "HG10BZ":
2597 elif header == "HG10BZ":
2668 def generator(f):
2598 def generator(f):
2669 zd = bz2.BZ2Decompressor()
2599 zd = bz2.BZ2Decompressor()
2670 zd.decompress("BZ")
2600 zd.decompress("BZ")
2671 for chunk in f:
2601 for chunk in f:
2672 yield zd.decompress(chunk)
2602 yield zd.decompress(chunk)
2673 elif header == "HG10UN":
2603 elif header == "HG10UN":
2674 def generator(f):
2604 def generator(f):
2675 for chunk in f:
2605 for chunk in f:
2676 yield chunk
2606 yield chunk
2677 else:
2607 else:
2678 raise util.Abort(_("%s: unknown bundle compression type")
2608 raise util.Abort(_("%s: unknown bundle compression type")
2679 % fname)
2609 % fname)
2680 gen = generator(util.filechunkiter(f, 4096))
2610 gen = generator(util.filechunkiter(f, 4096))
2681 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2611 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2682 'bundle:' + fname)
2612 'bundle:' + fname)
2683 return postincoming(ui, repo, modheads, opts['update'])
2613 return postincoming(ui, repo, modheads, opts['update'])
2684
2614
2685 def undo(ui, repo):
2615 def undo(ui, repo):
2686 """undo the last commit or pull (DEPRECATED)
2616 """undo the last commit or pull (DEPRECATED)
2687
2617
2688 (DEPRECATED)
2618 (DEPRECATED)
2689 This command is now deprecated and will be removed in a future
2619 This command is now deprecated and will be removed in a future
2690 release. Please use the rollback command instead. For usage
2620 release. Please use the rollback command instead. For usage
2691 instructions, see the rollback command.
2621 instructions, see the rollback command.
2692 """
2622 """
2693 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2623 ui.warn(_('(the undo command is deprecated; use rollback instead)\n'))
2694 repo.rollback()
2624 repo.rollback()
2695
2625
2696 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2626 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2697 branch=None):
2627 branch=None):
2698 """update or merge working directory
2628 """update or merge working directory
2699
2629
2700 Update the working directory to the specified revision.
2630 Update the working directory to the specified revision.
2701
2631
2702 If there are no outstanding changes in the working directory and
2632 If there are no outstanding changes in the working directory and
2703 there is a linear relationship between the current version and the
2633 there is a linear relationship between the current version and the
2704 requested version, the result is the requested version.
2634 requested version, the result is the requested version.
2705
2635
2706 To merge the working directory with another revision, use the
2636 To merge the working directory with another revision, use the
2707 merge command.
2637 merge command.
2708
2638
2709 By default, update will refuse to run if doing so would require
2639 By default, update will refuse to run if doing so would require
2710 merging or discarding local changes.
2640 merging or discarding local changes.
2711 """
2641 """
2712 node = _lookup(repo, node, branch)
2642 node = _lookup(repo, node, branch)
2713 if merge:
2643 if merge:
2714 ui.warn(_('(the -m/--merge option is deprecated; '
2644 ui.warn(_('(the -m/--merge option is deprecated; '
2715 'use the merge command instead)\n'))
2645 'use the merge command instead)\n'))
2716 return hg.merge(repo, node, force=force)
2646 return hg.merge(repo, node, force=force)
2717 elif clean:
2647 elif clean:
2718 return hg.clean(repo, node)
2648 return hg.clean(repo, node)
2719 else:
2649 else:
2720 return hg.update(repo, node)
2650 return hg.update(repo, node)
2721
2651
2722 def _lookup(repo, node, branch=None):
2652 def _lookup(repo, node, branch=None):
2723 if branch:
2653 if branch:
2724 br = repo.branchlookup(branch=branch)
2654 br = repo.branchlookup(branch=branch)
2725 found = []
2655 found = []
2726 for x in br:
2656 for x in br:
2727 if branch in br[x]:
2657 if branch in br[x]:
2728 found.append(x)
2658 found.append(x)
2729 if len(found) > 1:
2659 if len(found) > 1:
2730 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2660 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2731 for x in found:
2661 for x in found:
2732 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2662 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br)
2733 raise util.Abort("")
2663 raise util.Abort("")
2734 if len(found) == 1:
2664 if len(found) == 1:
2735 node = found[0]
2665 node = found[0]
2736 repo.ui.warn(_("Using head %s for branch %s\n")
2666 repo.ui.warn(_("Using head %s for branch %s\n")
2737 % (short(node), branch))
2667 % (short(node), branch))
2738 else:
2668 else:
2739 raise util.Abort(_("branch %s not found") % branch)
2669 raise util.Abort(_("branch %s not found") % branch)
2740 else:
2670 else:
2741 node = node and repo.lookup(node) or repo.changelog.tip()
2671 node = node and repo.lookup(node) or repo.changelog.tip()
2742 return node
2672 return node
2743
2673
2744 def verify(ui, repo):
2674 def verify(ui, repo):
2745 """verify the integrity of the repository
2675 """verify the integrity of the repository
2746
2676
2747 Verify the integrity of the current repository.
2677 Verify the integrity of the current repository.
2748
2678
2749 This will perform an extensive check of the repository's
2679 This will perform an extensive check of the repository's
2750 integrity, validating the hashes and checksums of each entry in
2680 integrity, validating the hashes and checksums of each entry in
2751 the changelog, manifest, and tracked files, as well as the
2681 the changelog, manifest, and tracked files, as well as the
2752 integrity of their crosslinks and indices.
2682 integrity of their crosslinks and indices.
2753 """
2683 """
2754 return hg.verify(repo)
2684 return hg.verify(repo)
2755
2685
2756 # Command options and aliases are listed here, alphabetically
2686 # Command options and aliases are listed here, alphabetically
2757
2687
2758 table = {
2688 table = {
2759 "^add":
2689 "^add":
2760 (add,
2690 (add,
2761 [('I', 'include', [], _('include names matching the given patterns')),
2691 [('I', 'include', [], _('include names matching the given patterns')),
2762 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2692 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2763 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2693 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2764 _('hg add [OPTION]... [FILE]...')),
2694 _('hg add [OPTION]... [FILE]...')),
2765 "addremove":
2695 "addremove":
2766 (addremove,
2696 (addremove,
2767 [('I', 'include', [], _('include names matching the given patterns')),
2697 [('I', 'include', [], _('include names matching the given patterns')),
2768 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2698 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2769 ('n', 'dry-run', None,
2699 ('n', 'dry-run', None,
2770 _('do not perform actions, just print output')),
2700 _('do not perform actions, just print output')),
2771 ('s', 'similarity', '',
2701 ('s', 'similarity', '',
2772 _('guess renamed files by similarity (0<=s<=1)'))],
2702 _('guess renamed files by similarity (0<=s<=1)'))],
2773 _('hg addremove [OPTION]... [FILE]...')),
2703 _('hg addremove [OPTION]... [FILE]...')),
2774 "^annotate":
2704 "^annotate":
2775 (annotate,
2705 (annotate,
2776 [('r', 'rev', '', _('annotate the specified revision')),
2706 [('r', 'rev', '', _('annotate the specified revision')),
2777 ('a', 'text', None, _('treat all files as text')),
2707 ('a', 'text', None, _('treat all files as text')),
2778 ('u', 'user', None, _('list the author')),
2708 ('u', 'user', None, _('list the author')),
2779 ('d', 'date', None, _('list the date')),
2709 ('d', 'date', None, _('list the date')),
2780 ('n', 'number', None, _('list the revision number (default)')),
2710 ('n', 'number', None, _('list the revision number (default)')),
2781 ('c', 'changeset', None, _('list the changeset')),
2711 ('c', 'changeset', None, _('list the changeset')),
2782 ('I', 'include', [], _('include names matching the given patterns')),
2712 ('I', 'include', [], _('include names matching the given patterns')),
2783 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2713 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2784 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2714 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2785 "archive":
2715 "archive":
2786 (archive,
2716 (archive,
2787 [('', 'no-decode', None, _('do not pass files through decoders')),
2717 [('', 'no-decode', None, _('do not pass files through decoders')),
2788 ('p', 'prefix', '', _('directory prefix for files in archive')),
2718 ('p', 'prefix', '', _('directory prefix for files in archive')),
2789 ('r', 'rev', '', _('revision to distribute')),
2719 ('r', 'rev', '', _('revision to distribute')),
2790 ('t', 'type', '', _('type of distribution to create')),
2720 ('t', 'type', '', _('type of distribution to create')),
2791 ('I', 'include', [], _('include names matching the given patterns')),
2721 ('I', 'include', [], _('include names matching the given patterns')),
2792 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2722 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2793 _('hg archive [OPTION]... DEST')),
2723 _('hg archive [OPTION]... DEST')),
2794 "backout":
2724 "backout":
2795 (backout,
2725 (backout,
2796 [('', 'merge', None,
2726 [('', 'merge', None,
2797 _('merge with old dirstate parent after backout')),
2727 _('merge with old dirstate parent after backout')),
2798 ('m', 'message', '', _('use <text> as commit message')),
2728 ('m', 'message', '', _('use <text> as commit message')),
2799 ('l', 'logfile', '', _('read commit message from <file>')),
2729 ('l', 'logfile', '', _('read commit message from <file>')),
2800 ('d', 'date', '', _('record datecode as commit date')),
2730 ('d', 'date', '', _('record datecode as commit date')),
2801 ('', 'parent', '', _('parent to choose when backing out merge')),
2731 ('', 'parent', '', _('parent to choose when backing out merge')),
2802 ('u', 'user', '', _('record user as committer')),
2732 ('u', 'user', '', _('record user as committer')),
2803 ('I', 'include', [], _('include names matching the given patterns')),
2733 ('I', 'include', [], _('include names matching the given patterns')),
2804 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2734 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2805 _('hg backout [OPTION]... REV')),
2735 _('hg backout [OPTION]... REV')),
2806 "bundle":
2736 "bundle":
2807 (bundle,
2737 (bundle,
2808 [('f', 'force', None,
2738 [('f', 'force', None,
2809 _('run even when remote repository is unrelated'))],
2739 _('run even when remote repository is unrelated'))],
2810 _('hg bundle FILE DEST')),
2740 _('hg bundle FILE DEST')),
2811 "cat":
2741 "cat":
2812 (cat,
2742 (cat,
2813 [('o', 'output', '', _('print output to file with formatted name')),
2743 [('o', 'output', '', _('print output to file with formatted name')),
2814 ('r', 'rev', '', _('print the given revision')),
2744 ('r', 'rev', '', _('print the given revision')),
2815 ('I', 'include', [], _('include names matching the given patterns')),
2745 ('I', 'include', [], _('include names matching the given patterns')),
2816 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2746 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2817 _('hg cat [OPTION]... FILE...')),
2747 _('hg cat [OPTION]... FILE...')),
2818 "^clone":
2748 "^clone":
2819 (clone,
2749 (clone,
2820 [('U', 'noupdate', None, _('do not update the new working directory')),
2750 [('U', 'noupdate', None, _('do not update the new working directory')),
2821 ('r', 'rev', [],
2751 ('r', 'rev', [],
2822 _('a changeset you would like to have after cloning')),
2752 _('a changeset you would like to have after cloning')),
2823 ('', 'pull', None, _('use pull protocol to copy metadata')),
2753 ('', 'pull', None, _('use pull protocol to copy metadata')),
2824 ('', 'uncompressed', None,
2754 ('', 'uncompressed', None,
2825 _('use uncompressed transfer (fast over LAN)')),
2755 _('use uncompressed transfer (fast over LAN)')),
2826 ('e', 'ssh', '', _('specify ssh command to use')),
2756 ('e', 'ssh', '', _('specify ssh command to use')),
2827 ('', 'remotecmd', '',
2757 ('', 'remotecmd', '',
2828 _('specify hg command to run on the remote side'))],
2758 _('specify hg command to run on the remote side'))],
2829 _('hg clone [OPTION]... SOURCE [DEST]')),
2759 _('hg clone [OPTION]... SOURCE [DEST]')),
2830 "^commit|ci":
2760 "^commit|ci":
2831 (commit,
2761 (commit,
2832 [('A', 'addremove', None,
2762 [('A', 'addremove', None,
2833 _('mark new/missing files as added/removed before committing')),
2763 _('mark new/missing files as added/removed before committing')),
2834 ('m', 'message', '', _('use <text> as commit message')),
2764 ('m', 'message', '', _('use <text> as commit message')),
2835 ('l', 'logfile', '', _('read the commit message from <file>')),
2765 ('l', 'logfile', '', _('read the commit message from <file>')),
2836 ('d', 'date', '', _('record datecode as commit date')),
2766 ('d', 'date', '', _('record datecode as commit date')),
2837 ('u', 'user', '', _('record user as commiter')),
2767 ('u', 'user', '', _('record user as commiter')),
2838 ('I', 'include', [], _('include names matching the given patterns')),
2768 ('I', 'include', [], _('include names matching the given patterns')),
2839 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2769 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2840 _('hg commit [OPTION]... [FILE]...')),
2770 _('hg commit [OPTION]... [FILE]...')),
2841 "copy|cp":
2771 "copy|cp":
2842 (copy,
2772 (copy,
2843 [('A', 'after', None, _('record a copy that has already occurred')),
2773 [('A', 'after', None, _('record a copy that has already occurred')),
2844 ('f', 'force', None,
2774 ('f', 'force', None,
2845 _('forcibly copy over an existing managed file')),
2775 _('forcibly copy over an existing managed file')),
2846 ('I', 'include', [], _('include names matching the given patterns')),
2776 ('I', 'include', [], _('include names matching the given patterns')),
2847 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2777 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2848 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2778 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2849 _('hg copy [OPTION]... [SOURCE]... DEST')),
2779 _('hg copy [OPTION]... [SOURCE]... DEST')),
2850 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2780 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2851 "debugcomplete":
2781 "debugcomplete":
2852 (debugcomplete,
2782 (debugcomplete,
2853 [('o', 'options', None, _('show the command options'))],
2783 [('o', 'options', None, _('show the command options'))],
2854 _('debugcomplete [-o] CMD')),
2784 _('debugcomplete [-o] CMD')),
2855 "debugrebuildstate":
2785 "debugrebuildstate":
2856 (debugrebuildstate,
2786 (debugrebuildstate,
2857 [('r', 'rev', '', _('revision to rebuild to'))],
2787 [('r', 'rev', '', _('revision to rebuild to'))],
2858 _('debugrebuildstate [-r REV] [REV]')),
2788 _('debugrebuildstate [-r REV] [REV]')),
2859 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2789 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2860 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2790 "debugconfig": (debugconfig, [], _('debugconfig [NAME]...')),
2861 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2791 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2862 "debugstate": (debugstate, [], _('debugstate')),
2792 "debugstate": (debugstate, [], _('debugstate')),
2863 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2793 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2864 "debugindex": (debugindex, [], _('debugindex FILE')),
2794 "debugindex": (debugindex, [], _('debugindex FILE')),
2865 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2795 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2866 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2796 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2867 "debugwalk":
2797 "debugwalk":
2868 (debugwalk,
2798 (debugwalk,
2869 [('I', 'include', [], _('include names matching the given patterns')),
2799 [('I', 'include', [], _('include names matching the given patterns')),
2870 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2800 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2871 _('debugwalk [OPTION]... [FILE]...')),
2801 _('debugwalk [OPTION]... [FILE]...')),
2872 "^diff":
2802 "^diff":
2873 (diff,
2803 (diff,
2874 [('r', 'rev', [], _('revision')),
2804 [('r', 'rev', [], _('revision')),
2875 ('a', 'text', None, _('treat all files as text')),
2805 ('a', 'text', None, _('treat all files as text')),
2876 ('p', 'show-function', None,
2806 ('p', 'show-function', None,
2877 _('show which function each change is in')),
2807 _('show which function each change is in')),
2878 ('g', 'git', None, _('use git extended diff format')),
2808 ('g', 'git', None, _('use git extended diff format')),
2879 ('w', 'ignore-all-space', None,
2809 ('w', 'ignore-all-space', None,
2880 _('ignore white space when comparing lines')),
2810 _('ignore white space when comparing lines')),
2881 ('b', 'ignore-space-change', None,
2811 ('b', 'ignore-space-change', None,
2882 _('ignore changes in the amount of white space')),
2812 _('ignore changes in the amount of white space')),
2883 ('B', 'ignore-blank-lines', None,
2813 ('B', 'ignore-blank-lines', None,
2884 _('ignore changes whose lines are all blank')),
2814 _('ignore changes whose lines are all blank')),
2885 ('I', 'include', [], _('include names matching the given patterns')),
2815 ('I', 'include', [], _('include names matching the given patterns')),
2886 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2816 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2887 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2817 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2888 "^export":
2818 "^export":
2889 (export,
2819 (export,
2890 [('o', 'output', '', _('print output to file with formatted name')),
2820 [('o', 'output', '', _('print output to file with formatted name')),
2891 ('a', 'text', None, _('treat all files as text')),
2821 ('a', 'text', None, _('treat all files as text')),
2892 ('g', 'git', None, _('use git extended diff format')),
2822 ('g', 'git', None, _('use git extended diff format')),
2893 ('', 'switch-parent', None, _('diff against the second parent'))],
2823 ('', 'switch-parent', None, _('diff against the second parent'))],
2894 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2824 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2895 "debugforget|forget":
2825 "debugforget|forget":
2896 (forget,
2826 (forget,
2897 [('I', 'include', [], _('include names matching the given patterns')),
2827 [('I', 'include', [], _('include names matching the given patterns')),
2898 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2828 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2899 _('hg forget [OPTION]... FILE...')),
2829 _('hg forget [OPTION]... FILE...')),
2900 "grep":
2830 "grep":
2901 (grep,
2831 (grep,
2902 [('0', 'print0', None, _('end fields with NUL')),
2832 [('0', 'print0', None, _('end fields with NUL')),
2903 ('', 'all', None, _('print all revisions that match')),
2833 ('', 'all', None, _('print all revisions that match')),
2904 ('f', 'follow', None,
2834 ('f', 'follow', None,
2905 _('follow changeset history, or file history across copies and renames')),
2835 _('follow changeset history, or file history across copies and renames')),
2906 ('i', 'ignore-case', None, _('ignore case when matching')),
2836 ('i', 'ignore-case', None, _('ignore case when matching')),
2907 ('l', 'files-with-matches', None,
2837 ('l', 'files-with-matches', None,
2908 _('print only filenames and revs that match')),
2838 _('print only filenames and revs that match')),
2909 ('n', 'line-number', None, _('print matching line numbers')),
2839 ('n', 'line-number', None, _('print matching line numbers')),
2910 ('r', 'rev', [], _('search in given revision range')),
2840 ('r', 'rev', [], _('search in given revision range')),
2911 ('u', 'user', None, _('print user who committed change')),
2841 ('u', 'user', None, _('print user who committed change')),
2912 ('I', 'include', [], _('include names matching the given patterns')),
2842 ('I', 'include', [], _('include names matching the given patterns')),
2913 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2843 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2914 _('hg grep [OPTION]... PATTERN [FILE]...')),
2844 _('hg grep [OPTION]... PATTERN [FILE]...')),
2915 "heads":
2845 "heads":
2916 (heads,
2846 (heads,
2917 [('b', 'branches', None, _('show branches')),
2847 [('b', 'branches', None, _('show branches')),
2918 ('', 'style', '', _('display using template map file')),
2848 ('', 'style', '', _('display using template map file')),
2919 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2849 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2920 ('', 'template', '', _('display with template'))],
2850 ('', 'template', '', _('display with template'))],
2921 _('hg heads [-b] [-r <rev>]')),
2851 _('hg heads [-b] [-r <rev>]')),
2922 "help": (help_, [], _('hg help [COMMAND]')),
2852 "help": (help_, [], _('hg help [COMMAND]')),
2923 "identify|id": (identify, [], _('hg identify')),
2853 "identify|id": (identify, [], _('hg identify')),
2924 "import|patch":
2854 "import|patch":
2925 (import_,
2855 (import_,
2926 [('p', 'strip', 1,
2856 [('p', 'strip', 1,
2927 _('directory strip option for patch. This has the same\n'
2857 _('directory strip option for patch. This has the same\n'
2928 'meaning as the corresponding patch option')),
2858 'meaning as the corresponding patch option')),
2929 ('m', 'message', '', _('use <text> as commit message')),
2859 ('m', 'message', '', _('use <text> as commit message')),
2930 ('b', 'base', '', _('base path')),
2860 ('b', 'base', '', _('base path')),
2931 ('f', 'force', None,
2861 ('f', 'force', None,
2932 _('skip check for outstanding uncommitted changes'))],
2862 _('skip check for outstanding uncommitted changes'))],
2933 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2863 _('hg import [-p NUM] [-b BASE] [-m MESSAGE] [-f] PATCH...')),
2934 "incoming|in": (incoming,
2864 "incoming|in": (incoming,
2935 [('M', 'no-merges', None, _('do not show merges')),
2865 [('M', 'no-merges', None, _('do not show merges')),
2936 ('f', 'force', None,
2866 ('f', 'force', None,
2937 _('run even when remote repository is unrelated')),
2867 _('run even when remote repository is unrelated')),
2938 ('', 'style', '', _('display using template map file')),
2868 ('', 'style', '', _('display using template map file')),
2939 ('n', 'newest-first', None, _('show newest record first')),
2869 ('n', 'newest-first', None, _('show newest record first')),
2940 ('', 'bundle', '', _('file to store the bundles into')),
2870 ('', 'bundle', '', _('file to store the bundles into')),
2941 ('p', 'patch', None, _('show patch')),
2871 ('p', 'patch', None, _('show patch')),
2942 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2872 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2943 ('', 'template', '', _('display with template')),
2873 ('', 'template', '', _('display with template')),
2944 ('e', 'ssh', '', _('specify ssh command to use')),
2874 ('e', 'ssh', '', _('specify ssh command to use')),
2945 ('', 'remotecmd', '',
2875 ('', 'remotecmd', '',
2946 _('specify hg command to run on the remote side'))],
2876 _('specify hg command to run on the remote side'))],
2947 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2877 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2948 ' [--bundle FILENAME] [SOURCE]')),
2878 ' [--bundle FILENAME] [SOURCE]')),
2949 "^init":
2879 "^init":
2950 (init,
2880 (init,
2951 [('e', 'ssh', '', _('specify ssh command to use')),
2881 [('e', 'ssh', '', _('specify ssh command to use')),
2952 ('', 'remotecmd', '',
2882 ('', 'remotecmd', '',
2953 _('specify hg command to run on the remote side'))],
2883 _('specify hg command to run on the remote side'))],
2954 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2884 _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2955 "locate":
2885 "locate":
2956 (locate,
2886 (locate,
2957 [('r', 'rev', '', _('search the repository as it stood at rev')),
2887 [('r', 'rev', '', _('search the repository as it stood at rev')),
2958 ('0', 'print0', None,
2888 ('0', 'print0', None,
2959 _('end filenames with NUL, for use with xargs')),
2889 _('end filenames with NUL, for use with xargs')),
2960 ('f', 'fullpath', None,
2890 ('f', 'fullpath', None,
2961 _('print complete paths from the filesystem root')),
2891 _('print complete paths from the filesystem root')),
2962 ('I', 'include', [], _('include names matching the given patterns')),
2892 ('I', 'include', [], _('include names matching the given patterns')),
2963 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2893 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2964 _('hg locate [OPTION]... [PATTERN]...')),
2894 _('hg locate [OPTION]... [PATTERN]...')),
2965 "^log|history":
2895 "^log|history":
2966 (log,
2896 (log,
2967 [('b', 'branches', None, _('show branches')),
2897 [('b', 'branches', None, _('show branches')),
2968 ('f', 'follow', None,
2898 ('f', 'follow', None,
2969 _('follow changeset history, or file history across copies and renames')),
2899 _('follow changeset history, or file history across copies and renames')),
2970 ('', 'follow-first', None,
2900 ('', 'follow-first', None,
2971 _('only follow the first parent of merge changesets')),
2901 _('only follow the first parent of merge changesets')),
2972 ('k', 'keyword', [], _('search for a keyword')),
2902 ('k', 'keyword', [], _('search for a keyword')),
2973 ('l', 'limit', '', _('limit number of changes displayed')),
2903 ('l', 'limit', '', _('limit number of changes displayed')),
2974 ('r', 'rev', [], _('show the specified revision or range')),
2904 ('r', 'rev', [], _('show the specified revision or range')),
2975 ('M', 'no-merges', None, _('do not show merges')),
2905 ('M', 'no-merges', None, _('do not show merges')),
2976 ('', 'style', '', _('display using template map file')),
2906 ('', 'style', '', _('display using template map file')),
2977 ('m', 'only-merges', None, _('show only merges')),
2907 ('m', 'only-merges', None, _('show only merges')),
2978 ('p', 'patch', None, _('show patch')),
2908 ('p', 'patch', None, _('show patch')),
2979 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2909 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2980 ('', 'template', '', _('display with template')),
2910 ('', 'template', '', _('display with template')),
2981 ('I', 'include', [], _('include names matching the given patterns')),
2911 ('I', 'include', [], _('include names matching the given patterns')),
2982 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2912 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2983 _('hg log [OPTION]... [FILE]')),
2913 _('hg log [OPTION]... [FILE]')),
2984 "manifest": (manifest, [], _('hg manifest [REV]')),
2914 "manifest": (manifest, [], _('hg manifest [REV]')),
2985 "merge":
2915 "merge":
2986 (merge,
2916 (merge,
2987 [('b', 'branch', '', _('merge with head of a specific branch')),
2917 [('b', 'branch', '', _('merge with head of a specific branch')),
2988 ('f', 'force', None, _('force a merge with outstanding changes'))],
2918 ('f', 'force', None, _('force a merge with outstanding changes'))],
2989 _('hg merge [-b TAG] [-f] [REV]')),
2919 _('hg merge [-b TAG] [-f] [REV]')),
2990 "outgoing|out": (outgoing,
2920 "outgoing|out": (outgoing,
2991 [('M', 'no-merges', None, _('do not show merges')),
2921 [('M', 'no-merges', None, _('do not show merges')),
2992 ('f', 'force', None,
2922 ('f', 'force', None,
2993 _('run even when remote repository is unrelated')),
2923 _('run even when remote repository is unrelated')),
2994 ('p', 'patch', None, _('show patch')),
2924 ('p', 'patch', None, _('show patch')),
2995 ('', 'style', '', _('display using template map file')),
2925 ('', 'style', '', _('display using template map file')),
2996 ('r', 'rev', [], _('a specific revision you would like to push')),
2926 ('r', 'rev', [], _('a specific revision you would like to push')),
2997 ('n', 'newest-first', None, _('show newest record first')),
2927 ('n', 'newest-first', None, _('show newest record first')),
2998 ('', 'template', '', _('display with template')),
2928 ('', 'template', '', _('display with template')),
2999 ('e', 'ssh', '', _('specify ssh command to use')),
2929 ('e', 'ssh', '', _('specify ssh command to use')),
3000 ('', 'remotecmd', '',
2930 ('', 'remotecmd', '',
3001 _('specify hg command to run on the remote side'))],
2931 _('specify hg command to run on the remote side'))],
3002 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2932 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
3003 "^parents":
2933 "^parents":
3004 (parents,
2934 (parents,
3005 [('b', 'branches', None, _('show branches')),
2935 [('b', 'branches', None, _('show branches')),
3006 ('r', 'rev', '', _('show parents from the specified rev')),
2936 ('r', 'rev', '', _('show parents from the specified rev')),
3007 ('', 'style', '', _('display using template map file')),
2937 ('', 'style', '', _('display using template map file')),
3008 ('', 'template', '', _('display with template'))],
2938 ('', 'template', '', _('display with template'))],
3009 _('hg parents [-b] [-r REV] [FILE]')),
2939 _('hg parents [-b] [-r REV] [FILE]')),
3010 "paths": (paths, [], _('hg paths [NAME]')),
2940 "paths": (paths, [], _('hg paths [NAME]')),
3011 "^pull":
2941 "^pull":
3012 (pull,
2942 (pull,
3013 [('u', 'update', None,
2943 [('u', 'update', None,
3014 _('update the working directory to tip after pull')),
2944 _('update the working directory to tip after pull')),
3015 ('e', 'ssh', '', _('specify ssh command to use')),
2945 ('e', 'ssh', '', _('specify ssh command to use')),
3016 ('f', 'force', None,
2946 ('f', 'force', None,
3017 _('run even when remote repository is unrelated')),
2947 _('run even when remote repository is unrelated')),
3018 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2948 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
3019 ('', 'remotecmd', '',
2949 ('', 'remotecmd', '',
3020 _('specify hg command to run on the remote side'))],
2950 _('specify hg command to run on the remote side'))],
3021 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2951 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
3022 "^push":
2952 "^push":
3023 (push,
2953 (push,
3024 [('f', 'force', None, _('force push')),
2954 [('f', 'force', None, _('force push')),
3025 ('e', 'ssh', '', _('specify ssh command to use')),
2955 ('e', 'ssh', '', _('specify ssh command to use')),
3026 ('r', 'rev', [], _('a specific revision you would like to push')),
2956 ('r', 'rev', [], _('a specific revision you would like to push')),
3027 ('', 'remotecmd', '',
2957 ('', 'remotecmd', '',
3028 _('specify hg command to run on the remote side'))],
2958 _('specify hg command to run on the remote side'))],
3029 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2959 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
3030 "debugrawcommit|rawcommit":
2960 "debugrawcommit|rawcommit":
3031 (rawcommit,
2961 (rawcommit,
3032 [('p', 'parent', [], _('parent')),
2962 [('p', 'parent', [], _('parent')),
3033 ('d', 'date', '', _('date code')),
2963 ('d', 'date', '', _('date code')),
3034 ('u', 'user', '', _('user')),
2964 ('u', 'user', '', _('user')),
3035 ('F', 'files', '', _('file list')),
2965 ('F', 'files', '', _('file list')),
3036 ('m', 'message', '', _('commit message')),
2966 ('m', 'message', '', _('commit message')),
3037 ('l', 'logfile', '', _('commit message file'))],
2967 ('l', 'logfile', '', _('commit message file'))],
3038 _('hg debugrawcommit [OPTION]... [FILE]...')),
2968 _('hg debugrawcommit [OPTION]... [FILE]...')),
3039 "recover": (recover, [], _('hg recover')),
2969 "recover": (recover, [], _('hg recover')),
3040 "^remove|rm":
2970 "^remove|rm":
3041 (remove,
2971 (remove,
3042 [('A', 'after', None, _('record remove that has already occurred')),
2972 [('A', 'after', None, _('record remove that has already occurred')),
3043 ('f', 'force', None, _('remove file even if modified')),
2973 ('f', 'force', None, _('remove file even if modified')),
3044 ('I', 'include', [], _('include names matching the given patterns')),
2974 ('I', 'include', [], _('include names matching the given patterns')),
3045 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2975 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3046 _('hg remove [OPTION]... FILE...')),
2976 _('hg remove [OPTION]... FILE...')),
3047 "rename|mv":
2977 "rename|mv":
3048 (rename,
2978 (rename,
3049 [('A', 'after', None, _('record a rename that has already occurred')),
2979 [('A', 'after', None, _('record a rename that has already occurred')),
3050 ('f', 'force', None,
2980 ('f', 'force', None,
3051 _('forcibly copy over an existing managed file')),
2981 _('forcibly copy over an existing managed file')),
3052 ('I', 'include', [], _('include names matching the given patterns')),
2982 ('I', 'include', [], _('include names matching the given patterns')),
3053 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2983 ('X', 'exclude', [], _('exclude names matching the given patterns')),
3054 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2984 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3055 _('hg rename [OPTION]... SOURCE... DEST')),
2985 _('hg rename [OPTION]... SOURCE... DEST')),
3056 "^revert":
2986 "^revert":
3057 (revert,
2987 (revert,
3058 [('a', 'all', None, _('revert all changes when no arguments given')),
2988 [('a', 'all', None, _('revert all changes when no arguments given')),
3059 ('r', 'rev', '', _('revision to revert to')),
2989 ('r', 'rev', '', _('revision to revert to')),
3060 ('', 'no-backup', None, _('do not save backup copies of files')),
2990 ('', 'no-backup', None, _('do not save backup copies of files')),
3061 ('I', 'include', [], _('include names matching given patterns')),
2991 ('I', 'include', [], _('include names matching given patterns')),
3062 ('X', 'exclude', [], _('exclude names matching given patterns')),
2992 ('X', 'exclude', [], _('exclude names matching given patterns')),
3063 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
2993 ('n', 'dry-run', None, _('do not perform actions, just print output'))],
3064 _('hg revert [-r REV] [NAME]...')),
2994 _('hg revert [-r REV] [NAME]...')),
3065 "rollback": (rollback, [], _('hg rollback')),
2995 "rollback": (rollback, [], _('hg rollback')),
3066 "root": (root, [], _('hg root')),
2996 "root": (root, [], _('hg root')),
3067 "^serve":
2997 "^serve":
3068 (serve,
2998 (serve,
3069 [('A', 'accesslog', '', _('name of access log file to write to')),
2999 [('A', 'accesslog', '', _('name of access log file to write to')),
3070 ('d', 'daemon', None, _('run server in background')),
3000 ('d', 'daemon', None, _('run server in background')),
3071 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3001 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3072 ('E', 'errorlog', '', _('name of error log file to write to')),
3002 ('E', 'errorlog', '', _('name of error log file to write to')),
3073 ('p', 'port', 0, _('port to use (default: 8000)')),
3003 ('p', 'port', 0, _('port to use (default: 8000)')),
3074 ('a', 'address', '', _('address to use')),
3004 ('a', 'address', '', _('address to use')),
3075 ('n', 'name', '',
3005 ('n', 'name', '',
3076 _('name to show in web pages (default: working dir)')),
3006 _('name to show in web pages (default: working dir)')),
3077 ('', 'webdir-conf', '', _('name of the webdir config file'
3007 ('', 'webdir-conf', '', _('name of the webdir config file'
3078 ' (serve more than one repo)')),
3008 ' (serve more than one repo)')),
3079 ('', 'pid-file', '', _('name of file to write process ID to')),
3009 ('', 'pid-file', '', _('name of file to write process ID to')),
3080 ('', 'stdio', None, _('for remote clients')),
3010 ('', 'stdio', None, _('for remote clients')),
3081 ('t', 'templates', '', _('web templates to use')),
3011 ('t', 'templates', '', _('web templates to use')),
3082 ('', 'style', '', _('template style to use')),
3012 ('', 'style', '', _('template style to use')),
3083 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3013 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
3084 _('hg serve [OPTION]...')),
3014 _('hg serve [OPTION]...')),
3085 "^status|st":
3015 "^status|st":
3086 (status,
3016 (status,
3087 [('A', 'all', None, _('show status of all files')),
3017 [('A', 'all', None, _('show status of all files')),
3088 ('m', 'modified', None, _('show only modified files')),
3018 ('m', 'modified', None, _('show only modified files')),
3089 ('a', 'added', None, _('show only added files')),
3019 ('a', 'added', None, _('show only added files')),
3090 ('r', 'removed', None, _('show only removed files')),
3020 ('r', 'removed', None, _('show only removed files')),
3091 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3021 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3092 ('c', 'clean', None, _('show only files without changes')),
3022 ('c', 'clean', None, _('show only files without changes')),
3093 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3023 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3094 ('i', 'ignored', None, _('show ignored files')),
3024 ('i', 'ignored', None, _('show ignored files')),
3095 ('n', 'no-status', None, _('hide status prefix')),
3025 ('n', 'no-status', None, _('hide status prefix')),
3096 ('C', 'copies', None, _('show source of copied files')),
3026 ('C', 'copies', None, _('show source of copied files')),
3097 ('0', 'print0', None,
3027 ('0', 'print0', None,
3098 _('end filenames with NUL, for use with xargs')),
3028 _('end filenames with NUL, for use with xargs')),
3099 ('I', 'include', [], _('include names matching the given patterns')),
3029 ('I', 'include', [], _('include names matching the given patterns')),
3100 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3030 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
3101 _('hg status [OPTION]... [FILE]...')),
3031 _('hg status [OPTION]... [FILE]...')),
3102 "tag":
3032 "tag":
3103 (tag,
3033 (tag,
3104 [('l', 'local', None, _('make the tag local')),
3034 [('l', 'local', None, _('make the tag local')),
3105 ('m', 'message', '', _('message for tag commit log entry')),
3035 ('m', 'message', '', _('message for tag commit log entry')),
3106 ('d', 'date', '', _('record datecode as commit date')),
3036 ('d', 'date', '', _('record datecode as commit date')),
3107 ('u', 'user', '', _('record user as commiter')),
3037 ('u', 'user', '', _('record user as commiter')),
3108 ('r', 'rev', '', _('revision to tag'))],
3038 ('r', 'rev', '', _('revision to tag'))],
3109 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3039 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3110 "tags": (tags, [], _('hg tags')),
3040 "tags": (tags, [], _('hg tags')),
3111 "tip":
3041 "tip":
3112 (tip,
3042 (tip,
3113 [('b', 'branches', None, _('show branches')),
3043 [('b', 'branches', None, _('show branches')),
3114 ('', 'style', '', _('display using template map file')),
3044 ('', 'style', '', _('display using template map file')),
3115 ('p', 'patch', None, _('show patch')),
3045 ('p', 'patch', None, _('show patch')),
3116 ('', 'template', '', _('display with template'))],
3046 ('', 'template', '', _('display with template'))],
3117 _('hg tip [-b] [-p]')),
3047 _('hg tip [-b] [-p]')),
3118 "unbundle":
3048 "unbundle":
3119 (unbundle,
3049 (unbundle,
3120 [('u', 'update', None,
3050 [('u', 'update', None,
3121 _('update the working directory to tip after unbundle'))],
3051 _('update the working directory to tip after unbundle'))],
3122 _('hg unbundle [-u] FILE')),
3052 _('hg unbundle [-u] FILE')),
3123 "debugundo|undo": (undo, [], _('hg undo')),
3053 "debugundo|undo": (undo, [], _('hg undo')),
3124 "^update|up|checkout|co":
3054 "^update|up|checkout|co":
3125 (update,
3055 (update,
3126 [('b', 'branch', '', _('checkout the head of a specific branch')),
3056 [('b', 'branch', '', _('checkout the head of a specific branch')),
3127 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3057 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3128 ('C', 'clean', None, _('overwrite locally modified files')),
3058 ('C', 'clean', None, _('overwrite locally modified files')),
3129 ('f', 'force', None, _('force a merge with outstanding changes'))],
3059 ('f', 'force', None, _('force a merge with outstanding changes'))],
3130 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3060 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
3131 "verify": (verify, [], _('hg verify')),
3061 "verify": (verify, [], _('hg verify')),
3132 "version": (show_version, [], _('hg version')),
3062 "version": (show_version, [], _('hg version')),
3133 }
3063 }
3134
3064
3135 globalopts = [
3065 globalopts = [
3136 ('R', 'repository', '',
3066 ('R', 'repository', '',
3137 _('repository root directory or symbolic path name')),
3067 _('repository root directory or symbolic path name')),
3138 ('', 'cwd', '', _('change working directory')),
3068 ('', 'cwd', '', _('change working directory')),
3139 ('y', 'noninteractive', None,
3069 ('y', 'noninteractive', None,
3140 _('do not prompt, assume \'yes\' for any required answers')),
3070 _('do not prompt, assume \'yes\' for any required answers')),
3141 ('q', 'quiet', None, _('suppress output')),
3071 ('q', 'quiet', None, _('suppress output')),
3142 ('v', 'verbose', None, _('enable additional output')),
3072 ('v', 'verbose', None, _('enable additional output')),
3143 ('', 'config', [], _('set/override config option')),
3073 ('', 'config', [], _('set/override config option')),
3144 ('', 'debug', None, _('enable debugging output')),
3074 ('', 'debug', None, _('enable debugging output')),
3145 ('', 'debugger', None, _('start debugger')),
3075 ('', 'debugger', None, _('start debugger')),
3146 ('', 'lsprof', None, _('print improved command execution profile')),
3076 ('', 'lsprof', None, _('print improved command execution profile')),
3147 ('', 'traceback', None, _('print traceback on exception')),
3077 ('', 'traceback', None, _('print traceback on exception')),
3148 ('', 'time', None, _('time how long the command takes')),
3078 ('', 'time', None, _('time how long the command takes')),
3149 ('', 'profile', None, _('print command execution profile')),
3079 ('', 'profile', None, _('print command execution profile')),
3150 ('', 'version', None, _('output version information and exit')),
3080 ('', 'version', None, _('output version information and exit')),
3151 ('h', 'help', None, _('display help and exit')),
3081 ('h', 'help', None, _('display help and exit')),
3152 ]
3082 ]
3153
3083
3154 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3084 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3155 " debugindex debugindexdot")
3085 " debugindex debugindexdot")
3156 optionalrepo = ("paths serve debugconfig")
3086 optionalrepo = ("paths serve debugconfig")
3157
3087
3158 def findpossible(ui, cmd):
3088 def findpossible(ui, cmd):
3159 """
3089 """
3160 Return cmd -> (aliases, command table entry)
3090 Return cmd -> (aliases, command table entry)
3161 for each matching command.
3091 for each matching command.
3162 Return debug commands (or their aliases) only if no normal command matches.
3092 Return debug commands (or their aliases) only if no normal command matches.
3163 """
3093 """
3164 choice = {}
3094 choice = {}
3165 debugchoice = {}
3095 debugchoice = {}
3166 for e in table.keys():
3096 for e in table.keys():
3167 aliases = e.lstrip("^").split("|")
3097 aliases = e.lstrip("^").split("|")
3168 found = None
3098 found = None
3169 if cmd in aliases:
3099 if cmd in aliases:
3170 found = cmd
3100 found = cmd
3171 elif not ui.config("ui", "strict"):
3101 elif not ui.config("ui", "strict"):
3172 for a in aliases:
3102 for a in aliases:
3173 if a.startswith(cmd):
3103 if a.startswith(cmd):
3174 found = a
3104 found = a
3175 break
3105 break
3176 if found is not None:
3106 if found is not None:
3177 if aliases[0].startswith("debug"):
3107 if aliases[0].startswith("debug"):
3178 debugchoice[found] = (aliases, table[e])
3108 debugchoice[found] = (aliases, table[e])
3179 else:
3109 else:
3180 choice[found] = (aliases, table[e])
3110 choice[found] = (aliases, table[e])
3181
3111
3182 if not choice and debugchoice:
3112 if not choice and debugchoice:
3183 choice = debugchoice
3113 choice = debugchoice
3184
3114
3185 return choice
3115 return choice
3186
3116
3187 def findcmd(ui, cmd):
3117 def findcmd(ui, cmd):
3188 """Return (aliases, command table entry) for command string."""
3118 """Return (aliases, command table entry) for command string."""
3189 choice = findpossible(ui, cmd)
3119 choice = findpossible(ui, cmd)
3190
3120
3191 if choice.has_key(cmd):
3121 if choice.has_key(cmd):
3192 return choice[cmd]
3122 return choice[cmd]
3193
3123
3194 if len(choice) > 1:
3124 if len(choice) > 1:
3195 clist = choice.keys()
3125 clist = choice.keys()
3196 clist.sort()
3126 clist.sort()
3197 raise AmbiguousCommand(cmd, clist)
3127 raise AmbiguousCommand(cmd, clist)
3198
3128
3199 if choice:
3129 if choice:
3200 return choice.values()[0]
3130 return choice.values()[0]
3201
3131
3202 raise UnknownCommand(cmd)
3132 raise UnknownCommand(cmd)
3203
3133
3204 def catchterm(*args):
3134 def catchterm(*args):
3205 raise util.SignalInterrupt
3135 raise util.SignalInterrupt
3206
3136
3207 def run():
3137 def run():
3208 sys.exit(dispatch(sys.argv[1:]))
3138 sys.exit(dispatch(sys.argv[1:]))
3209
3139
3210 class ParseError(Exception):
3140 class ParseError(Exception):
3211 """Exception raised on errors in parsing the command line."""
3141 """Exception raised on errors in parsing the command line."""
3212
3142
3213 def parse(ui, args):
3143 def parse(ui, args):
3214 options = {}
3144 options = {}
3215 cmdoptions = {}
3145 cmdoptions = {}
3216
3146
3217 try:
3147 try:
3218 args = fancyopts.fancyopts(args, globalopts, options)
3148 args = fancyopts.fancyopts(args, globalopts, options)
3219 except fancyopts.getopt.GetoptError, inst:
3149 except fancyopts.getopt.GetoptError, inst:
3220 raise ParseError(None, inst)
3150 raise ParseError(None, inst)
3221
3151
3222 if args:
3152 if args:
3223 cmd, args = args[0], args[1:]
3153 cmd, args = args[0], args[1:]
3224 aliases, i = findcmd(ui, cmd)
3154 aliases, i = findcmd(ui, cmd)
3225 cmd = aliases[0]
3155 cmd = aliases[0]
3226 defaults = ui.config("defaults", cmd)
3156 defaults = ui.config("defaults", cmd)
3227 if defaults:
3157 if defaults:
3228 args = shlex.split(defaults) + args
3158 args = shlex.split(defaults) + args
3229 c = list(i[1])
3159 c = list(i[1])
3230 else:
3160 else:
3231 cmd = None
3161 cmd = None
3232 c = []
3162 c = []
3233
3163
3234 # combine global options into local
3164 # combine global options into local
3235 for o in globalopts:
3165 for o in globalopts:
3236 c.append((o[0], o[1], options[o[1]], o[3]))
3166 c.append((o[0], o[1], options[o[1]], o[3]))
3237
3167
3238 try:
3168 try:
3239 args = fancyopts.fancyopts(args, c, cmdoptions)
3169 args = fancyopts.fancyopts(args, c, cmdoptions)
3240 except fancyopts.getopt.GetoptError, inst:
3170 except fancyopts.getopt.GetoptError, inst:
3241 raise ParseError(cmd, inst)
3171 raise ParseError(cmd, inst)
3242
3172
3243 # separate global options back out
3173 # separate global options back out
3244 for o in globalopts:
3174 for o in globalopts:
3245 n = o[1]
3175 n = o[1]
3246 options[n] = cmdoptions[n]
3176 options[n] = cmdoptions[n]
3247 del cmdoptions[n]
3177 del cmdoptions[n]
3248
3178
3249 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3179 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3250
3180
3251 external = {}
3181 external = {}
3252
3182
3253 def findext(name):
3183 def findext(name):
3254 '''return module with given extension name'''
3184 '''return module with given extension name'''
3255 try:
3185 try:
3256 return sys.modules[external[name]]
3186 return sys.modules[external[name]]
3257 except KeyError:
3187 except KeyError:
3258 for k, v in external.iteritems():
3188 for k, v in external.iteritems():
3259 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3189 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3260 return sys.modules[v]
3190 return sys.modules[v]
3261 raise KeyError(name)
3191 raise KeyError(name)
3262
3192
3263 def load_extensions(ui):
3193 def load_extensions(ui):
3264 added = []
3194 added = []
3265 for ext_name, load_from_name in ui.extensions():
3195 for ext_name, load_from_name in ui.extensions():
3266 if ext_name in external:
3196 if ext_name in external:
3267 continue
3197 continue
3268 try:
3198 try:
3269 if load_from_name:
3199 if load_from_name:
3270 # the module will be loaded in sys.modules
3200 # the module will be loaded in sys.modules
3271 # choose an unique name so that it doesn't
3201 # choose an unique name so that it doesn't
3272 # conflicts with other modules
3202 # conflicts with other modules
3273 module_name = "hgext_%s" % ext_name.replace('.', '_')
3203 module_name = "hgext_%s" % ext_name.replace('.', '_')
3274 mod = imp.load_source(module_name, load_from_name)
3204 mod = imp.load_source(module_name, load_from_name)
3275 else:
3205 else:
3276 def importh(name):
3206 def importh(name):
3277 mod = __import__(name)
3207 mod = __import__(name)
3278 components = name.split('.')
3208 components = name.split('.')
3279 for comp in components[1:]:
3209 for comp in components[1:]:
3280 mod = getattr(mod, comp)
3210 mod = getattr(mod, comp)
3281 return mod
3211 return mod
3282 try:
3212 try:
3283 mod = importh("hgext.%s" % ext_name)
3213 mod = importh("hgext.%s" % ext_name)
3284 except ImportError:
3214 except ImportError:
3285 mod = importh(ext_name)
3215 mod = importh(ext_name)
3286 external[ext_name] = mod.__name__
3216 external[ext_name] = mod.__name__
3287 added.append((mod, ext_name))
3217 added.append((mod, ext_name))
3288 except (util.SignalInterrupt, KeyboardInterrupt):
3218 except (util.SignalInterrupt, KeyboardInterrupt):
3289 raise
3219 raise
3290 except Exception, inst:
3220 except Exception, inst:
3291 ui.warn(_("*** failed to import extension %s: %s\n") %
3221 ui.warn(_("*** failed to import extension %s: %s\n") %
3292 (ext_name, inst))
3222 (ext_name, inst))
3293 if ui.print_exc():
3223 if ui.print_exc():
3294 return 1
3224 return 1
3295
3225
3296 for mod, name in added:
3226 for mod, name in added:
3297 uisetup = getattr(mod, 'uisetup', None)
3227 uisetup = getattr(mod, 'uisetup', None)
3298 if uisetup:
3228 if uisetup:
3299 uisetup(ui)
3229 uisetup(ui)
3300 cmdtable = getattr(mod, 'cmdtable', {})
3230 cmdtable = getattr(mod, 'cmdtable', {})
3301 for t in cmdtable:
3231 for t in cmdtable:
3302 if t in table:
3232 if t in table:
3303 ui.warn(_("module %s overrides %s\n") % (name, t))
3233 ui.warn(_("module %s overrides %s\n") % (name, t))
3304 table.update(cmdtable)
3234 table.update(cmdtable)
3305
3235
3306 def dispatch(args):
3236 def dispatch(args):
3307 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3237 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3308 num = getattr(signal, name, None)
3238 num = getattr(signal, name, None)
3309 if num: signal.signal(num, catchterm)
3239 if num: signal.signal(num, catchterm)
3310
3240
3311 try:
3241 try:
3312 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3242 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3313 except util.Abort, inst:
3243 except util.Abort, inst:
3314 sys.stderr.write(_("abort: %s\n") % inst)
3244 sys.stderr.write(_("abort: %s\n") % inst)
3315 return -1
3245 return -1
3316
3246
3317 load_extensions(u)
3247 load_extensions(u)
3318 u.addreadhook(load_extensions)
3248 u.addreadhook(load_extensions)
3319
3249
3320 try:
3250 try:
3321 cmd, func, args, options, cmdoptions = parse(u, args)
3251 cmd, func, args, options, cmdoptions = parse(u, args)
3322 if options["time"]:
3252 if options["time"]:
3323 def get_times():
3253 def get_times():
3324 t = os.times()
3254 t = os.times()
3325 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3255 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3326 t = (t[0], t[1], t[2], t[3], time.clock())
3256 t = (t[0], t[1], t[2], t[3], time.clock())
3327 return t
3257 return t
3328 s = get_times()
3258 s = get_times()
3329 def print_time():
3259 def print_time():
3330 t = get_times()
3260 t = get_times()
3331 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3261 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3332 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3262 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3333 atexit.register(print_time)
3263 atexit.register(print_time)
3334
3264
3335 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3265 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3336 not options["noninteractive"], options["traceback"],
3266 not options["noninteractive"], options["traceback"],
3337 options["config"])
3267 options["config"])
3338
3268
3339 # enter the debugger before command execution
3269 # enter the debugger before command execution
3340 if options['debugger']:
3270 if options['debugger']:
3341 pdb.set_trace()
3271 pdb.set_trace()
3342
3272
3343 try:
3273 try:
3344 if options['cwd']:
3274 if options['cwd']:
3345 try:
3275 try:
3346 os.chdir(options['cwd'])
3276 os.chdir(options['cwd'])
3347 except OSError, inst:
3277 except OSError, inst:
3348 raise util.Abort('%s: %s' %
3278 raise util.Abort('%s: %s' %
3349 (options['cwd'], inst.strerror))
3279 (options['cwd'], inst.strerror))
3350
3280
3351 path = u.expandpath(options["repository"]) or ""
3281 path = u.expandpath(options["repository"]) or ""
3352 repo = path and hg.repository(u, path=path) or None
3282 repo = path and hg.repository(u, path=path) or None
3353
3283
3354 if options['help']:
3284 if options['help']:
3355 return help_(u, cmd, options['version'])
3285 return help_(u, cmd, options['version'])
3356 elif options['version']:
3286 elif options['version']:
3357 return show_version(u)
3287 return show_version(u)
3358 elif not cmd:
3288 elif not cmd:
3359 return help_(u, 'shortlist')
3289 return help_(u, 'shortlist')
3360
3290
3361 if cmd not in norepo.split():
3291 if cmd not in norepo.split():
3362 try:
3292 try:
3363 if not repo:
3293 if not repo:
3364 repo = hg.repository(u, path=path)
3294 repo = hg.repository(u, path=path)
3365 u = repo.ui
3295 u = repo.ui
3366 for name in external.itervalues():
3296 for name in external.itervalues():
3367 mod = sys.modules[name]
3297 mod = sys.modules[name]
3368 if hasattr(mod, 'reposetup'):
3298 if hasattr(mod, 'reposetup'):
3369 mod.reposetup(u, repo)
3299 mod.reposetup(u, repo)
3370 hg.repo_setup_hooks.append(mod.reposetup)
3300 hg.repo_setup_hooks.append(mod.reposetup)
3371 except hg.RepoError:
3301 except hg.RepoError:
3372 if cmd not in optionalrepo.split():
3302 if cmd not in optionalrepo.split():
3373 raise
3303 raise
3374 d = lambda: func(u, repo, *args, **cmdoptions)
3304 d = lambda: func(u, repo, *args, **cmdoptions)
3375 else:
3305 else:
3376 d = lambda: func(u, *args, **cmdoptions)
3306 d = lambda: func(u, *args, **cmdoptions)
3377
3307
3378 # reupdate the options, repo/.hg/hgrc may have changed them
3308 # reupdate the options, repo/.hg/hgrc may have changed them
3379 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3309 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3380 not options["noninteractive"], options["traceback"],
3310 not options["noninteractive"], options["traceback"],
3381 options["config"])
3311 options["config"])
3382
3312
3383 try:
3313 try:
3384 if options['profile']:
3314 if options['profile']:
3385 import hotshot, hotshot.stats
3315 import hotshot, hotshot.stats
3386 prof = hotshot.Profile("hg.prof")
3316 prof = hotshot.Profile("hg.prof")
3387 try:
3317 try:
3388 try:
3318 try:
3389 return prof.runcall(d)
3319 return prof.runcall(d)
3390 except:
3320 except:
3391 try:
3321 try:
3392 u.warn(_('exception raised - generating '
3322 u.warn(_('exception raised - generating '
3393 'profile anyway\n'))
3323 'profile anyway\n'))
3394 except:
3324 except:
3395 pass
3325 pass
3396 raise
3326 raise
3397 finally:
3327 finally:
3398 prof.close()
3328 prof.close()
3399 stats = hotshot.stats.load("hg.prof")
3329 stats = hotshot.stats.load("hg.prof")
3400 stats.strip_dirs()
3330 stats.strip_dirs()
3401 stats.sort_stats('time', 'calls')
3331 stats.sort_stats('time', 'calls')
3402 stats.print_stats(40)
3332 stats.print_stats(40)
3403 elif options['lsprof']:
3333 elif options['lsprof']:
3404 try:
3334 try:
3405 from mercurial import lsprof
3335 from mercurial import lsprof
3406 except ImportError:
3336 except ImportError:
3407 raise util.Abort(_(
3337 raise util.Abort(_(
3408 'lsprof not available - install from '
3338 'lsprof not available - install from '
3409 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3339 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3410 p = lsprof.Profiler()
3340 p = lsprof.Profiler()
3411 p.enable(subcalls=True)
3341 p.enable(subcalls=True)
3412 try:
3342 try:
3413 return d()
3343 return d()
3414 finally:
3344 finally:
3415 p.disable()
3345 p.disable()
3416 stats = lsprof.Stats(p.getstats())
3346 stats = lsprof.Stats(p.getstats())
3417 stats.sort()
3347 stats.sort()
3418 stats.pprint(top=10, file=sys.stderr, climit=5)
3348 stats.pprint(top=10, file=sys.stderr, climit=5)
3419 else:
3349 else:
3420 return d()
3350 return d()
3421 finally:
3351 finally:
3422 u.flush()
3352 u.flush()
3423 except:
3353 except:
3424 # enter the debugger when we hit an exception
3354 # enter the debugger when we hit an exception
3425 if options['debugger']:
3355 if options['debugger']:
3426 pdb.post_mortem(sys.exc_info()[2])
3356 pdb.post_mortem(sys.exc_info()[2])
3427 u.print_exc()
3357 u.print_exc()
3428 raise
3358 raise
3429 except ParseError, inst:
3359 except ParseError, inst:
3430 if inst.args[0]:
3360 if inst.args[0]:
3431 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3361 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3432 help_(u, inst.args[0])
3362 help_(u, inst.args[0])
3433 else:
3363 else:
3434 u.warn(_("hg: %s\n") % inst.args[1])
3364 u.warn(_("hg: %s\n") % inst.args[1])
3435 help_(u, 'shortlist')
3365 help_(u, 'shortlist')
3436 except AmbiguousCommand, inst:
3366 except AmbiguousCommand, inst:
3437 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3367 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3438 (inst.args[0], " ".join(inst.args[1])))
3368 (inst.args[0], " ".join(inst.args[1])))
3439 except UnknownCommand, inst:
3369 except UnknownCommand, inst:
3440 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3370 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3441 help_(u, 'shortlist')
3371 help_(u, 'shortlist')
3442 except hg.RepoError, inst:
3372 except hg.RepoError, inst:
3443 u.warn(_("abort: %s!\n") % inst)
3373 u.warn(_("abort: %s!\n") % inst)
3444 except lock.LockHeld, inst:
3374 except lock.LockHeld, inst:
3445 if inst.errno == errno.ETIMEDOUT:
3375 if inst.errno == errno.ETIMEDOUT:
3446 reason = _('timed out waiting for lock held by %s') % inst.locker
3376 reason = _('timed out waiting for lock held by %s') % inst.locker
3447 else:
3377 else:
3448 reason = _('lock held by %s') % inst.locker
3378 reason = _('lock held by %s') % inst.locker
3449 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3379 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3450 except lock.LockUnavailable, inst:
3380 except lock.LockUnavailable, inst:
3451 u.warn(_("abort: could not lock %s: %s\n") %
3381 u.warn(_("abort: could not lock %s: %s\n") %
3452 (inst.desc or inst.filename, inst.strerror))
3382 (inst.desc or inst.filename, inst.strerror))
3453 except revlog.RevlogError, inst:
3383 except revlog.RevlogError, inst:
3454 u.warn(_("abort: %s!\n") % inst)
3384 u.warn(_("abort: %s!\n") % inst)
3455 except util.SignalInterrupt:
3385 except util.SignalInterrupt:
3456 u.warn(_("killed!\n"))
3386 u.warn(_("killed!\n"))
3457 except KeyboardInterrupt:
3387 except KeyboardInterrupt:
3458 try:
3388 try:
3459 u.warn(_("interrupted!\n"))
3389 u.warn(_("interrupted!\n"))
3460 except IOError, inst:
3390 except IOError, inst:
3461 if inst.errno == errno.EPIPE:
3391 if inst.errno == errno.EPIPE:
3462 if u.debugflag:
3392 if u.debugflag:
3463 u.warn(_("\nbroken pipe\n"))
3393 u.warn(_("\nbroken pipe\n"))
3464 else:
3394 else:
3465 raise
3395 raise
3466 except IOError, inst:
3396 except IOError, inst:
3467 if hasattr(inst, "code"):
3397 if hasattr(inst, "code"):
3468 u.warn(_("abort: %s\n") % inst)
3398 u.warn(_("abort: %s\n") % inst)
3469 elif hasattr(inst, "reason"):
3399 elif hasattr(inst, "reason"):
3470 u.warn(_("abort: error: %s\n") % inst.reason[1])
3400 u.warn(_("abort: error: %s\n") % inst.reason[1])
3471 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3401 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3472 if u.debugflag:
3402 if u.debugflag:
3473 u.warn(_("broken pipe\n"))
3403 u.warn(_("broken pipe\n"))
3474 elif getattr(inst, "strerror", None):
3404 elif getattr(inst, "strerror", None):
3475 if getattr(inst, "filename", None):
3405 if getattr(inst, "filename", None):
3476 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3406 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3477 else:
3407 else:
3478 u.warn(_("abort: %s\n") % inst.strerror)
3408 u.warn(_("abort: %s\n") % inst.strerror)
3479 else:
3409 else:
3480 raise
3410 raise
3481 except OSError, inst:
3411 except OSError, inst:
3482 if getattr(inst, "filename", None):
3412 if getattr(inst, "filename", None):
3483 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3413 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3484 else:
3414 else:
3485 u.warn(_("abort: %s\n") % inst.strerror)
3415 u.warn(_("abort: %s\n") % inst.strerror)
3486 except util.Abort, inst:
3416 except util.Abort, inst:
3487 u.warn(_("abort: %s\n") % inst)
3417 u.warn(_("abort: %s\n") % inst)
3488 except TypeError, inst:
3418 except TypeError, inst:
3489 # was this an argument error?
3419 # was this an argument error?
3490 tb = traceback.extract_tb(sys.exc_info()[2])
3420 tb = traceback.extract_tb(sys.exc_info()[2])
3491 if len(tb) > 2: # no
3421 if len(tb) > 2: # no
3492 raise
3422 raise
3493 u.debug(inst, "\n")
3423 u.debug(inst, "\n")
3494 u.warn(_("%s: invalid arguments\n") % cmd)
3424 u.warn(_("%s: invalid arguments\n") % cmd)
3495 help_(u, cmd)
3425 help_(u, cmd)
3496 except SystemExit, inst:
3426 except SystemExit, inst:
3497 # Commands shouldn't sys.exit directly, but give a return code.
3427 # Commands shouldn't sys.exit directly, but give a return code.
3498 # Just in case catch this and and pass exit code to caller.
3428 # Just in case catch this and and pass exit code to caller.
3499 return inst.code
3429 return inst.code
3500 except:
3430 except:
3501 u.warn(_("** unknown exception encountered, details follow\n"))
3431 u.warn(_("** unknown exception encountered, details follow\n"))
3502 u.warn(_("** report bug details to "
3432 u.warn(_("** report bug details to "
3503 "http://www.selenic.com/mercurial/bts\n"))
3433 "http://www.selenic.com/mercurial/bts\n"))
3504 u.warn(_("** or mercurial@selenic.com\n"))
3434 u.warn(_("** or mercurial@selenic.com\n"))
3505 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3435 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3506 % version.get_version())
3436 % version.get_version())
3507 raise
3437 raise
3508
3438
3509 return -1
3439 return -1
General Comments 0
You need to be logged in to leave comments. Login now