##// END OF EJS Templates
doc: use double quotation mark to quote arguments in examples for Windows users...
FUJIWARA Katsunori -
r19959:9ef92384 stable
parent child Browse files
Show More
@@ -1,204 +1,204 b''
1 # churn.py - create a graph of revisions count grouped by template
1 # churn.py - create a graph of revisions count grouped by template
2 #
2 #
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 '''command to display statistics about repository history'''
9 '''command to display statistics about repository history'''
10
10
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 from mercurial import patch, cmdutil, scmutil, util, templater, commands
12 from mercurial import patch, cmdutil, scmutil, util, templater, commands
13 import os
13 import os
14 import time, datetime
14 import time, datetime
15
15
16 testedwith = 'internal'
16 testedwith = 'internal'
17
17
18 def maketemplater(ui, repo, tmpl):
18 def maketemplater(ui, repo, tmpl):
19 tmpl = templater.parsestring(tmpl, quoted=False)
19 tmpl = templater.parsestring(tmpl, quoted=False)
20 try:
20 try:
21 t = cmdutil.changeset_templater(ui, repo, False, None, None, False)
21 t = cmdutil.changeset_templater(ui, repo, False, None, None, False)
22 except SyntaxError, inst:
22 except SyntaxError, inst:
23 raise util.Abort(inst.args[0])
23 raise util.Abort(inst.args[0])
24 t.use_template(tmpl)
24 t.use_template(tmpl)
25 return t
25 return t
26
26
27 def changedlines(ui, repo, ctx1, ctx2, fns):
27 def changedlines(ui, repo, ctx1, ctx2, fns):
28 added, removed = 0, 0
28 added, removed = 0, 0
29 fmatch = scmutil.matchfiles(repo, fns)
29 fmatch = scmutil.matchfiles(repo, fns)
30 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
30 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch))
31 for l in diff.split('\n'):
31 for l in diff.split('\n'):
32 if l.startswith("+") and not l.startswith("+++ "):
32 if l.startswith("+") and not l.startswith("+++ "):
33 added += 1
33 added += 1
34 elif l.startswith("-") and not l.startswith("--- "):
34 elif l.startswith("-") and not l.startswith("--- "):
35 removed += 1
35 removed += 1
36 return (added, removed)
36 return (added, removed)
37
37
38 def countrate(ui, repo, amap, *pats, **opts):
38 def countrate(ui, repo, amap, *pats, **opts):
39 """Calculate stats"""
39 """Calculate stats"""
40 if opts.get('dateformat'):
40 if opts.get('dateformat'):
41 def getkey(ctx):
41 def getkey(ctx):
42 t, tz = ctx.date()
42 t, tz = ctx.date()
43 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
43 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
44 return date.strftime(opts['dateformat'])
44 return date.strftime(opts['dateformat'])
45 else:
45 else:
46 tmpl = opts.get('template', '{author|email}')
46 tmpl = opts.get('template', '{author|email}')
47 tmpl = maketemplater(ui, repo, tmpl)
47 tmpl = maketemplater(ui, repo, tmpl)
48 def getkey(ctx):
48 def getkey(ctx):
49 ui.pushbuffer()
49 ui.pushbuffer()
50 tmpl.show(ctx)
50 tmpl.show(ctx)
51 return ui.popbuffer()
51 return ui.popbuffer()
52
52
53 state = {'count': 0}
53 state = {'count': 0}
54 rate = {}
54 rate = {}
55 df = False
55 df = False
56 if opts.get('date'):
56 if opts.get('date'):
57 df = util.matchdate(opts['date'])
57 df = util.matchdate(opts['date'])
58
58
59 m = scmutil.match(repo[None], pats, opts)
59 m = scmutil.match(repo[None], pats, opts)
60 def prep(ctx, fns):
60 def prep(ctx, fns):
61 rev = ctx.rev()
61 rev = ctx.rev()
62 if df and not df(ctx.date()[0]): # doesn't match date format
62 if df and not df(ctx.date()[0]): # doesn't match date format
63 return
63 return
64
64
65 key = getkey(ctx).strip()
65 key = getkey(ctx).strip()
66 key = amap.get(key, key) # alias remap
66 key = amap.get(key, key) # alias remap
67 if opts.get('changesets'):
67 if opts.get('changesets'):
68 rate[key] = (rate.get(key, (0,))[0] + 1, 0)
68 rate[key] = (rate.get(key, (0,))[0] + 1, 0)
69 else:
69 else:
70 parents = ctx.parents()
70 parents = ctx.parents()
71 if len(parents) > 1:
71 if len(parents) > 1:
72 ui.note(_('revision %d is a merge, ignoring...\n') % (rev,))
72 ui.note(_('revision %d is a merge, ignoring...\n') % (rev,))
73 return
73 return
74
74
75 ctx1 = parents[0]
75 ctx1 = parents[0]
76 lines = changedlines(ui, repo, ctx1, ctx, fns)
76 lines = changedlines(ui, repo, ctx1, ctx, fns)
77 rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
77 rate[key] = [r + l for r, l in zip(rate.get(key, (0, 0)), lines)]
78
78
79 state['count'] += 1
79 state['count'] += 1
80 ui.progress(_('analyzing'), state['count'], total=len(repo))
80 ui.progress(_('analyzing'), state['count'], total=len(repo))
81
81
82 for ctx in cmdutil.walkchangerevs(repo, m, opts, prep):
82 for ctx in cmdutil.walkchangerevs(repo, m, opts, prep):
83 continue
83 continue
84
84
85 ui.progress(_('analyzing'), None)
85 ui.progress(_('analyzing'), None)
86
86
87 return rate
87 return rate
88
88
89
89
90 def churn(ui, repo, *pats, **opts):
90 def churn(ui, repo, *pats, **opts):
91 '''histogram of changes to the repository
91 '''histogram of changes to the repository
92
92
93 This command will display a histogram representing the number
93 This command will display a histogram representing the number
94 of changed lines or revisions, grouped according to the given
94 of changed lines or revisions, grouped according to the given
95 template. The default template will group changes by author.
95 template. The default template will group changes by author.
96 The --dateformat option may be used to group the results by
96 The --dateformat option may be used to group the results by
97 date instead.
97 date instead.
98
98
99 Statistics are based on the number of changed lines, or
99 Statistics are based on the number of changed lines, or
100 alternatively the number of matching revisions if the
100 alternatively the number of matching revisions if the
101 --changesets option is specified.
101 --changesets option is specified.
102
102
103 Examples::
103 Examples::
104
104
105 # display count of changed lines for every committer
105 # display count of changed lines for every committer
106 hg churn -t '{author|email}'
106 hg churn -t "{author|email}"
107
107
108 # display daily activity graph
108 # display daily activity graph
109 hg churn -f '%H' -s -c
109 hg churn -f "%H" -s -c
110
110
111 # display activity of developers by month
111 # display activity of developers by month
112 hg churn -f '%Y-%m' -s -c
112 hg churn -f "%Y-%m" -s -c
113
113
114 # display count of lines changed in every year
114 # display count of lines changed in every year
115 hg churn -f '%Y' -s
115 hg churn -f "%Y" -s
116
116
117 It is possible to map alternate email addresses to a main address
117 It is possible to map alternate email addresses to a main address
118 by providing a file using the following format::
118 by providing a file using the following format::
119
119
120 <alias email> = <actual email>
120 <alias email> = <actual email>
121
121
122 Such a file may be specified with the --aliases option, otherwise
122 Such a file may be specified with the --aliases option, otherwise
123 a .hgchurn file will be looked for in the working directory root.
123 a .hgchurn file will be looked for in the working directory root.
124 Aliases will be split from the rightmost "=".
124 Aliases will be split from the rightmost "=".
125 '''
125 '''
126 def pad(s, l):
126 def pad(s, l):
127 return (s + " " * l)[:l]
127 return (s + " " * l)[:l]
128
128
129 amap = {}
129 amap = {}
130 aliases = opts.get('aliases')
130 aliases = opts.get('aliases')
131 if not aliases and os.path.exists(repo.wjoin('.hgchurn')):
131 if not aliases and os.path.exists(repo.wjoin('.hgchurn')):
132 aliases = repo.wjoin('.hgchurn')
132 aliases = repo.wjoin('.hgchurn')
133 if aliases:
133 if aliases:
134 for l in open(aliases, "r"):
134 for l in open(aliases, "r"):
135 try:
135 try:
136 alias, actual = l.rsplit('=' in l and '=' or None, 1)
136 alias, actual = l.rsplit('=' in l and '=' or None, 1)
137 amap[alias.strip()] = actual.strip()
137 amap[alias.strip()] = actual.strip()
138 except ValueError:
138 except ValueError:
139 l = l.strip()
139 l = l.strip()
140 if l:
140 if l:
141 ui.warn(_("skipping malformed alias: %s\n") % l)
141 ui.warn(_("skipping malformed alias: %s\n") % l)
142 continue
142 continue
143
143
144 rate = countrate(ui, repo, amap, *pats, **opts).items()
144 rate = countrate(ui, repo, amap, *pats, **opts).items()
145 if not rate:
145 if not rate:
146 return
146 return
147
147
148 if opts.get('sort'):
148 if opts.get('sort'):
149 rate.sort()
149 rate.sort()
150 else:
150 else:
151 rate.sort(key=lambda x: (-sum(x[1]), x))
151 rate.sort(key=lambda x: (-sum(x[1]), x))
152
152
153 # Be careful not to have a zero maxcount (issue833)
153 # Be careful not to have a zero maxcount (issue833)
154 maxcount = float(max(sum(v) for k, v in rate)) or 1.0
154 maxcount = float(max(sum(v) for k, v in rate)) or 1.0
155 maxname = max(len(k) for k, v in rate)
155 maxname = max(len(k) for k, v in rate)
156
156
157 ttywidth = ui.termwidth()
157 ttywidth = ui.termwidth()
158 ui.debug("assuming %i character terminal\n" % ttywidth)
158 ui.debug("assuming %i character terminal\n" % ttywidth)
159 width = ttywidth - maxname - 2 - 2 - 2
159 width = ttywidth - maxname - 2 - 2 - 2
160
160
161 if opts.get('diffstat'):
161 if opts.get('diffstat'):
162 width -= 15
162 width -= 15
163 def format(name, diffstat):
163 def format(name, diffstat):
164 added, removed = diffstat
164 added, removed = diffstat
165 return "%s %15s %s%s\n" % (pad(name, maxname),
165 return "%s %15s %s%s\n" % (pad(name, maxname),
166 '+%d/-%d' % (added, removed),
166 '+%d/-%d' % (added, removed),
167 ui.label('+' * charnum(added),
167 ui.label('+' * charnum(added),
168 'diffstat.inserted'),
168 'diffstat.inserted'),
169 ui.label('-' * charnum(removed),
169 ui.label('-' * charnum(removed),
170 'diffstat.deleted'))
170 'diffstat.deleted'))
171 else:
171 else:
172 width -= 6
172 width -= 6
173 def format(name, count):
173 def format(name, count):
174 return "%s %6d %s\n" % (pad(name, maxname), sum(count),
174 return "%s %6d %s\n" % (pad(name, maxname), sum(count),
175 '*' * charnum(sum(count)))
175 '*' * charnum(sum(count)))
176
176
177 def charnum(count):
177 def charnum(count):
178 return int(round(count * width / maxcount))
178 return int(round(count * width / maxcount))
179
179
180 for name, count in rate:
180 for name, count in rate:
181 ui.write(format(name, count))
181 ui.write(format(name, count))
182
182
183
183
184 cmdtable = {
184 cmdtable = {
185 "churn":
185 "churn":
186 (churn,
186 (churn,
187 [('r', 'rev', [],
187 [('r', 'rev', [],
188 _('count rate for the specified revision or range'), _('REV')),
188 _('count rate for the specified revision or range'), _('REV')),
189 ('d', 'date', '',
189 ('d', 'date', '',
190 _('count rate for revisions matching date spec'), _('DATE')),
190 _('count rate for revisions matching date spec'), _('DATE')),
191 ('t', 'template', '{author|email}',
191 ('t', 'template', '{author|email}',
192 _('template to group changesets'), _('TEMPLATE')),
192 _('template to group changesets'), _('TEMPLATE')),
193 ('f', 'dateformat', '',
193 ('f', 'dateformat', '',
194 _('strftime-compatible format for grouping by date'), _('FORMAT')),
194 _('strftime-compatible format for grouping by date'), _('FORMAT')),
195 ('c', 'changesets', False, _('count rate by number of changesets')),
195 ('c', 'changesets', False, _('count rate by number of changesets')),
196 ('s', 'sort', False, _('sort by key (default: sort by count)')),
196 ('s', 'sort', False, _('sort by key (default: sort by count)')),
197 ('', 'diffstat', False, _('display added/removed lines separately')),
197 ('', 'diffstat', False, _('display added/removed lines separately')),
198 ('', 'aliases', '',
198 ('', 'aliases', '',
199 _('file with email aliases'), _('FILE')),
199 _('file with email aliases'), _('FILE')),
200 ] + commands.walkopts,
200 ] + commands.walkopts,
201 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]")),
201 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]")),
202 }
202 }
203
203
204 commands.inferrepo += " churn"
204 commands.inferrepo += " churn"
@@ -1,5918 +1,5918 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, commandserver
15 import sshserver, hgweb, commandserver
16 from hgweb import server as hgweb_server
16 from hgweb import server as hgweb_server
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge, graphmod
19 import dagparser, context, simplemerge, graphmod
20 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
21 import phases, obsolete
21 import phases, obsolete
22
22
23 table = {}
23 table = {}
24
24
25 command = cmdutil.command(table)
25 command = cmdutil.command(table)
26
26
27 # common command options
27 # common command options
28
28
29 globalopts = [
29 globalopts = [
30 ('R', 'repository', '',
30 ('R', 'repository', '',
31 _('repository root directory or name of overlay bundle file'),
31 _('repository root directory or name of overlay bundle file'),
32 _('REPO')),
32 _('REPO')),
33 ('', 'cwd', '',
33 ('', 'cwd', '',
34 _('change working directory'), _('DIR')),
34 _('change working directory'), _('DIR')),
35 ('y', 'noninteractive', None,
35 ('y', 'noninteractive', None,
36 _('do not prompt, automatically pick the first choice for all prompts')),
36 _('do not prompt, automatically pick the first choice for all prompts')),
37 ('q', 'quiet', None, _('suppress output')),
37 ('q', 'quiet', None, _('suppress output')),
38 ('v', 'verbose', None, _('enable additional output')),
38 ('v', 'verbose', None, _('enable additional output')),
39 ('', 'config', [],
39 ('', 'config', [],
40 _('set/override config option (use \'section.name=value\')'),
40 _('set/override config option (use \'section.name=value\')'),
41 _('CONFIG')),
41 _('CONFIG')),
42 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debug', None, _('enable debugging output')),
43 ('', 'debugger', None, _('start debugger')),
43 ('', 'debugger', None, _('start debugger')),
44 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
45 _('ENCODE')),
45 _('ENCODE')),
46 ('', 'encodingmode', encoding.encodingmode,
46 ('', 'encodingmode', encoding.encodingmode,
47 _('set the charset encoding mode'), _('MODE')),
47 _('set the charset encoding mode'), _('MODE')),
48 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'traceback', None, _('always print a traceback on exception')),
49 ('', 'time', None, _('time how long the command takes')),
49 ('', 'time', None, _('time how long the command takes')),
50 ('', 'profile', None, _('print command execution profile')),
50 ('', 'profile', None, _('print command execution profile')),
51 ('', 'version', None, _('output version information and exit')),
51 ('', 'version', None, _('output version information and exit')),
52 ('h', 'help', None, _('display help and exit')),
52 ('h', 'help', None, _('display help and exit')),
53 ('', 'hidden', False, _('consider hidden changesets')),
53 ('', 'hidden', False, _('consider hidden changesets')),
54 ]
54 ]
55
55
56 dryrunopts = [('n', 'dry-run', None,
56 dryrunopts = [('n', 'dry-run', None,
57 _('do not perform actions, just print output'))]
57 _('do not perform actions, just print output'))]
58
58
59 remoteopts = [
59 remoteopts = [
60 ('e', 'ssh', '',
60 ('e', 'ssh', '',
61 _('specify ssh command to use'), _('CMD')),
61 _('specify ssh command to use'), _('CMD')),
62 ('', 'remotecmd', '',
62 ('', 'remotecmd', '',
63 _('specify hg command to run on the remote side'), _('CMD')),
63 _('specify hg command to run on the remote side'), _('CMD')),
64 ('', 'insecure', None,
64 ('', 'insecure', None,
65 _('do not verify server certificate (ignoring web.cacerts config)')),
65 _('do not verify server certificate (ignoring web.cacerts config)')),
66 ]
66 ]
67
67
68 walkopts = [
68 walkopts = [
69 ('I', 'include', [],
69 ('I', 'include', [],
70 _('include names matching the given patterns'), _('PATTERN')),
70 _('include names matching the given patterns'), _('PATTERN')),
71 ('X', 'exclude', [],
71 ('X', 'exclude', [],
72 _('exclude names matching the given patterns'), _('PATTERN')),
72 _('exclude names matching the given patterns'), _('PATTERN')),
73 ]
73 ]
74
74
75 commitopts = [
75 commitopts = [
76 ('m', 'message', '',
76 ('m', 'message', '',
77 _('use text as commit message'), _('TEXT')),
77 _('use text as commit message'), _('TEXT')),
78 ('l', 'logfile', '',
78 ('l', 'logfile', '',
79 _('read commit message from file'), _('FILE')),
79 _('read commit message from file'), _('FILE')),
80 ]
80 ]
81
81
82 commitopts2 = [
82 commitopts2 = [
83 ('d', 'date', '',
83 ('d', 'date', '',
84 _('record the specified date as commit date'), _('DATE')),
84 _('record the specified date as commit date'), _('DATE')),
85 ('u', 'user', '',
85 ('u', 'user', '',
86 _('record the specified user as committer'), _('USER')),
86 _('record the specified user as committer'), _('USER')),
87 ]
87 ]
88
88
89 templateopts = [
89 templateopts = [
90 ('', 'style', '',
90 ('', 'style', '',
91 _('display using template map file'), _('STYLE')),
91 _('display using template map file'), _('STYLE')),
92 ('', 'template', '',
92 ('', 'template', '',
93 _('display with template'), _('TEMPLATE')),
93 _('display with template'), _('TEMPLATE')),
94 ]
94 ]
95
95
96 logopts = [
96 logopts = [
97 ('p', 'patch', None, _('show patch')),
97 ('p', 'patch', None, _('show patch')),
98 ('g', 'git', None, _('use git extended diff format')),
98 ('g', 'git', None, _('use git extended diff format')),
99 ('l', 'limit', '',
99 ('l', 'limit', '',
100 _('limit number of changes displayed'), _('NUM')),
100 _('limit number of changes displayed'), _('NUM')),
101 ('M', 'no-merges', None, _('do not show merges')),
101 ('M', 'no-merges', None, _('do not show merges')),
102 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('', 'stat', None, _('output diffstat-style summary of changes')),
103 ('G', 'graph', None, _("show the revision DAG")),
103 ('G', 'graph', None, _("show the revision DAG")),
104 ] + templateopts
104 ] + templateopts
105
105
106 diffopts = [
106 diffopts = [
107 ('a', 'text', None, _('treat all files as text')),
107 ('a', 'text', None, _('treat all files as text')),
108 ('g', 'git', None, _('use git extended diff format')),
108 ('g', 'git', None, _('use git extended diff format')),
109 ('', 'nodates', None, _('omit dates from diff headers'))
109 ('', 'nodates', None, _('omit dates from diff headers'))
110 ]
110 ]
111
111
112 diffwsopts = [
112 diffwsopts = [
113 ('w', 'ignore-all-space', None,
113 ('w', 'ignore-all-space', None,
114 _('ignore white space when comparing lines')),
114 _('ignore white space when comparing lines')),
115 ('b', 'ignore-space-change', None,
115 ('b', 'ignore-space-change', None,
116 _('ignore changes in the amount of white space')),
116 _('ignore changes in the amount of white space')),
117 ('B', 'ignore-blank-lines', None,
117 ('B', 'ignore-blank-lines', None,
118 _('ignore changes whose lines are all blank')),
118 _('ignore changes whose lines are all blank')),
119 ]
119 ]
120
120
121 diffopts2 = [
121 diffopts2 = [
122 ('p', 'show-function', None, _('show which function each change is in')),
122 ('p', 'show-function', None, _('show which function each change is in')),
123 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ('', 'reverse', None, _('produce a diff that undoes the changes')),
124 ] + diffwsopts + [
124 ] + diffwsopts + [
125 ('U', 'unified', '',
125 ('U', 'unified', '',
126 _('number of lines of context to show'), _('NUM')),
126 _('number of lines of context to show'), _('NUM')),
127 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ('', 'stat', None, _('output diffstat-style summary of changes')),
128 ]
128 ]
129
129
130 mergetoolopts = [
130 mergetoolopts = [
131 ('t', 'tool', '', _('specify merge tool')),
131 ('t', 'tool', '', _('specify merge tool')),
132 ]
132 ]
133
133
134 similarityopts = [
134 similarityopts = [
135 ('s', 'similarity', '',
135 ('s', 'similarity', '',
136 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
137 ]
137 ]
138
138
139 subrepoopts = [
139 subrepoopts = [
140 ('S', 'subrepos', None,
140 ('S', 'subrepos', None,
141 _('recurse into subrepositories'))
141 _('recurse into subrepositories'))
142 ]
142 ]
143
143
144 # Commands start here, listed alphabetically
144 # Commands start here, listed alphabetically
145
145
146 @command('^add',
146 @command('^add',
147 walkopts + subrepoopts + dryrunopts,
147 walkopts + subrepoopts + dryrunopts,
148 _('[OPTION]... [FILE]...'))
148 _('[OPTION]... [FILE]...'))
149 def add(ui, repo, *pats, **opts):
149 def add(ui, repo, *pats, **opts):
150 """add the specified files on the next commit
150 """add the specified files on the next commit
151
151
152 Schedule files to be version controlled and added to the
152 Schedule files to be version controlled and added to the
153 repository.
153 repository.
154
154
155 The files will be added to the repository at the next commit. To
155 The files will be added to the repository at the next commit. To
156 undo an add before that, see :hg:`forget`.
156 undo an add before that, see :hg:`forget`.
157
157
158 If no names are given, add all files to the repository.
158 If no names are given, add all files to the repository.
159
159
160 .. container:: verbose
160 .. container:: verbose
161
161
162 An example showing how new (unknown) files are added
162 An example showing how new (unknown) files are added
163 automatically by :hg:`add`::
163 automatically by :hg:`add`::
164
164
165 $ ls
165 $ ls
166 foo.c
166 foo.c
167 $ hg status
167 $ hg status
168 ? foo.c
168 ? foo.c
169 $ hg add
169 $ hg add
170 adding foo.c
170 adding foo.c
171 $ hg status
171 $ hg status
172 A foo.c
172 A foo.c
173
173
174 Returns 0 if all files are successfully added.
174 Returns 0 if all files are successfully added.
175 """
175 """
176
176
177 m = scmutil.match(repo[None], pats, opts)
177 m = scmutil.match(repo[None], pats, opts)
178 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
179 opts.get('subrepos'), prefix="", explicitonly=False)
179 opts.get('subrepos'), prefix="", explicitonly=False)
180 return rejected and 1 or 0
180 return rejected and 1 or 0
181
181
182 @command('addremove',
182 @command('addremove',
183 similarityopts + walkopts + dryrunopts,
183 similarityopts + walkopts + dryrunopts,
184 _('[OPTION]... [FILE]...'))
184 _('[OPTION]... [FILE]...'))
185 def addremove(ui, repo, *pats, **opts):
185 def addremove(ui, repo, *pats, **opts):
186 """add all new files, delete all missing files
186 """add all new files, delete all missing files
187
187
188 Add all new files and remove all missing files from the
188 Add all new files and remove all missing files from the
189 repository.
189 repository.
190
190
191 New files are ignored if they match any of the patterns in
191 New files are ignored if they match any of the patterns in
192 ``.hgignore``. As with add, these changes take effect at the next
192 ``.hgignore``. As with add, these changes take effect at the next
193 commit.
193 commit.
194
194
195 Use the -s/--similarity option to detect renamed files. This
195 Use the -s/--similarity option to detect renamed files. This
196 option takes a percentage between 0 (disabled) and 100 (files must
196 option takes a percentage between 0 (disabled) and 100 (files must
197 be identical) as its parameter. With a parameter greater than 0,
197 be identical) as its parameter. With a parameter greater than 0,
198 this compares every removed file with every added file and records
198 this compares every removed file with every added file and records
199 those similar enough as renames. Detecting renamed files this way
199 those similar enough as renames. Detecting renamed files this way
200 can be expensive. After using this option, :hg:`status -C` can be
200 can be expensive. After using this option, :hg:`status -C` can be
201 used to check which files were identified as moved or renamed. If
201 used to check which files were identified as moved or renamed. If
202 not specified, -s/--similarity defaults to 100 and only renames of
202 not specified, -s/--similarity defaults to 100 and only renames of
203 identical files are detected.
203 identical files are detected.
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207 try:
207 try:
208 sim = float(opts.get('similarity') or 100)
208 sim = float(opts.get('similarity') or 100)
209 except ValueError:
209 except ValueError:
210 raise util.Abort(_('similarity must be a number'))
210 raise util.Abort(_('similarity must be a number'))
211 if sim < 0 or sim > 100:
211 if sim < 0 or sim > 100:
212 raise util.Abort(_('similarity must be between 0 and 100'))
212 raise util.Abort(_('similarity must be between 0 and 100'))
213 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
214
214
215 @command('^annotate|blame',
215 @command('^annotate|blame',
216 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
217 ('', 'follow', None,
217 ('', 'follow', None,
218 _('follow copies/renames and list the filename (DEPRECATED)')),
218 _('follow copies/renames and list the filename (DEPRECATED)')),
219 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('', 'no-follow', None, _("don't follow copies and renames")),
220 ('a', 'text', None, _('treat all files as text')),
220 ('a', 'text', None, _('treat all files as text')),
221 ('u', 'user', None, _('list the author (long with -v)')),
221 ('u', 'user', None, _('list the author (long with -v)')),
222 ('f', 'file', None, _('list the filename')),
222 ('f', 'file', None, _('list the filename')),
223 ('d', 'date', None, _('list the date (short with -q)')),
223 ('d', 'date', None, _('list the date (short with -q)')),
224 ('n', 'number', None, _('list the revision number (default)')),
224 ('n', 'number', None, _('list the revision number (default)')),
225 ('c', 'changeset', None, _('list the changeset')),
225 ('c', 'changeset', None, _('list the changeset')),
226 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ('l', 'line-number', None, _('show line number at the first appearance'))
227 ] + diffwsopts + walkopts,
227 ] + diffwsopts + walkopts,
228 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
229 def annotate(ui, repo, *pats, **opts):
229 def annotate(ui, repo, *pats, **opts):
230 """show changeset information by line for each file
230 """show changeset information by line for each file
231
231
232 List changes in files, showing the revision id responsible for
232 List changes in files, showing the revision id responsible for
233 each line
233 each line
234
234
235 This command is useful for discovering when a change was made and
235 This command is useful for discovering when a change was made and
236 by whom.
236 by whom.
237
237
238 Without the -a/--text option, annotate will avoid processing files
238 Without the -a/--text option, annotate will avoid processing files
239 it detects as binary. With -a, annotate will annotate the file
239 it detects as binary. With -a, annotate will annotate the file
240 anyway, although the results will probably be neither useful
240 anyway, although the results will probably be neither useful
241 nor desirable.
241 nor desirable.
242
242
243 Returns 0 on success.
243 Returns 0 on success.
244 """
244 """
245 if opts.get('follow'):
245 if opts.get('follow'):
246 # --follow is deprecated and now just an alias for -f/--file
246 # --follow is deprecated and now just an alias for -f/--file
247 # to mimic the behavior of Mercurial before version 1.5
247 # to mimic the behavior of Mercurial before version 1.5
248 opts['file'] = True
248 opts['file'] = True
249
249
250 datefunc = ui.quiet and util.shortdate or util.datestr
250 datefunc = ui.quiet and util.shortdate or util.datestr
251 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
252
252
253 if not pats:
253 if not pats:
254 raise util.Abort(_('at least one filename or pattern is required'))
254 raise util.Abort(_('at least one filename or pattern is required'))
255
255
256 hexfn = ui.debugflag and hex or short
256 hexfn = ui.debugflag and hex or short
257
257
258 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
259 ('number', ' ', lambda x: str(x[0].rev())),
259 ('number', ' ', lambda x: str(x[0].rev())),
260 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('changeset', ' ', lambda x: hexfn(x[0].node())),
261 ('date', ' ', getdate),
261 ('date', ' ', getdate),
262 ('file', ' ', lambda x: x[0].path()),
262 ('file', ' ', lambda x: x[0].path()),
263 ('line_number', ':', lambda x: str(x[1])),
263 ('line_number', ':', lambda x: str(x[1])),
264 ]
264 ]
265
265
266 if (not opts.get('user') and not opts.get('changeset')
266 if (not opts.get('user') and not opts.get('changeset')
267 and not opts.get('date') and not opts.get('file')):
267 and not opts.get('date') and not opts.get('file')):
268 opts['number'] = True
268 opts['number'] = True
269
269
270 linenumber = opts.get('line_number') is not None
270 linenumber = opts.get('line_number') is not None
271 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
272 raise util.Abort(_('at least one of -n/-c is required for -l'))
272 raise util.Abort(_('at least one of -n/-c is required for -l'))
273
273
274 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
275 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
276
276
277 def bad(x, y):
277 def bad(x, y):
278 raise util.Abort("%s: %s" % (x, y))
278 raise util.Abort("%s: %s" % (x, y))
279
279
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
281 m = scmutil.match(ctx, pats, opts)
281 m = scmutil.match(ctx, pats, opts)
282 m.bad = bad
282 m.bad = bad
283 follow = not opts.get('no_follow')
283 follow = not opts.get('no_follow')
284 diffopts = patch.diffopts(ui, opts, section='annotate')
284 diffopts = patch.diffopts(ui, opts, section='annotate')
285 for abs in ctx.walk(m):
285 for abs in ctx.walk(m):
286 fctx = ctx[abs]
286 fctx = ctx[abs]
287 if not opts.get('text') and util.binary(fctx.data()):
287 if not opts.get('text') and util.binary(fctx.data()):
288 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
289 continue
289 continue
290
290
291 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 lines = fctx.annotate(follow=follow, linenumber=linenumber,
292 diffopts=diffopts)
292 diffopts=diffopts)
293 pieces = []
293 pieces = []
294
294
295 for f, sep in funcmap:
295 for f, sep in funcmap:
296 l = [f(n) for n, dummy in lines]
296 l = [f(n) for n, dummy in lines]
297 if l:
297 if l:
298 sized = [(x, encoding.colwidth(x)) for x in l]
298 sized = [(x, encoding.colwidth(x)) for x in l]
299 ml = max([w for x, w in sized])
299 ml = max([w for x, w in sized])
300 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
301 for x, w in sized])
301 for x, w in sized])
302
302
303 if pieces:
303 if pieces:
304 for p, l in zip(zip(*pieces), lines):
304 for p, l in zip(zip(*pieces), lines):
305 ui.write("%s: %s" % ("".join(p), l[1]))
305 ui.write("%s: %s" % ("".join(p), l[1]))
306
306
307 if lines and not lines[-1][1].endswith('\n'):
307 if lines and not lines[-1][1].endswith('\n'):
308 ui.write('\n')
308 ui.write('\n')
309
309
310 @command('archive',
310 @command('archive',
311 [('', 'no-decode', None, _('do not pass files through decoders')),
311 [('', 'no-decode', None, _('do not pass files through decoders')),
312 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 ('p', 'prefix', '', _('directory prefix for files in archive'),
313 _('PREFIX')),
313 _('PREFIX')),
314 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('r', 'rev', '', _('revision to distribute'), _('REV')),
315 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
316 ] + subrepoopts + walkopts,
316 ] + subrepoopts + walkopts,
317 _('[OPTION]... DEST'))
317 _('[OPTION]... DEST'))
318 def archive(ui, repo, dest, **opts):
318 def archive(ui, repo, dest, **opts):
319 '''create an unversioned archive of a repository revision
319 '''create an unversioned archive of a repository revision
320
320
321 By default, the revision used is the parent of the working
321 By default, the revision used is the parent of the working
322 directory; use -r/--rev to specify a different revision.
322 directory; use -r/--rev to specify a different revision.
323
323
324 The archive type is automatically detected based on file
324 The archive type is automatically detected based on file
325 extension (or override using -t/--type).
325 extension (or override using -t/--type).
326
326
327 .. container:: verbose
327 .. container:: verbose
328
328
329 Examples:
329 Examples:
330
330
331 - create a zip file containing the 1.0 release::
331 - create a zip file containing the 1.0 release::
332
332
333 hg archive -r 1.0 project-1.0.zip
333 hg archive -r 1.0 project-1.0.zip
334
334
335 - create a tarball excluding .hg files::
335 - create a tarball excluding .hg files::
336
336
337 hg archive project.tar.gz -X ".hg*"
337 hg archive project.tar.gz -X ".hg*"
338
338
339 Valid types are:
339 Valid types are:
340
340
341 :``files``: a directory full of files (default)
341 :``files``: a directory full of files (default)
342 :``tar``: tar archive, uncompressed
342 :``tar``: tar archive, uncompressed
343 :``tbz2``: tar archive, compressed using bzip2
343 :``tbz2``: tar archive, compressed using bzip2
344 :``tgz``: tar archive, compressed using gzip
344 :``tgz``: tar archive, compressed using gzip
345 :``uzip``: zip archive, uncompressed
345 :``uzip``: zip archive, uncompressed
346 :``zip``: zip archive, compressed using deflate
346 :``zip``: zip archive, compressed using deflate
347
347
348 The exact name of the destination archive or directory is given
348 The exact name of the destination archive or directory is given
349 using a format string; see :hg:`help export` for details.
349 using a format string; see :hg:`help export` for details.
350
350
351 Each member added to an archive file has a directory prefix
351 Each member added to an archive file has a directory prefix
352 prepended. Use -p/--prefix to specify a format string for the
352 prepended. Use -p/--prefix to specify a format string for the
353 prefix. The default is the basename of the archive, with suffixes
353 prefix. The default is the basename of the archive, with suffixes
354 removed.
354 removed.
355
355
356 Returns 0 on success.
356 Returns 0 on success.
357 '''
357 '''
358
358
359 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 ctx = scmutil.revsingle(repo, opts.get('rev'))
360 if not ctx:
360 if not ctx:
361 raise util.Abort(_('no working directory: please specify a revision'))
361 raise util.Abort(_('no working directory: please specify a revision'))
362 node = ctx.node()
362 node = ctx.node()
363 dest = cmdutil.makefilename(repo, dest, node)
363 dest = cmdutil.makefilename(repo, dest, node)
364 if os.path.realpath(dest) == repo.root:
364 if os.path.realpath(dest) == repo.root:
365 raise util.Abort(_('repository root cannot be destination'))
365 raise util.Abort(_('repository root cannot be destination'))
366
366
367 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 kind = opts.get('type') or archival.guesskind(dest) or 'files'
368 prefix = opts.get('prefix')
368 prefix = opts.get('prefix')
369
369
370 if dest == '-':
370 if dest == '-':
371 if kind == 'files':
371 if kind == 'files':
372 raise util.Abort(_('cannot archive plain files to stdout'))
372 raise util.Abort(_('cannot archive plain files to stdout'))
373 dest = cmdutil.makefileobj(repo, dest)
373 dest = cmdutil.makefileobj(repo, dest)
374 if not prefix:
374 if not prefix:
375 prefix = os.path.basename(repo.root) + '-%h'
375 prefix = os.path.basename(repo.root) + '-%h'
376
376
377 prefix = cmdutil.makefilename(repo, prefix, node)
377 prefix = cmdutil.makefilename(repo, prefix, node)
378 matchfn = scmutil.match(ctx, [], opts)
378 matchfn = scmutil.match(ctx, [], opts)
379 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
380 matchfn, prefix, subrepos=opts.get('subrepos'))
380 matchfn, prefix, subrepos=opts.get('subrepos'))
381
381
382 @command('backout',
382 @command('backout',
383 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 [('', 'merge', None, _('merge with old dirstate parent after backout')),
384 ('', 'parent', '',
384 ('', 'parent', '',
385 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
386 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ('r', 'rev', '', _('revision to backout'), _('REV')),
387 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 ] + mergetoolopts + walkopts + commitopts + commitopts2,
388 _('[OPTION]... [-r] REV'))
388 _('[OPTION]... [-r] REV'))
389 def backout(ui, repo, node=None, rev=None, **opts):
389 def backout(ui, repo, node=None, rev=None, **opts):
390 '''reverse effect of earlier changeset
390 '''reverse effect of earlier changeset
391
391
392 Prepare a new changeset with the effect of REV undone in the
392 Prepare a new changeset with the effect of REV undone in the
393 current working directory.
393 current working directory.
394
394
395 If REV is the parent of the working directory, then this new changeset
395 If REV is the parent of the working directory, then this new changeset
396 is committed automatically. Otherwise, hg needs to merge the
396 is committed automatically. Otherwise, hg needs to merge the
397 changes and the merged result is left uncommitted.
397 changes and the merged result is left uncommitted.
398
398
399 .. note::
399 .. note::
400 backout cannot be used to fix either an unwanted or
400 backout cannot be used to fix either an unwanted or
401 incorrect merge.
401 incorrect merge.
402
402
403 .. container:: verbose
403 .. container:: verbose
404
404
405 By default, the pending changeset will have one parent,
405 By default, the pending changeset will have one parent,
406 maintaining a linear history. With --merge, the pending
406 maintaining a linear history. With --merge, the pending
407 changeset will instead have two parents: the old parent of the
407 changeset will instead have two parents: the old parent of the
408 working directory and a new child of REV that simply undoes REV.
408 working directory and a new child of REV that simply undoes REV.
409
409
410 Before version 1.7, the behavior without --merge was equivalent
410 Before version 1.7, the behavior without --merge was equivalent
411 to specifying --merge followed by :hg:`update --clean .` to
411 to specifying --merge followed by :hg:`update --clean .` to
412 cancel the merge and leave the child of REV as a head to be
412 cancel the merge and leave the child of REV as a head to be
413 merged separately.
413 merged separately.
414
414
415 See :hg:`help dates` for a list of formats valid for -d/--date.
415 See :hg:`help dates` for a list of formats valid for -d/--date.
416
416
417 Returns 0 on success.
417 Returns 0 on success.
418 '''
418 '''
419 if rev and node:
419 if rev and node:
420 raise util.Abort(_("please specify just one revision"))
420 raise util.Abort(_("please specify just one revision"))
421
421
422 if not rev:
422 if not rev:
423 rev = node
423 rev = node
424
424
425 if not rev:
425 if not rev:
426 raise util.Abort(_("please specify a revision to backout"))
426 raise util.Abort(_("please specify a revision to backout"))
427
427
428 date = opts.get('date')
428 date = opts.get('date')
429 if date:
429 if date:
430 opts['date'] = util.parsedate(date)
430 opts['date'] = util.parsedate(date)
431
431
432 cmdutil.checkunfinished(repo)
432 cmdutil.checkunfinished(repo)
433 cmdutil.bailifchanged(repo)
433 cmdutil.bailifchanged(repo)
434 node = scmutil.revsingle(repo, rev).node()
434 node = scmutil.revsingle(repo, rev).node()
435
435
436 op1, op2 = repo.dirstate.parents()
436 op1, op2 = repo.dirstate.parents()
437 a = repo.changelog.ancestor(op1, node)
437 a = repo.changelog.ancestor(op1, node)
438 if a != node:
438 if a != node:
439 raise util.Abort(_('cannot backout change on a different branch'))
439 raise util.Abort(_('cannot backout change on a different branch'))
440
440
441 p1, p2 = repo.changelog.parents(node)
441 p1, p2 = repo.changelog.parents(node)
442 if p1 == nullid:
442 if p1 == nullid:
443 raise util.Abort(_('cannot backout a change with no parents'))
443 raise util.Abort(_('cannot backout a change with no parents'))
444 if p2 != nullid:
444 if p2 != nullid:
445 if not opts.get('parent'):
445 if not opts.get('parent'):
446 raise util.Abort(_('cannot backout a merge changeset'))
446 raise util.Abort(_('cannot backout a merge changeset'))
447 p = repo.lookup(opts['parent'])
447 p = repo.lookup(opts['parent'])
448 if p not in (p1, p2):
448 if p not in (p1, p2):
449 raise util.Abort(_('%s is not a parent of %s') %
449 raise util.Abort(_('%s is not a parent of %s') %
450 (short(p), short(node)))
450 (short(p), short(node)))
451 parent = p
451 parent = p
452 else:
452 else:
453 if opts.get('parent'):
453 if opts.get('parent'):
454 raise util.Abort(_('cannot use --parent on non-merge changeset'))
454 raise util.Abort(_('cannot use --parent on non-merge changeset'))
455 parent = p1
455 parent = p1
456
456
457 # the backout should appear on the same branch
457 # the backout should appear on the same branch
458 wlock = repo.wlock()
458 wlock = repo.wlock()
459 try:
459 try:
460 branch = repo.dirstate.branch()
460 branch = repo.dirstate.branch()
461 bheads = repo.branchheads(branch)
461 bheads = repo.branchheads(branch)
462 hg.clean(repo, node, show_stats=False)
462 hg.clean(repo, node, show_stats=False)
463 repo.dirstate.setbranch(branch)
463 repo.dirstate.setbranch(branch)
464 rctx = scmutil.revsingle(repo, hex(parent))
464 rctx = scmutil.revsingle(repo, hex(parent))
465 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
465 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 e = cmdutil.commiteditor
473 e = cmdutil.commiteditor
474 if not opts['message'] and not opts['logfile']:
474 if not opts['message'] and not opts['logfile']:
475 # we don't translate commit messages
475 # we don't translate commit messages
476 opts['message'] = "Backed out changeset %s" % short(node)
476 opts['message'] = "Backed out changeset %s" % short(node)
477 e = cmdutil.commitforceeditor
477 e = cmdutil.commitforceeditor
478
478
479 def commitfunc(ui, repo, message, match, opts):
479 def commitfunc(ui, repo, message, match, opts):
480 return repo.commit(message, opts.get('user'), opts.get('date'),
480 return repo.commit(message, opts.get('user'), opts.get('date'),
481 match, editor=e)
481 match, editor=e)
482 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
482 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
483 cmdutil.commitstatus(repo, newnode, branch, bheads)
483 cmdutil.commitstatus(repo, newnode, branch, bheads)
484
484
485 def nice(node):
485 def nice(node):
486 return '%d:%s' % (repo.changelog.rev(node), short(node))
486 return '%d:%s' % (repo.changelog.rev(node), short(node))
487 ui.status(_('changeset %s backs out changeset %s\n') %
487 ui.status(_('changeset %s backs out changeset %s\n') %
488 (nice(repo.changelog.tip()), nice(node)))
488 (nice(repo.changelog.tip()), nice(node)))
489 if opts.get('merge') and op1 != node:
489 if opts.get('merge') and op1 != node:
490 hg.clean(repo, op1, show_stats=False)
490 hg.clean(repo, op1, show_stats=False)
491 ui.status(_('merging with changeset %s\n')
491 ui.status(_('merging with changeset %s\n')
492 % nice(repo.changelog.tip()))
492 % nice(repo.changelog.tip()))
493 try:
493 try:
494 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
494 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
495 return hg.merge(repo, hex(repo.changelog.tip()))
495 return hg.merge(repo, hex(repo.changelog.tip()))
496 finally:
496 finally:
497 ui.setconfig('ui', 'forcemerge', '')
497 ui.setconfig('ui', 'forcemerge', '')
498 finally:
498 finally:
499 wlock.release()
499 wlock.release()
500 return 0
500 return 0
501
501
502 @command('bisect',
502 @command('bisect',
503 [('r', 'reset', False, _('reset bisect state')),
503 [('r', 'reset', False, _('reset bisect state')),
504 ('g', 'good', False, _('mark changeset good')),
504 ('g', 'good', False, _('mark changeset good')),
505 ('b', 'bad', False, _('mark changeset bad')),
505 ('b', 'bad', False, _('mark changeset bad')),
506 ('s', 'skip', False, _('skip testing changeset')),
506 ('s', 'skip', False, _('skip testing changeset')),
507 ('e', 'extend', False, _('extend the bisect range')),
507 ('e', 'extend', False, _('extend the bisect range')),
508 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
508 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
509 ('U', 'noupdate', False, _('do not update to target'))],
509 ('U', 'noupdate', False, _('do not update to target'))],
510 _("[-gbsr] [-U] [-c CMD] [REV]"))
510 _("[-gbsr] [-U] [-c CMD] [REV]"))
511 def bisect(ui, repo, rev=None, extra=None, command=None,
511 def bisect(ui, repo, rev=None, extra=None, command=None,
512 reset=None, good=None, bad=None, skip=None, extend=None,
512 reset=None, good=None, bad=None, skip=None, extend=None,
513 noupdate=None):
513 noupdate=None):
514 """subdivision search of changesets
514 """subdivision search of changesets
515
515
516 This command helps to find changesets which introduce problems. To
516 This command helps to find changesets which introduce problems. To
517 use, mark the earliest changeset you know exhibits the problem as
517 use, mark the earliest changeset you know exhibits the problem as
518 bad, then mark the latest changeset which is free from the problem
518 bad, then mark the latest changeset which is free from the problem
519 as good. Bisect will update your working directory to a revision
519 as good. Bisect will update your working directory to a revision
520 for testing (unless the -U/--noupdate option is specified). Once
520 for testing (unless the -U/--noupdate option is specified). Once
521 you have performed tests, mark the working directory as good or
521 you have performed tests, mark the working directory as good or
522 bad, and bisect will either update to another candidate changeset
522 bad, and bisect will either update to another candidate changeset
523 or announce that it has found the bad revision.
523 or announce that it has found the bad revision.
524
524
525 As a shortcut, you can also use the revision argument to mark a
525 As a shortcut, you can also use the revision argument to mark a
526 revision as good or bad without checking it out first.
526 revision as good or bad without checking it out first.
527
527
528 If you supply a command, it will be used for automatic bisection.
528 If you supply a command, it will be used for automatic bisection.
529 The environment variable HG_NODE will contain the ID of the
529 The environment variable HG_NODE will contain the ID of the
530 changeset being tested. The exit status of the command will be
530 changeset being tested. The exit status of the command will be
531 used to mark revisions as good or bad: status 0 means good, 125
531 used to mark revisions as good or bad: status 0 means good, 125
532 means to skip the revision, 127 (command not found) will abort the
532 means to skip the revision, 127 (command not found) will abort the
533 bisection, and any other non-zero exit status means the revision
533 bisection, and any other non-zero exit status means the revision
534 is bad.
534 is bad.
535
535
536 .. container:: verbose
536 .. container:: verbose
537
537
538 Some examples:
538 Some examples:
539
539
540 - start a bisection with known bad revision 12, and good revision 34::
540 - start a bisection with known bad revision 12, and good revision 34::
541
541
542 hg bisect --bad 34
542 hg bisect --bad 34
543 hg bisect --good 12
543 hg bisect --good 12
544
544
545 - advance the current bisection by marking current revision as good or
545 - advance the current bisection by marking current revision as good or
546 bad::
546 bad::
547
547
548 hg bisect --good
548 hg bisect --good
549 hg bisect --bad
549 hg bisect --bad
550
550
551 - mark the current revision, or a known revision, to be skipped (e.g. if
551 - mark the current revision, or a known revision, to be skipped (e.g. if
552 that revision is not usable because of another issue)::
552 that revision is not usable because of another issue)::
553
553
554 hg bisect --skip
554 hg bisect --skip
555 hg bisect --skip 23
555 hg bisect --skip 23
556
556
557 - skip all revisions that do not touch directories ``foo`` or ``bar``::
557 - skip all revisions that do not touch directories ``foo`` or ``bar``::
558
558
559 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
559 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
560
560
561 - forget the current bisection::
561 - forget the current bisection::
562
562
563 hg bisect --reset
563 hg bisect --reset
564
564
565 - use 'make && make tests' to automatically find the first broken
565 - use 'make && make tests' to automatically find the first broken
566 revision::
566 revision::
567
567
568 hg bisect --reset
568 hg bisect --reset
569 hg bisect --bad 34
569 hg bisect --bad 34
570 hg bisect --good 12
570 hg bisect --good 12
571 hg bisect --command 'make && make tests'
571 hg bisect --command "make && make tests"
572
572
573 - see all changesets whose states are already known in the current
573 - see all changesets whose states are already known in the current
574 bisection::
574 bisection::
575
575
576 hg log -r "bisect(pruned)"
576 hg log -r "bisect(pruned)"
577
577
578 - see the changeset currently being bisected (especially useful
578 - see the changeset currently being bisected (especially useful
579 if running with -U/--noupdate)::
579 if running with -U/--noupdate)::
580
580
581 hg log -r "bisect(current)"
581 hg log -r "bisect(current)"
582
582
583 - see all changesets that took part in the current bisection::
583 - see all changesets that took part in the current bisection::
584
584
585 hg log -r "bisect(range)"
585 hg log -r "bisect(range)"
586
586
587 - with the graphlog extension, you can even get a nice graph::
587 - with the graphlog extension, you can even get a nice graph::
588
588
589 hg log --graph -r "bisect(range)"
589 hg log --graph -r "bisect(range)"
590
590
591 See :hg:`help revsets` for more about the `bisect()` keyword.
591 See :hg:`help revsets` for more about the `bisect()` keyword.
592
592
593 Returns 0 on success.
593 Returns 0 on success.
594 """
594 """
595 def extendbisectrange(nodes, good):
595 def extendbisectrange(nodes, good):
596 # bisect is incomplete when it ends on a merge node and
596 # bisect is incomplete when it ends on a merge node and
597 # one of the parent was not checked.
597 # one of the parent was not checked.
598 parents = repo[nodes[0]].parents()
598 parents = repo[nodes[0]].parents()
599 if len(parents) > 1:
599 if len(parents) > 1:
600 side = good and state['bad'] or state['good']
600 side = good and state['bad'] or state['good']
601 num = len(set(i.node() for i in parents) & set(side))
601 num = len(set(i.node() for i in parents) & set(side))
602 if num == 1:
602 if num == 1:
603 return parents[0].ancestor(parents[1])
603 return parents[0].ancestor(parents[1])
604 return None
604 return None
605
605
606 def print_result(nodes, good):
606 def print_result(nodes, good):
607 displayer = cmdutil.show_changeset(ui, repo, {})
607 displayer = cmdutil.show_changeset(ui, repo, {})
608 if len(nodes) == 1:
608 if len(nodes) == 1:
609 # narrowed it down to a single revision
609 # narrowed it down to a single revision
610 if good:
610 if good:
611 ui.write(_("The first good revision is:\n"))
611 ui.write(_("The first good revision is:\n"))
612 else:
612 else:
613 ui.write(_("The first bad revision is:\n"))
613 ui.write(_("The first bad revision is:\n"))
614 displayer.show(repo[nodes[0]])
614 displayer.show(repo[nodes[0]])
615 extendnode = extendbisectrange(nodes, good)
615 extendnode = extendbisectrange(nodes, good)
616 if extendnode is not None:
616 if extendnode is not None:
617 ui.write(_('Not all ancestors of this changeset have been'
617 ui.write(_('Not all ancestors of this changeset have been'
618 ' checked.\nUse bisect --extend to continue the '
618 ' checked.\nUse bisect --extend to continue the '
619 'bisection from\nthe common ancestor, %s.\n')
619 'bisection from\nthe common ancestor, %s.\n')
620 % extendnode)
620 % extendnode)
621 else:
621 else:
622 # multiple possible revisions
622 # multiple possible revisions
623 if good:
623 if good:
624 ui.write(_("Due to skipped revisions, the first "
624 ui.write(_("Due to skipped revisions, the first "
625 "good revision could be any of:\n"))
625 "good revision could be any of:\n"))
626 else:
626 else:
627 ui.write(_("Due to skipped revisions, the first "
627 ui.write(_("Due to skipped revisions, the first "
628 "bad revision could be any of:\n"))
628 "bad revision could be any of:\n"))
629 for n in nodes:
629 for n in nodes:
630 displayer.show(repo[n])
630 displayer.show(repo[n])
631 displayer.close()
631 displayer.close()
632
632
633 def check_state(state, interactive=True):
633 def check_state(state, interactive=True):
634 if not state['good'] or not state['bad']:
634 if not state['good'] or not state['bad']:
635 if (good or bad or skip or reset) and interactive:
635 if (good or bad or skip or reset) and interactive:
636 return
636 return
637 if not state['good']:
637 if not state['good']:
638 raise util.Abort(_('cannot bisect (no known good revisions)'))
638 raise util.Abort(_('cannot bisect (no known good revisions)'))
639 else:
639 else:
640 raise util.Abort(_('cannot bisect (no known bad revisions)'))
640 raise util.Abort(_('cannot bisect (no known bad revisions)'))
641 return True
641 return True
642
642
643 # backward compatibility
643 # backward compatibility
644 if rev in "good bad reset init".split():
644 if rev in "good bad reset init".split():
645 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
645 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
646 cmd, rev, extra = rev, extra, None
646 cmd, rev, extra = rev, extra, None
647 if cmd == "good":
647 if cmd == "good":
648 good = True
648 good = True
649 elif cmd == "bad":
649 elif cmd == "bad":
650 bad = True
650 bad = True
651 else:
651 else:
652 reset = True
652 reset = True
653 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
653 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
654 raise util.Abort(_('incompatible arguments'))
654 raise util.Abort(_('incompatible arguments'))
655
655
656 cmdutil.checkunfinished(repo)
656 cmdutil.checkunfinished(repo)
657
657
658 if reset:
658 if reset:
659 p = repo.join("bisect.state")
659 p = repo.join("bisect.state")
660 if os.path.exists(p):
660 if os.path.exists(p):
661 os.unlink(p)
661 os.unlink(p)
662 return
662 return
663
663
664 state = hbisect.load_state(repo)
664 state = hbisect.load_state(repo)
665
665
666 if command:
666 if command:
667 changesets = 1
667 changesets = 1
668 try:
668 try:
669 node = state['current'][0]
669 node = state['current'][0]
670 except LookupError:
670 except LookupError:
671 if noupdate:
671 if noupdate:
672 raise util.Abort(_('current bisect revision is unknown - '
672 raise util.Abort(_('current bisect revision is unknown - '
673 'start a new bisect to fix'))
673 'start a new bisect to fix'))
674 node, p2 = repo.dirstate.parents()
674 node, p2 = repo.dirstate.parents()
675 if p2 != nullid:
675 if p2 != nullid:
676 raise util.Abort(_('current bisect revision is a merge'))
676 raise util.Abort(_('current bisect revision is a merge'))
677 try:
677 try:
678 while changesets:
678 while changesets:
679 # update state
679 # update state
680 state['current'] = [node]
680 state['current'] = [node]
681 hbisect.save_state(repo, state)
681 hbisect.save_state(repo, state)
682 status = util.system(command,
682 status = util.system(command,
683 environ={'HG_NODE': hex(node)},
683 environ={'HG_NODE': hex(node)},
684 out=ui.fout)
684 out=ui.fout)
685 if status == 125:
685 if status == 125:
686 transition = "skip"
686 transition = "skip"
687 elif status == 0:
687 elif status == 0:
688 transition = "good"
688 transition = "good"
689 # status < 0 means process was killed
689 # status < 0 means process was killed
690 elif status == 127:
690 elif status == 127:
691 raise util.Abort(_("failed to execute %s") % command)
691 raise util.Abort(_("failed to execute %s") % command)
692 elif status < 0:
692 elif status < 0:
693 raise util.Abort(_("%s killed") % command)
693 raise util.Abort(_("%s killed") % command)
694 else:
694 else:
695 transition = "bad"
695 transition = "bad"
696 ctx = scmutil.revsingle(repo, rev, node)
696 ctx = scmutil.revsingle(repo, rev, node)
697 rev = None # clear for future iterations
697 rev = None # clear for future iterations
698 state[transition].append(ctx.node())
698 state[transition].append(ctx.node())
699 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
699 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
700 check_state(state, interactive=False)
700 check_state(state, interactive=False)
701 # bisect
701 # bisect
702 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
702 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
703 # update to next check
703 # update to next check
704 node = nodes[0]
704 node = nodes[0]
705 if not noupdate:
705 if not noupdate:
706 cmdutil.bailifchanged(repo)
706 cmdutil.bailifchanged(repo)
707 hg.clean(repo, node, show_stats=False)
707 hg.clean(repo, node, show_stats=False)
708 finally:
708 finally:
709 state['current'] = [node]
709 state['current'] = [node]
710 hbisect.save_state(repo, state)
710 hbisect.save_state(repo, state)
711 print_result(nodes, good)
711 print_result(nodes, good)
712 return
712 return
713
713
714 # update state
714 # update state
715
715
716 if rev:
716 if rev:
717 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
717 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
718 else:
718 else:
719 nodes = [repo.lookup('.')]
719 nodes = [repo.lookup('.')]
720
720
721 if good or bad or skip:
721 if good or bad or skip:
722 if good:
722 if good:
723 state['good'] += nodes
723 state['good'] += nodes
724 elif bad:
724 elif bad:
725 state['bad'] += nodes
725 state['bad'] += nodes
726 elif skip:
726 elif skip:
727 state['skip'] += nodes
727 state['skip'] += nodes
728 hbisect.save_state(repo, state)
728 hbisect.save_state(repo, state)
729
729
730 if not check_state(state):
730 if not check_state(state):
731 return
731 return
732
732
733 # actually bisect
733 # actually bisect
734 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
734 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
735 if extend:
735 if extend:
736 if not changesets:
736 if not changesets:
737 extendnode = extendbisectrange(nodes, good)
737 extendnode = extendbisectrange(nodes, good)
738 if extendnode is not None:
738 if extendnode is not None:
739 ui.write(_("Extending search to changeset %d:%s\n"
739 ui.write(_("Extending search to changeset %d:%s\n"
740 % (extendnode.rev(), extendnode)))
740 % (extendnode.rev(), extendnode)))
741 state['current'] = [extendnode.node()]
741 state['current'] = [extendnode.node()]
742 hbisect.save_state(repo, state)
742 hbisect.save_state(repo, state)
743 if noupdate:
743 if noupdate:
744 return
744 return
745 cmdutil.bailifchanged(repo)
745 cmdutil.bailifchanged(repo)
746 return hg.clean(repo, extendnode.node())
746 return hg.clean(repo, extendnode.node())
747 raise util.Abort(_("nothing to extend"))
747 raise util.Abort(_("nothing to extend"))
748
748
749 if changesets == 0:
749 if changesets == 0:
750 print_result(nodes, good)
750 print_result(nodes, good)
751 else:
751 else:
752 assert len(nodes) == 1 # only a single node can be tested next
752 assert len(nodes) == 1 # only a single node can be tested next
753 node = nodes[0]
753 node = nodes[0]
754 # compute the approximate number of remaining tests
754 # compute the approximate number of remaining tests
755 tests, size = 0, 2
755 tests, size = 0, 2
756 while size <= changesets:
756 while size <= changesets:
757 tests, size = tests + 1, size * 2
757 tests, size = tests + 1, size * 2
758 rev = repo.changelog.rev(node)
758 rev = repo.changelog.rev(node)
759 ui.write(_("Testing changeset %d:%s "
759 ui.write(_("Testing changeset %d:%s "
760 "(%d changesets remaining, ~%d tests)\n")
760 "(%d changesets remaining, ~%d tests)\n")
761 % (rev, short(node), changesets, tests))
761 % (rev, short(node), changesets, tests))
762 state['current'] = [node]
762 state['current'] = [node]
763 hbisect.save_state(repo, state)
763 hbisect.save_state(repo, state)
764 if not noupdate:
764 if not noupdate:
765 cmdutil.bailifchanged(repo)
765 cmdutil.bailifchanged(repo)
766 return hg.clean(repo, node)
766 return hg.clean(repo, node)
767
767
768 @command('bookmarks|bookmark',
768 @command('bookmarks|bookmark',
769 [('f', 'force', False, _('force')),
769 [('f', 'force', False, _('force')),
770 ('r', 'rev', '', _('revision'), _('REV')),
770 ('r', 'rev', '', _('revision'), _('REV')),
771 ('d', 'delete', False, _('delete a given bookmark')),
771 ('d', 'delete', False, _('delete a given bookmark')),
772 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
772 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
773 ('i', 'inactive', False, _('mark a bookmark inactive'))],
773 ('i', 'inactive', False, _('mark a bookmark inactive'))],
774 _('hg bookmarks [OPTIONS]... [NAME]...'))
774 _('hg bookmarks [OPTIONS]... [NAME]...'))
775 def bookmark(ui, repo, *names, **opts):
775 def bookmark(ui, repo, *names, **opts):
776 '''track a line of development with movable markers
776 '''track a line of development with movable markers
777
777
778 Bookmarks are pointers to certain commits that move when committing.
778 Bookmarks are pointers to certain commits that move when committing.
779 Bookmarks are local. They can be renamed, copied and deleted. It is
779 Bookmarks are local. They can be renamed, copied and deleted. It is
780 possible to use :hg:`merge NAME` to merge from a given bookmark, and
780 possible to use :hg:`merge NAME` to merge from a given bookmark, and
781 :hg:`update NAME` to update to a given bookmark.
781 :hg:`update NAME` to update to a given bookmark.
782
782
783 You can use :hg:`bookmark NAME` to set a bookmark on the working
783 You can use :hg:`bookmark NAME` to set a bookmark on the working
784 directory's parent revision with the given name. If you specify
784 directory's parent revision with the given name. If you specify
785 a revision using -r REV (where REV may be an existing bookmark),
785 a revision using -r REV (where REV may be an existing bookmark),
786 the bookmark is assigned to that revision.
786 the bookmark is assigned to that revision.
787
787
788 Bookmarks can be pushed and pulled between repositories (see :hg:`help
788 Bookmarks can be pushed and pulled between repositories (see :hg:`help
789 push` and :hg:`help pull`). This requires both the local and remote
789 push` and :hg:`help pull`). This requires both the local and remote
790 repositories to support bookmarks. For versions prior to 1.8, this means
790 repositories to support bookmarks. For versions prior to 1.8, this means
791 the bookmarks extension must be enabled.
791 the bookmarks extension must be enabled.
792
792
793 If you set a bookmark called '@', new clones of the repository will
793 If you set a bookmark called '@', new clones of the repository will
794 have that revision checked out (and the bookmark made active) by
794 have that revision checked out (and the bookmark made active) by
795 default.
795 default.
796
796
797 With -i/--inactive, the new bookmark will not be made the active
797 With -i/--inactive, the new bookmark will not be made the active
798 bookmark. If -r/--rev is given, the new bookmark will not be made
798 bookmark. If -r/--rev is given, the new bookmark will not be made
799 active even if -i/--inactive is not given. If no NAME is given, the
799 active even if -i/--inactive is not given. If no NAME is given, the
800 current active bookmark will be marked inactive.
800 current active bookmark will be marked inactive.
801 '''
801 '''
802 force = opts.get('force')
802 force = opts.get('force')
803 rev = opts.get('rev')
803 rev = opts.get('rev')
804 delete = opts.get('delete')
804 delete = opts.get('delete')
805 rename = opts.get('rename')
805 rename = opts.get('rename')
806 inactive = opts.get('inactive')
806 inactive = opts.get('inactive')
807
807
808 hexfn = ui.debugflag and hex or short
808 hexfn = ui.debugflag and hex or short
809 marks = repo._bookmarks
809 marks = repo._bookmarks
810 cur = repo.changectx('.').node()
810 cur = repo.changectx('.').node()
811
811
812 def checkformat(mark):
812 def checkformat(mark):
813 mark = mark.strip()
813 mark = mark.strip()
814 if not mark:
814 if not mark:
815 raise util.Abort(_("bookmark names cannot consist entirely of "
815 raise util.Abort(_("bookmark names cannot consist entirely of "
816 "whitespace"))
816 "whitespace"))
817 scmutil.checknewlabel(repo, mark, 'bookmark')
817 scmutil.checknewlabel(repo, mark, 'bookmark')
818 return mark
818 return mark
819
819
820 def checkconflict(repo, mark, force=False, target=None):
820 def checkconflict(repo, mark, force=False, target=None):
821 if mark in marks and not force:
821 if mark in marks and not force:
822 if target:
822 if target:
823 if marks[mark] == target and target == cur:
823 if marks[mark] == target and target == cur:
824 # re-activating a bookmark
824 # re-activating a bookmark
825 return
825 return
826 anc = repo.changelog.ancestors([repo[target].rev()])
826 anc = repo.changelog.ancestors([repo[target].rev()])
827 bmctx = repo[marks[mark]]
827 bmctx = repo[marks[mark]]
828 divs = [repo[b].node() for b in marks
828 divs = [repo[b].node() for b in marks
829 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
829 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
830
830
831 # allow resolving a single divergent bookmark even if moving
831 # allow resolving a single divergent bookmark even if moving
832 # the bookmark across branches when a revision is specified
832 # the bookmark across branches when a revision is specified
833 # that contains a divergent bookmark
833 # that contains a divergent bookmark
834 if bmctx.rev() not in anc and target in divs:
834 if bmctx.rev() not in anc and target in divs:
835 bookmarks.deletedivergent(repo, [target], mark)
835 bookmarks.deletedivergent(repo, [target], mark)
836 return
836 return
837
837
838 deletefrom = [b for b in divs
838 deletefrom = [b for b in divs
839 if repo[b].rev() in anc or b == target]
839 if repo[b].rev() in anc or b == target]
840 bookmarks.deletedivergent(repo, deletefrom, mark)
840 bookmarks.deletedivergent(repo, deletefrom, mark)
841 if bmctx.rev() in anc:
841 if bmctx.rev() in anc:
842 ui.status(_("moving bookmark '%s' forward from %s\n") %
842 ui.status(_("moving bookmark '%s' forward from %s\n") %
843 (mark, short(bmctx.node())))
843 (mark, short(bmctx.node())))
844 return
844 return
845 raise util.Abort(_("bookmark '%s' already exists "
845 raise util.Abort(_("bookmark '%s' already exists "
846 "(use -f to force)") % mark)
846 "(use -f to force)") % mark)
847 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
847 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
848 and not force):
848 and not force):
849 raise util.Abort(
849 raise util.Abort(
850 _("a bookmark cannot have the name of an existing branch"))
850 _("a bookmark cannot have the name of an existing branch"))
851
851
852 if delete and rename:
852 if delete and rename:
853 raise util.Abort(_("--delete and --rename are incompatible"))
853 raise util.Abort(_("--delete and --rename are incompatible"))
854 if delete and rev:
854 if delete and rev:
855 raise util.Abort(_("--rev is incompatible with --delete"))
855 raise util.Abort(_("--rev is incompatible with --delete"))
856 if rename and rev:
856 if rename and rev:
857 raise util.Abort(_("--rev is incompatible with --rename"))
857 raise util.Abort(_("--rev is incompatible with --rename"))
858 if not names and (delete or rev):
858 if not names and (delete or rev):
859 raise util.Abort(_("bookmark name required"))
859 raise util.Abort(_("bookmark name required"))
860
860
861 if delete:
861 if delete:
862 for mark in names:
862 for mark in names:
863 if mark not in marks:
863 if mark not in marks:
864 raise util.Abort(_("bookmark '%s' does not exist") % mark)
864 raise util.Abort(_("bookmark '%s' does not exist") % mark)
865 if mark == repo._bookmarkcurrent:
865 if mark == repo._bookmarkcurrent:
866 bookmarks.setcurrent(repo, None)
866 bookmarks.setcurrent(repo, None)
867 del marks[mark]
867 del marks[mark]
868 marks.write()
868 marks.write()
869
869
870 elif rename:
870 elif rename:
871 if not names:
871 if not names:
872 raise util.Abort(_("new bookmark name required"))
872 raise util.Abort(_("new bookmark name required"))
873 elif len(names) > 1:
873 elif len(names) > 1:
874 raise util.Abort(_("only one new bookmark name allowed"))
874 raise util.Abort(_("only one new bookmark name allowed"))
875 mark = checkformat(names[0])
875 mark = checkformat(names[0])
876 if rename not in marks:
876 if rename not in marks:
877 raise util.Abort(_("bookmark '%s' does not exist") % rename)
877 raise util.Abort(_("bookmark '%s' does not exist") % rename)
878 checkconflict(repo, mark, force)
878 checkconflict(repo, mark, force)
879 marks[mark] = marks[rename]
879 marks[mark] = marks[rename]
880 if repo._bookmarkcurrent == rename and not inactive:
880 if repo._bookmarkcurrent == rename and not inactive:
881 bookmarks.setcurrent(repo, mark)
881 bookmarks.setcurrent(repo, mark)
882 del marks[rename]
882 del marks[rename]
883 marks.write()
883 marks.write()
884
884
885 elif names:
885 elif names:
886 newact = None
886 newact = None
887 for mark in names:
887 for mark in names:
888 mark = checkformat(mark)
888 mark = checkformat(mark)
889 if newact is None:
889 if newact is None:
890 newact = mark
890 newact = mark
891 if inactive and mark == repo._bookmarkcurrent:
891 if inactive and mark == repo._bookmarkcurrent:
892 bookmarks.setcurrent(repo, None)
892 bookmarks.setcurrent(repo, None)
893 return
893 return
894 tgt = cur
894 tgt = cur
895 if rev:
895 if rev:
896 tgt = scmutil.revsingle(repo, rev).node()
896 tgt = scmutil.revsingle(repo, rev).node()
897 checkconflict(repo, mark, force, tgt)
897 checkconflict(repo, mark, force, tgt)
898 marks[mark] = tgt
898 marks[mark] = tgt
899 if not inactive and cur == marks[newact] and not rev:
899 if not inactive and cur == marks[newact] and not rev:
900 bookmarks.setcurrent(repo, newact)
900 bookmarks.setcurrent(repo, newact)
901 elif cur != tgt and newact == repo._bookmarkcurrent:
901 elif cur != tgt and newact == repo._bookmarkcurrent:
902 bookmarks.setcurrent(repo, None)
902 bookmarks.setcurrent(repo, None)
903 marks.write()
903 marks.write()
904
904
905 # Same message whether trying to deactivate the current bookmark (-i
905 # Same message whether trying to deactivate the current bookmark (-i
906 # with no NAME) or listing bookmarks
906 # with no NAME) or listing bookmarks
907 elif len(marks) == 0:
907 elif len(marks) == 0:
908 ui.status(_("no bookmarks set\n"))
908 ui.status(_("no bookmarks set\n"))
909
909
910 elif inactive:
910 elif inactive:
911 if not repo._bookmarkcurrent:
911 if not repo._bookmarkcurrent:
912 ui.status(_("no active bookmark\n"))
912 ui.status(_("no active bookmark\n"))
913 else:
913 else:
914 bookmarks.setcurrent(repo, None)
914 bookmarks.setcurrent(repo, None)
915
915
916 else: # show bookmarks
916 else: # show bookmarks
917 for bmark, n in sorted(marks.iteritems()):
917 for bmark, n in sorted(marks.iteritems()):
918 current = repo._bookmarkcurrent
918 current = repo._bookmarkcurrent
919 if bmark == current:
919 if bmark == current:
920 prefix, label = '*', 'bookmarks.current'
920 prefix, label = '*', 'bookmarks.current'
921 else:
921 else:
922 prefix, label = ' ', ''
922 prefix, label = ' ', ''
923
923
924 if ui.quiet:
924 if ui.quiet:
925 ui.write("%s\n" % bmark, label=label)
925 ui.write("%s\n" % bmark, label=label)
926 else:
926 else:
927 ui.write(" %s %-25s %d:%s\n" % (
927 ui.write(" %s %-25s %d:%s\n" % (
928 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
928 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
929 label=label)
929 label=label)
930
930
931 @command('branch',
931 @command('branch',
932 [('f', 'force', None,
932 [('f', 'force', None,
933 _('set branch name even if it shadows an existing branch')),
933 _('set branch name even if it shadows an existing branch')),
934 ('C', 'clean', None, _('reset branch name to parent branch name'))],
934 ('C', 'clean', None, _('reset branch name to parent branch name'))],
935 _('[-fC] [NAME]'))
935 _('[-fC] [NAME]'))
936 def branch(ui, repo, label=None, **opts):
936 def branch(ui, repo, label=None, **opts):
937 """set or show the current branch name
937 """set or show the current branch name
938
938
939 .. note::
939 .. note::
940 Branch names are permanent and global. Use :hg:`bookmark` to create a
940 Branch names are permanent and global. Use :hg:`bookmark` to create a
941 light-weight bookmark instead. See :hg:`help glossary` for more
941 light-weight bookmark instead. See :hg:`help glossary` for more
942 information about named branches and bookmarks.
942 information about named branches and bookmarks.
943
943
944 With no argument, show the current branch name. With one argument,
944 With no argument, show the current branch name. With one argument,
945 set the working directory branch name (the branch will not exist
945 set the working directory branch name (the branch will not exist
946 in the repository until the next commit). Standard practice
946 in the repository until the next commit). Standard practice
947 recommends that primary development take place on the 'default'
947 recommends that primary development take place on the 'default'
948 branch.
948 branch.
949
949
950 Unless -f/--force is specified, branch will not let you set a
950 Unless -f/--force is specified, branch will not let you set a
951 branch name that already exists, even if it's inactive.
951 branch name that already exists, even if it's inactive.
952
952
953 Use -C/--clean to reset the working directory branch to that of
953 Use -C/--clean to reset the working directory branch to that of
954 the parent of the working directory, negating a previous branch
954 the parent of the working directory, negating a previous branch
955 change.
955 change.
956
956
957 Use the command :hg:`update` to switch to an existing branch. Use
957 Use the command :hg:`update` to switch to an existing branch. Use
958 :hg:`commit --close-branch` to mark this branch as closed.
958 :hg:`commit --close-branch` to mark this branch as closed.
959
959
960 Returns 0 on success.
960 Returns 0 on success.
961 """
961 """
962 if label:
962 if label:
963 label = label.strip()
963 label = label.strip()
964
964
965 if not opts.get('clean') and not label:
965 if not opts.get('clean') and not label:
966 ui.write("%s\n" % repo.dirstate.branch())
966 ui.write("%s\n" % repo.dirstate.branch())
967 return
967 return
968
968
969 wlock = repo.wlock()
969 wlock = repo.wlock()
970 try:
970 try:
971 if opts.get('clean'):
971 if opts.get('clean'):
972 label = repo[None].p1().branch()
972 label = repo[None].p1().branch()
973 repo.dirstate.setbranch(label)
973 repo.dirstate.setbranch(label)
974 ui.status(_('reset working directory to branch %s\n') % label)
974 ui.status(_('reset working directory to branch %s\n') % label)
975 elif label:
975 elif label:
976 if not opts.get('force') and label in repo.branchmap():
976 if not opts.get('force') and label in repo.branchmap():
977 if label not in [p.branch() for p in repo.parents()]:
977 if label not in [p.branch() for p in repo.parents()]:
978 raise util.Abort(_('a branch of the same name already'
978 raise util.Abort(_('a branch of the same name already'
979 ' exists'),
979 ' exists'),
980 # i18n: "it" refers to an existing branch
980 # i18n: "it" refers to an existing branch
981 hint=_("use 'hg update' to switch to it"))
981 hint=_("use 'hg update' to switch to it"))
982 scmutil.checknewlabel(repo, label, 'branch')
982 scmutil.checknewlabel(repo, label, 'branch')
983 repo.dirstate.setbranch(label)
983 repo.dirstate.setbranch(label)
984 ui.status(_('marked working directory as branch %s\n') % label)
984 ui.status(_('marked working directory as branch %s\n') % label)
985 ui.status(_('(branches are permanent and global, '
985 ui.status(_('(branches are permanent and global, '
986 'did you want a bookmark?)\n'))
986 'did you want a bookmark?)\n'))
987 finally:
987 finally:
988 wlock.release()
988 wlock.release()
989
989
990 @command('branches',
990 @command('branches',
991 [('a', 'active', False, _('show only branches that have unmerged heads')),
991 [('a', 'active', False, _('show only branches that have unmerged heads')),
992 ('c', 'closed', False, _('show normal and closed branches'))],
992 ('c', 'closed', False, _('show normal and closed branches'))],
993 _('[-ac]'))
993 _('[-ac]'))
994 def branches(ui, repo, active=False, closed=False):
994 def branches(ui, repo, active=False, closed=False):
995 """list repository named branches
995 """list repository named branches
996
996
997 List the repository's named branches, indicating which ones are
997 List the repository's named branches, indicating which ones are
998 inactive. If -c/--closed is specified, also list branches which have
998 inactive. If -c/--closed is specified, also list branches which have
999 been marked closed (see :hg:`commit --close-branch`).
999 been marked closed (see :hg:`commit --close-branch`).
1000
1000
1001 If -a/--active is specified, only show active branches. A branch
1001 If -a/--active is specified, only show active branches. A branch
1002 is considered active if it contains repository heads.
1002 is considered active if it contains repository heads.
1003
1003
1004 Use the command :hg:`update` to switch to an existing branch.
1004 Use the command :hg:`update` to switch to an existing branch.
1005
1005
1006 Returns 0.
1006 Returns 0.
1007 """
1007 """
1008
1008
1009 hexfunc = ui.debugflag and hex or short
1009 hexfunc = ui.debugflag and hex or short
1010
1010
1011 activebranches = set([repo[n].branch() for n in repo.heads()])
1011 activebranches = set([repo[n].branch() for n in repo.heads()])
1012 branches = []
1012 branches = []
1013 for tag, heads in repo.branchmap().iteritems():
1013 for tag, heads in repo.branchmap().iteritems():
1014 for h in reversed(heads):
1014 for h in reversed(heads):
1015 ctx = repo[h]
1015 ctx = repo[h]
1016 isopen = not ctx.closesbranch()
1016 isopen = not ctx.closesbranch()
1017 if isopen:
1017 if isopen:
1018 tip = ctx
1018 tip = ctx
1019 break
1019 break
1020 else:
1020 else:
1021 tip = repo[heads[-1]]
1021 tip = repo[heads[-1]]
1022 isactive = tag in activebranches and isopen
1022 isactive = tag in activebranches and isopen
1023 branches.append((tip, isactive, isopen))
1023 branches.append((tip, isactive, isopen))
1024 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1024 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1025 reverse=True)
1025 reverse=True)
1026
1026
1027 for ctx, isactive, isopen in branches:
1027 for ctx, isactive, isopen in branches:
1028 if (not active) or isactive:
1028 if (not active) or isactive:
1029 if isactive:
1029 if isactive:
1030 label = 'branches.active'
1030 label = 'branches.active'
1031 notice = ''
1031 notice = ''
1032 elif not isopen:
1032 elif not isopen:
1033 if not closed:
1033 if not closed:
1034 continue
1034 continue
1035 label = 'branches.closed'
1035 label = 'branches.closed'
1036 notice = _(' (closed)')
1036 notice = _(' (closed)')
1037 else:
1037 else:
1038 label = 'branches.inactive'
1038 label = 'branches.inactive'
1039 notice = _(' (inactive)')
1039 notice = _(' (inactive)')
1040 if ctx.branch() == repo.dirstate.branch():
1040 if ctx.branch() == repo.dirstate.branch():
1041 label = 'branches.current'
1041 label = 'branches.current'
1042 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1042 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1043 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1043 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1044 'log.changeset changeset.%s' % ctx.phasestr())
1044 'log.changeset changeset.%s' % ctx.phasestr())
1045 tag = ui.label(ctx.branch(), label)
1045 tag = ui.label(ctx.branch(), label)
1046 if ui.quiet:
1046 if ui.quiet:
1047 ui.write("%s\n" % tag)
1047 ui.write("%s\n" % tag)
1048 else:
1048 else:
1049 ui.write("%s %s%s\n" % (tag, rev, notice))
1049 ui.write("%s %s%s\n" % (tag, rev, notice))
1050
1050
1051 @command('bundle',
1051 @command('bundle',
1052 [('f', 'force', None, _('run even when the destination is unrelated')),
1052 [('f', 'force', None, _('run even when the destination is unrelated')),
1053 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1053 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1054 _('REV')),
1054 _('REV')),
1055 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1055 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1056 _('BRANCH')),
1056 _('BRANCH')),
1057 ('', 'base', [],
1057 ('', 'base', [],
1058 _('a base changeset assumed to be available at the destination'),
1058 _('a base changeset assumed to be available at the destination'),
1059 _('REV')),
1059 _('REV')),
1060 ('a', 'all', None, _('bundle all changesets in the repository')),
1060 ('a', 'all', None, _('bundle all changesets in the repository')),
1061 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1061 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1062 ] + remoteopts,
1062 ] + remoteopts,
1063 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1063 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1064 def bundle(ui, repo, fname, dest=None, **opts):
1064 def bundle(ui, repo, fname, dest=None, **opts):
1065 """create a changegroup file
1065 """create a changegroup file
1066
1066
1067 Generate a compressed changegroup file collecting changesets not
1067 Generate a compressed changegroup file collecting changesets not
1068 known to be in another repository.
1068 known to be in another repository.
1069
1069
1070 If you omit the destination repository, then hg assumes the
1070 If you omit the destination repository, then hg assumes the
1071 destination will have all the nodes you specify with --base
1071 destination will have all the nodes you specify with --base
1072 parameters. To create a bundle containing all changesets, use
1072 parameters. To create a bundle containing all changesets, use
1073 -a/--all (or --base null).
1073 -a/--all (or --base null).
1074
1074
1075 You can change compression method with the -t/--type option.
1075 You can change compression method with the -t/--type option.
1076 The available compression methods are: none, bzip2, and
1076 The available compression methods are: none, bzip2, and
1077 gzip (by default, bundles are compressed using bzip2).
1077 gzip (by default, bundles are compressed using bzip2).
1078
1078
1079 The bundle file can then be transferred using conventional means
1079 The bundle file can then be transferred using conventional means
1080 and applied to another repository with the unbundle or pull
1080 and applied to another repository with the unbundle or pull
1081 command. This is useful when direct push and pull are not
1081 command. This is useful when direct push and pull are not
1082 available or when exporting an entire repository is undesirable.
1082 available or when exporting an entire repository is undesirable.
1083
1083
1084 Applying bundles preserves all changeset contents including
1084 Applying bundles preserves all changeset contents including
1085 permissions, copy/rename information, and revision history.
1085 permissions, copy/rename information, and revision history.
1086
1086
1087 Returns 0 on success, 1 if no changes found.
1087 Returns 0 on success, 1 if no changes found.
1088 """
1088 """
1089 revs = None
1089 revs = None
1090 if 'rev' in opts:
1090 if 'rev' in opts:
1091 revs = scmutil.revrange(repo, opts['rev'])
1091 revs = scmutil.revrange(repo, opts['rev'])
1092
1092
1093 bundletype = opts.get('type', 'bzip2').lower()
1093 bundletype = opts.get('type', 'bzip2').lower()
1094 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1094 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1095 bundletype = btypes.get(bundletype)
1095 bundletype = btypes.get(bundletype)
1096 if bundletype not in changegroup.bundletypes:
1096 if bundletype not in changegroup.bundletypes:
1097 raise util.Abort(_('unknown bundle type specified with --type'))
1097 raise util.Abort(_('unknown bundle type specified with --type'))
1098
1098
1099 if opts.get('all'):
1099 if opts.get('all'):
1100 base = ['null']
1100 base = ['null']
1101 else:
1101 else:
1102 base = scmutil.revrange(repo, opts.get('base'))
1102 base = scmutil.revrange(repo, opts.get('base'))
1103 # TODO: get desired bundlecaps from command line.
1103 # TODO: get desired bundlecaps from command line.
1104 bundlecaps = None
1104 bundlecaps = None
1105 if base:
1105 if base:
1106 if dest:
1106 if dest:
1107 raise util.Abort(_("--base is incompatible with specifying "
1107 raise util.Abort(_("--base is incompatible with specifying "
1108 "a destination"))
1108 "a destination"))
1109 common = [repo.lookup(rev) for rev in base]
1109 common = [repo.lookup(rev) for rev in base]
1110 heads = revs and map(repo.lookup, revs) or revs
1110 heads = revs and map(repo.lookup, revs) or revs
1111 cg = repo.getbundle('bundle', heads=heads, common=common,
1111 cg = repo.getbundle('bundle', heads=heads, common=common,
1112 bundlecaps=bundlecaps)
1112 bundlecaps=bundlecaps)
1113 outgoing = None
1113 outgoing = None
1114 else:
1114 else:
1115 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1115 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1116 dest, branches = hg.parseurl(dest, opts.get('branch'))
1116 dest, branches = hg.parseurl(dest, opts.get('branch'))
1117 other = hg.peer(repo, opts, dest)
1117 other = hg.peer(repo, opts, dest)
1118 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1118 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1119 heads = revs and map(repo.lookup, revs) or revs
1119 heads = revs and map(repo.lookup, revs) or revs
1120 outgoing = discovery.findcommonoutgoing(repo, other,
1120 outgoing = discovery.findcommonoutgoing(repo, other,
1121 onlyheads=heads,
1121 onlyheads=heads,
1122 force=opts.get('force'),
1122 force=opts.get('force'),
1123 portable=True)
1123 portable=True)
1124 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1124 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1125 if not cg:
1125 if not cg:
1126 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1126 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1127 return 1
1127 return 1
1128
1128
1129 changegroup.writebundle(cg, fname, bundletype)
1129 changegroup.writebundle(cg, fname, bundletype)
1130
1130
1131 @command('cat',
1131 @command('cat',
1132 [('o', 'output', '',
1132 [('o', 'output', '',
1133 _('print output to file with formatted name'), _('FORMAT')),
1133 _('print output to file with formatted name'), _('FORMAT')),
1134 ('r', 'rev', '', _('print the given revision'), _('REV')),
1134 ('r', 'rev', '', _('print the given revision'), _('REV')),
1135 ('', 'decode', None, _('apply any matching decode filter')),
1135 ('', 'decode', None, _('apply any matching decode filter')),
1136 ] + walkopts,
1136 ] + walkopts,
1137 _('[OPTION]... FILE...'))
1137 _('[OPTION]... FILE...'))
1138 def cat(ui, repo, file1, *pats, **opts):
1138 def cat(ui, repo, file1, *pats, **opts):
1139 """output the current or given revision of files
1139 """output the current or given revision of files
1140
1140
1141 Print the specified files as they were at the given revision. If
1141 Print the specified files as they were at the given revision. If
1142 no revision is given, the parent of the working directory is used.
1142 no revision is given, the parent of the working directory is used.
1143
1143
1144 Output may be to a file, in which case the name of the file is
1144 Output may be to a file, in which case the name of the file is
1145 given using a format string. The formatting rules are the same as
1145 given using a format string. The formatting rules are the same as
1146 for the export command, with the following additions:
1146 for the export command, with the following additions:
1147
1147
1148 :``%s``: basename of file being printed
1148 :``%s``: basename of file being printed
1149 :``%d``: dirname of file being printed, or '.' if in repository root
1149 :``%d``: dirname of file being printed, or '.' if in repository root
1150 :``%p``: root-relative path name of file being printed
1150 :``%p``: root-relative path name of file being printed
1151
1151
1152 Returns 0 on success.
1152 Returns 0 on success.
1153 """
1153 """
1154 ctx = scmutil.revsingle(repo, opts.get('rev'))
1154 ctx = scmutil.revsingle(repo, opts.get('rev'))
1155 err = 1
1155 err = 1
1156 m = scmutil.match(ctx, (file1,) + pats, opts)
1156 m = scmutil.match(ctx, (file1,) + pats, opts)
1157 for abs in ctx.walk(m):
1157 for abs in ctx.walk(m):
1158 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1158 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1159 pathname=abs)
1159 pathname=abs)
1160 data = ctx[abs].data()
1160 data = ctx[abs].data()
1161 if opts.get('decode'):
1161 if opts.get('decode'):
1162 data = repo.wwritedata(abs, data)
1162 data = repo.wwritedata(abs, data)
1163 fp.write(data)
1163 fp.write(data)
1164 fp.close()
1164 fp.close()
1165 err = 0
1165 err = 0
1166 return err
1166 return err
1167
1167
1168 @command('^clone',
1168 @command('^clone',
1169 [('U', 'noupdate', None,
1169 [('U', 'noupdate', None,
1170 _('the clone will include an empty working copy (only a repository)')),
1170 _('the clone will include an empty working copy (only a repository)')),
1171 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1171 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1172 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1172 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1173 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1173 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1174 ('', 'pull', None, _('use pull protocol to copy metadata')),
1174 ('', 'pull', None, _('use pull protocol to copy metadata')),
1175 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1175 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1176 ] + remoteopts,
1176 ] + remoteopts,
1177 _('[OPTION]... SOURCE [DEST]'))
1177 _('[OPTION]... SOURCE [DEST]'))
1178 def clone(ui, source, dest=None, **opts):
1178 def clone(ui, source, dest=None, **opts):
1179 """make a copy of an existing repository
1179 """make a copy of an existing repository
1180
1180
1181 Create a copy of an existing repository in a new directory.
1181 Create a copy of an existing repository in a new directory.
1182
1182
1183 If no destination directory name is specified, it defaults to the
1183 If no destination directory name is specified, it defaults to the
1184 basename of the source.
1184 basename of the source.
1185
1185
1186 The location of the source is added to the new repository's
1186 The location of the source is added to the new repository's
1187 ``.hg/hgrc`` file, as the default to be used for future pulls.
1187 ``.hg/hgrc`` file, as the default to be used for future pulls.
1188
1188
1189 Only local paths and ``ssh://`` URLs are supported as
1189 Only local paths and ``ssh://`` URLs are supported as
1190 destinations. For ``ssh://`` destinations, no working directory or
1190 destinations. For ``ssh://`` destinations, no working directory or
1191 ``.hg/hgrc`` will be created on the remote side.
1191 ``.hg/hgrc`` will be created on the remote side.
1192
1192
1193 To pull only a subset of changesets, specify one or more revisions
1193 To pull only a subset of changesets, specify one or more revisions
1194 identifiers with -r/--rev or branches with -b/--branch. The
1194 identifiers with -r/--rev or branches with -b/--branch. The
1195 resulting clone will contain only the specified changesets and
1195 resulting clone will contain only the specified changesets and
1196 their ancestors. These options (or 'clone src#rev dest') imply
1196 their ancestors. These options (or 'clone src#rev dest') imply
1197 --pull, even for local source repositories. Note that specifying a
1197 --pull, even for local source repositories. Note that specifying a
1198 tag will include the tagged changeset but not the changeset
1198 tag will include the tagged changeset but not the changeset
1199 containing the tag.
1199 containing the tag.
1200
1200
1201 If the source repository has a bookmark called '@' set, that
1201 If the source repository has a bookmark called '@' set, that
1202 revision will be checked out in the new repository by default.
1202 revision will be checked out in the new repository by default.
1203
1203
1204 To check out a particular version, use -u/--update, or
1204 To check out a particular version, use -u/--update, or
1205 -U/--noupdate to create a clone with no working directory.
1205 -U/--noupdate to create a clone with no working directory.
1206
1206
1207 .. container:: verbose
1207 .. container:: verbose
1208
1208
1209 For efficiency, hardlinks are used for cloning whenever the
1209 For efficiency, hardlinks are used for cloning whenever the
1210 source and destination are on the same filesystem (note this
1210 source and destination are on the same filesystem (note this
1211 applies only to the repository data, not to the working
1211 applies only to the repository data, not to the working
1212 directory). Some filesystems, such as AFS, implement hardlinking
1212 directory). Some filesystems, such as AFS, implement hardlinking
1213 incorrectly, but do not report errors. In these cases, use the
1213 incorrectly, but do not report errors. In these cases, use the
1214 --pull option to avoid hardlinking.
1214 --pull option to avoid hardlinking.
1215
1215
1216 In some cases, you can clone repositories and the working
1216 In some cases, you can clone repositories and the working
1217 directory using full hardlinks with ::
1217 directory using full hardlinks with ::
1218
1218
1219 $ cp -al REPO REPOCLONE
1219 $ cp -al REPO REPOCLONE
1220
1220
1221 This is the fastest way to clone, but it is not always safe. The
1221 This is the fastest way to clone, but it is not always safe. The
1222 operation is not atomic (making sure REPO is not modified during
1222 operation is not atomic (making sure REPO is not modified during
1223 the operation is up to you) and you have to make sure your
1223 the operation is up to you) and you have to make sure your
1224 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1224 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1225 so). Also, this is not compatible with certain extensions that
1225 so). Also, this is not compatible with certain extensions that
1226 place their metadata under the .hg directory, such as mq.
1226 place their metadata under the .hg directory, such as mq.
1227
1227
1228 Mercurial will update the working directory to the first applicable
1228 Mercurial will update the working directory to the first applicable
1229 revision from this list:
1229 revision from this list:
1230
1230
1231 a) null if -U or the source repository has no changesets
1231 a) null if -U or the source repository has no changesets
1232 b) if -u . and the source repository is local, the first parent of
1232 b) if -u . and the source repository is local, the first parent of
1233 the source repository's working directory
1233 the source repository's working directory
1234 c) the changeset specified with -u (if a branch name, this means the
1234 c) the changeset specified with -u (if a branch name, this means the
1235 latest head of that branch)
1235 latest head of that branch)
1236 d) the changeset specified with -r
1236 d) the changeset specified with -r
1237 e) the tipmost head specified with -b
1237 e) the tipmost head specified with -b
1238 f) the tipmost head specified with the url#branch source syntax
1238 f) the tipmost head specified with the url#branch source syntax
1239 g) the revision marked with the '@' bookmark, if present
1239 g) the revision marked with the '@' bookmark, if present
1240 h) the tipmost head of the default branch
1240 h) the tipmost head of the default branch
1241 i) tip
1241 i) tip
1242
1242
1243 Examples:
1243 Examples:
1244
1244
1245 - clone a remote repository to a new directory named hg/::
1245 - clone a remote repository to a new directory named hg/::
1246
1246
1247 hg clone http://selenic.com/hg
1247 hg clone http://selenic.com/hg
1248
1248
1249 - create a lightweight local clone::
1249 - create a lightweight local clone::
1250
1250
1251 hg clone project/ project-feature/
1251 hg clone project/ project-feature/
1252
1252
1253 - clone from an absolute path on an ssh server (note double-slash)::
1253 - clone from an absolute path on an ssh server (note double-slash)::
1254
1254
1255 hg clone ssh://user@server//home/projects/alpha/
1255 hg clone ssh://user@server//home/projects/alpha/
1256
1256
1257 - do a high-speed clone over a LAN while checking out a
1257 - do a high-speed clone over a LAN while checking out a
1258 specified version::
1258 specified version::
1259
1259
1260 hg clone --uncompressed http://server/repo -u 1.5
1260 hg clone --uncompressed http://server/repo -u 1.5
1261
1261
1262 - create a repository without changesets after a particular revision::
1262 - create a repository without changesets after a particular revision::
1263
1263
1264 hg clone -r 04e544 experimental/ good/
1264 hg clone -r 04e544 experimental/ good/
1265
1265
1266 - clone (and track) a particular named branch::
1266 - clone (and track) a particular named branch::
1267
1267
1268 hg clone http://selenic.com/hg#stable
1268 hg clone http://selenic.com/hg#stable
1269
1269
1270 See :hg:`help urls` for details on specifying URLs.
1270 See :hg:`help urls` for details on specifying URLs.
1271
1271
1272 Returns 0 on success.
1272 Returns 0 on success.
1273 """
1273 """
1274 if opts.get('noupdate') and opts.get('updaterev'):
1274 if opts.get('noupdate') and opts.get('updaterev'):
1275 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1275 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1276
1276
1277 r = hg.clone(ui, opts, source, dest,
1277 r = hg.clone(ui, opts, source, dest,
1278 pull=opts.get('pull'),
1278 pull=opts.get('pull'),
1279 stream=opts.get('uncompressed'),
1279 stream=opts.get('uncompressed'),
1280 rev=opts.get('rev'),
1280 rev=opts.get('rev'),
1281 update=opts.get('updaterev') or not opts.get('noupdate'),
1281 update=opts.get('updaterev') or not opts.get('noupdate'),
1282 branch=opts.get('branch'))
1282 branch=opts.get('branch'))
1283
1283
1284 return r is None
1284 return r is None
1285
1285
1286 @command('^commit|ci',
1286 @command('^commit|ci',
1287 [('A', 'addremove', None,
1287 [('A', 'addremove', None,
1288 _('mark new/missing files as added/removed before committing')),
1288 _('mark new/missing files as added/removed before committing')),
1289 ('', 'close-branch', None,
1289 ('', 'close-branch', None,
1290 _('mark a branch as closed, hiding it from the branch list')),
1290 _('mark a branch as closed, hiding it from the branch list')),
1291 ('', 'amend', None, _('amend the parent of the working dir')),
1291 ('', 'amend', None, _('amend the parent of the working dir')),
1292 ('s', 'secret', None, _('use the secret phase for committing')),
1292 ('s', 'secret', None, _('use the secret phase for committing')),
1293 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1293 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1294 _('[OPTION]... [FILE]...'))
1294 _('[OPTION]... [FILE]...'))
1295 def commit(ui, repo, *pats, **opts):
1295 def commit(ui, repo, *pats, **opts):
1296 """commit the specified files or all outstanding changes
1296 """commit the specified files or all outstanding changes
1297
1297
1298 Commit changes to the given files into the repository. Unlike a
1298 Commit changes to the given files into the repository. Unlike a
1299 centralized SCM, this operation is a local operation. See
1299 centralized SCM, this operation is a local operation. See
1300 :hg:`push` for a way to actively distribute your changes.
1300 :hg:`push` for a way to actively distribute your changes.
1301
1301
1302 If a list of files is omitted, all changes reported by :hg:`status`
1302 If a list of files is omitted, all changes reported by :hg:`status`
1303 will be committed.
1303 will be committed.
1304
1304
1305 If you are committing the result of a merge, do not provide any
1305 If you are committing the result of a merge, do not provide any
1306 filenames or -I/-X filters.
1306 filenames or -I/-X filters.
1307
1307
1308 If no commit message is specified, Mercurial starts your
1308 If no commit message is specified, Mercurial starts your
1309 configured editor where you can enter a message. In case your
1309 configured editor where you can enter a message. In case your
1310 commit fails, you will find a backup of your message in
1310 commit fails, you will find a backup of your message in
1311 ``.hg/last-message.txt``.
1311 ``.hg/last-message.txt``.
1312
1312
1313 The --amend flag can be used to amend the parent of the
1313 The --amend flag can be used to amend the parent of the
1314 working directory with a new commit that contains the changes
1314 working directory with a new commit that contains the changes
1315 in the parent in addition to those currently reported by :hg:`status`,
1315 in the parent in addition to those currently reported by :hg:`status`,
1316 if there are any. The old commit is stored in a backup bundle in
1316 if there are any. The old commit is stored in a backup bundle in
1317 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1317 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1318 on how to restore it).
1318 on how to restore it).
1319
1319
1320 Message, user and date are taken from the amended commit unless
1320 Message, user and date are taken from the amended commit unless
1321 specified. When a message isn't specified on the command line,
1321 specified. When a message isn't specified on the command line,
1322 the editor will open with the message of the amended commit.
1322 the editor will open with the message of the amended commit.
1323
1323
1324 It is not possible to amend public changesets (see :hg:`help phases`)
1324 It is not possible to amend public changesets (see :hg:`help phases`)
1325 or changesets that have children.
1325 or changesets that have children.
1326
1326
1327 See :hg:`help dates` for a list of formats valid for -d/--date.
1327 See :hg:`help dates` for a list of formats valid for -d/--date.
1328
1328
1329 Returns 0 on success, 1 if nothing changed.
1329 Returns 0 on success, 1 if nothing changed.
1330 """
1330 """
1331 if opts.get('subrepos'):
1331 if opts.get('subrepos'):
1332 if opts.get('amend'):
1332 if opts.get('amend'):
1333 raise util.Abort(_('cannot amend with --subrepos'))
1333 raise util.Abort(_('cannot amend with --subrepos'))
1334 # Let --subrepos on the command line override config setting.
1334 # Let --subrepos on the command line override config setting.
1335 ui.setconfig('ui', 'commitsubrepos', True)
1335 ui.setconfig('ui', 'commitsubrepos', True)
1336
1336
1337 # Save this for restoring it later
1337 # Save this for restoring it later
1338 oldcommitphase = ui.config('phases', 'new-commit')
1338 oldcommitphase = ui.config('phases', 'new-commit')
1339
1339
1340 cmdutil.checkunfinished(repo, commit=True)
1340 cmdutil.checkunfinished(repo, commit=True)
1341
1341
1342 branch = repo[None].branch()
1342 branch = repo[None].branch()
1343 bheads = repo.branchheads(branch)
1343 bheads = repo.branchheads(branch)
1344
1344
1345 extra = {}
1345 extra = {}
1346 if opts.get('close_branch'):
1346 if opts.get('close_branch'):
1347 extra['close'] = 1
1347 extra['close'] = 1
1348
1348
1349 if not bheads:
1349 if not bheads:
1350 raise util.Abort(_('can only close branch heads'))
1350 raise util.Abort(_('can only close branch heads'))
1351 elif opts.get('amend'):
1351 elif opts.get('amend'):
1352 if repo.parents()[0].p1().branch() != branch and \
1352 if repo.parents()[0].p1().branch() != branch and \
1353 repo.parents()[0].p2().branch() != branch:
1353 repo.parents()[0].p2().branch() != branch:
1354 raise util.Abort(_('can only close branch heads'))
1354 raise util.Abort(_('can only close branch heads'))
1355
1355
1356 if opts.get('amend'):
1356 if opts.get('amend'):
1357 if ui.configbool('ui', 'commitsubrepos'):
1357 if ui.configbool('ui', 'commitsubrepos'):
1358 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1358 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1359
1359
1360 old = repo['.']
1360 old = repo['.']
1361 if old.phase() == phases.public:
1361 if old.phase() == phases.public:
1362 raise util.Abort(_('cannot amend public changesets'))
1362 raise util.Abort(_('cannot amend public changesets'))
1363 if len(repo[None].parents()) > 1:
1363 if len(repo[None].parents()) > 1:
1364 raise util.Abort(_('cannot amend while merging'))
1364 raise util.Abort(_('cannot amend while merging'))
1365 if (not obsolete._enabled) and old.children():
1365 if (not obsolete._enabled) and old.children():
1366 raise util.Abort(_('cannot amend changeset with children'))
1366 raise util.Abort(_('cannot amend changeset with children'))
1367
1367
1368 e = cmdutil.commiteditor
1368 e = cmdutil.commiteditor
1369 if opts.get('force_editor'):
1369 if opts.get('force_editor'):
1370 e = cmdutil.commitforceeditor
1370 e = cmdutil.commitforceeditor
1371
1371
1372 def commitfunc(ui, repo, message, match, opts):
1372 def commitfunc(ui, repo, message, match, opts):
1373 editor = e
1373 editor = e
1374 # message contains text from -m or -l, if it's empty,
1374 # message contains text from -m or -l, if it's empty,
1375 # open the editor with the old message
1375 # open the editor with the old message
1376 if not message:
1376 if not message:
1377 message = old.description()
1377 message = old.description()
1378 editor = cmdutil.commitforceeditor
1378 editor = cmdutil.commitforceeditor
1379 try:
1379 try:
1380 if opts.get('secret'):
1380 if opts.get('secret'):
1381 ui.setconfig('phases', 'new-commit', 'secret')
1381 ui.setconfig('phases', 'new-commit', 'secret')
1382
1382
1383 return repo.commit(message,
1383 return repo.commit(message,
1384 opts.get('user') or old.user(),
1384 opts.get('user') or old.user(),
1385 opts.get('date') or old.date(),
1385 opts.get('date') or old.date(),
1386 match,
1386 match,
1387 editor=editor,
1387 editor=editor,
1388 extra=extra)
1388 extra=extra)
1389 finally:
1389 finally:
1390 ui.setconfig('phases', 'new-commit', oldcommitphase)
1390 ui.setconfig('phases', 'new-commit', oldcommitphase)
1391
1391
1392 current = repo._bookmarkcurrent
1392 current = repo._bookmarkcurrent
1393 marks = old.bookmarks()
1393 marks = old.bookmarks()
1394 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1394 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1395 if node == old.node():
1395 if node == old.node():
1396 ui.status(_("nothing changed\n"))
1396 ui.status(_("nothing changed\n"))
1397 return 1
1397 return 1
1398 elif marks:
1398 elif marks:
1399 ui.debug('moving bookmarks %r from %s to %s\n' %
1399 ui.debug('moving bookmarks %r from %s to %s\n' %
1400 (marks, old.hex(), hex(node)))
1400 (marks, old.hex(), hex(node)))
1401 newmarks = repo._bookmarks
1401 newmarks = repo._bookmarks
1402 for bm in marks:
1402 for bm in marks:
1403 newmarks[bm] = node
1403 newmarks[bm] = node
1404 if bm == current:
1404 if bm == current:
1405 bookmarks.setcurrent(repo, bm)
1405 bookmarks.setcurrent(repo, bm)
1406 newmarks.write()
1406 newmarks.write()
1407 else:
1407 else:
1408 e = cmdutil.commiteditor
1408 e = cmdutil.commiteditor
1409 if opts.get('force_editor'):
1409 if opts.get('force_editor'):
1410 e = cmdutil.commitforceeditor
1410 e = cmdutil.commitforceeditor
1411
1411
1412 def commitfunc(ui, repo, message, match, opts):
1412 def commitfunc(ui, repo, message, match, opts):
1413 try:
1413 try:
1414 if opts.get('secret'):
1414 if opts.get('secret'):
1415 ui.setconfig('phases', 'new-commit', 'secret')
1415 ui.setconfig('phases', 'new-commit', 'secret')
1416
1416
1417 return repo.commit(message, opts.get('user'), opts.get('date'),
1417 return repo.commit(message, opts.get('user'), opts.get('date'),
1418 match, editor=e, extra=extra)
1418 match, editor=e, extra=extra)
1419 finally:
1419 finally:
1420 ui.setconfig('phases', 'new-commit', oldcommitphase)
1420 ui.setconfig('phases', 'new-commit', oldcommitphase)
1421
1421
1422
1422
1423 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1423 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1424
1424
1425 if not node:
1425 if not node:
1426 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1426 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1427 if stat[3]:
1427 if stat[3]:
1428 ui.status(_("nothing changed (%d missing files, see "
1428 ui.status(_("nothing changed (%d missing files, see "
1429 "'hg status')\n") % len(stat[3]))
1429 "'hg status')\n") % len(stat[3]))
1430 else:
1430 else:
1431 ui.status(_("nothing changed\n"))
1431 ui.status(_("nothing changed\n"))
1432 return 1
1432 return 1
1433
1433
1434 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1434 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1435
1435
1436 @command('copy|cp',
1436 @command('copy|cp',
1437 [('A', 'after', None, _('record a copy that has already occurred')),
1437 [('A', 'after', None, _('record a copy that has already occurred')),
1438 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1438 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1439 ] + walkopts + dryrunopts,
1439 ] + walkopts + dryrunopts,
1440 _('[OPTION]... [SOURCE]... DEST'))
1440 _('[OPTION]... [SOURCE]... DEST'))
1441 def copy(ui, repo, *pats, **opts):
1441 def copy(ui, repo, *pats, **opts):
1442 """mark files as copied for the next commit
1442 """mark files as copied for the next commit
1443
1443
1444 Mark dest as having copies of source files. If dest is a
1444 Mark dest as having copies of source files. If dest is a
1445 directory, copies are put in that directory. If dest is a file,
1445 directory, copies are put in that directory. If dest is a file,
1446 the source must be a single file.
1446 the source must be a single file.
1447
1447
1448 By default, this command copies the contents of files as they
1448 By default, this command copies the contents of files as they
1449 exist in the working directory. If invoked with -A/--after, the
1449 exist in the working directory. If invoked with -A/--after, the
1450 operation is recorded, but no copying is performed.
1450 operation is recorded, but no copying is performed.
1451
1451
1452 This command takes effect with the next commit. To undo a copy
1452 This command takes effect with the next commit. To undo a copy
1453 before that, see :hg:`revert`.
1453 before that, see :hg:`revert`.
1454
1454
1455 Returns 0 on success, 1 if errors are encountered.
1455 Returns 0 on success, 1 if errors are encountered.
1456 """
1456 """
1457 wlock = repo.wlock(False)
1457 wlock = repo.wlock(False)
1458 try:
1458 try:
1459 return cmdutil.copy(ui, repo, pats, opts)
1459 return cmdutil.copy(ui, repo, pats, opts)
1460 finally:
1460 finally:
1461 wlock.release()
1461 wlock.release()
1462
1462
1463 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1463 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1464 def debugancestor(ui, repo, *args):
1464 def debugancestor(ui, repo, *args):
1465 """find the ancestor revision of two revisions in a given index"""
1465 """find the ancestor revision of two revisions in a given index"""
1466 if len(args) == 3:
1466 if len(args) == 3:
1467 index, rev1, rev2 = args
1467 index, rev1, rev2 = args
1468 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1468 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1469 lookup = r.lookup
1469 lookup = r.lookup
1470 elif len(args) == 2:
1470 elif len(args) == 2:
1471 if not repo:
1471 if not repo:
1472 raise util.Abort(_("there is no Mercurial repository here "
1472 raise util.Abort(_("there is no Mercurial repository here "
1473 "(.hg not found)"))
1473 "(.hg not found)"))
1474 rev1, rev2 = args
1474 rev1, rev2 = args
1475 r = repo.changelog
1475 r = repo.changelog
1476 lookup = repo.lookup
1476 lookup = repo.lookup
1477 else:
1477 else:
1478 raise util.Abort(_('either two or three arguments required'))
1478 raise util.Abort(_('either two or three arguments required'))
1479 a = r.ancestor(lookup(rev1), lookup(rev2))
1479 a = r.ancestor(lookup(rev1), lookup(rev2))
1480 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1480 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1481
1481
1482 @command('debugbuilddag',
1482 @command('debugbuilddag',
1483 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1483 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1484 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1484 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1485 ('n', 'new-file', None, _('add new file at each rev'))],
1485 ('n', 'new-file', None, _('add new file at each rev'))],
1486 _('[OPTION]... [TEXT]'))
1486 _('[OPTION]... [TEXT]'))
1487 def debugbuilddag(ui, repo, text=None,
1487 def debugbuilddag(ui, repo, text=None,
1488 mergeable_file=False,
1488 mergeable_file=False,
1489 overwritten_file=False,
1489 overwritten_file=False,
1490 new_file=False):
1490 new_file=False):
1491 """builds a repo with a given DAG from scratch in the current empty repo
1491 """builds a repo with a given DAG from scratch in the current empty repo
1492
1492
1493 The description of the DAG is read from stdin if not given on the
1493 The description of the DAG is read from stdin if not given on the
1494 command line.
1494 command line.
1495
1495
1496 Elements:
1496 Elements:
1497
1497
1498 - "+n" is a linear run of n nodes based on the current default parent
1498 - "+n" is a linear run of n nodes based on the current default parent
1499 - "." is a single node based on the current default parent
1499 - "." is a single node based on the current default parent
1500 - "$" resets the default parent to null (implied at the start);
1500 - "$" resets the default parent to null (implied at the start);
1501 otherwise the default parent is always the last node created
1501 otherwise the default parent is always the last node created
1502 - "<p" sets the default parent to the backref p
1502 - "<p" sets the default parent to the backref p
1503 - "*p" is a fork at parent p, which is a backref
1503 - "*p" is a fork at parent p, which is a backref
1504 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1504 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1505 - "/p2" is a merge of the preceding node and p2
1505 - "/p2" is a merge of the preceding node and p2
1506 - ":tag" defines a local tag for the preceding node
1506 - ":tag" defines a local tag for the preceding node
1507 - "@branch" sets the named branch for subsequent nodes
1507 - "@branch" sets the named branch for subsequent nodes
1508 - "#...\\n" is a comment up to the end of the line
1508 - "#...\\n" is a comment up to the end of the line
1509
1509
1510 Whitespace between the above elements is ignored.
1510 Whitespace between the above elements is ignored.
1511
1511
1512 A backref is either
1512 A backref is either
1513
1513
1514 - a number n, which references the node curr-n, where curr is the current
1514 - a number n, which references the node curr-n, where curr is the current
1515 node, or
1515 node, or
1516 - the name of a local tag you placed earlier using ":tag", or
1516 - the name of a local tag you placed earlier using ":tag", or
1517 - empty to denote the default parent.
1517 - empty to denote the default parent.
1518
1518
1519 All string valued-elements are either strictly alphanumeric, or must
1519 All string valued-elements are either strictly alphanumeric, or must
1520 be enclosed in double quotes ("..."), with "\\" as escape character.
1520 be enclosed in double quotes ("..."), with "\\" as escape character.
1521 """
1521 """
1522
1522
1523 if text is None:
1523 if text is None:
1524 ui.status(_("reading DAG from stdin\n"))
1524 ui.status(_("reading DAG from stdin\n"))
1525 text = ui.fin.read()
1525 text = ui.fin.read()
1526
1526
1527 cl = repo.changelog
1527 cl = repo.changelog
1528 if len(cl) > 0:
1528 if len(cl) > 0:
1529 raise util.Abort(_('repository is not empty'))
1529 raise util.Abort(_('repository is not empty'))
1530
1530
1531 # determine number of revs in DAG
1531 # determine number of revs in DAG
1532 total = 0
1532 total = 0
1533 for type, data in dagparser.parsedag(text):
1533 for type, data in dagparser.parsedag(text):
1534 if type == 'n':
1534 if type == 'n':
1535 total += 1
1535 total += 1
1536
1536
1537 if mergeable_file:
1537 if mergeable_file:
1538 linesperrev = 2
1538 linesperrev = 2
1539 # make a file with k lines per rev
1539 # make a file with k lines per rev
1540 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1540 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1541 initialmergedlines.append("")
1541 initialmergedlines.append("")
1542
1542
1543 tags = []
1543 tags = []
1544
1544
1545 lock = tr = None
1545 lock = tr = None
1546 try:
1546 try:
1547 lock = repo.lock()
1547 lock = repo.lock()
1548 tr = repo.transaction("builddag")
1548 tr = repo.transaction("builddag")
1549
1549
1550 at = -1
1550 at = -1
1551 atbranch = 'default'
1551 atbranch = 'default'
1552 nodeids = []
1552 nodeids = []
1553 id = 0
1553 id = 0
1554 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1554 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1555 for type, data in dagparser.parsedag(text):
1555 for type, data in dagparser.parsedag(text):
1556 if type == 'n':
1556 if type == 'n':
1557 ui.note(('node %s\n' % str(data)))
1557 ui.note(('node %s\n' % str(data)))
1558 id, ps = data
1558 id, ps = data
1559
1559
1560 files = []
1560 files = []
1561 fctxs = {}
1561 fctxs = {}
1562
1562
1563 p2 = None
1563 p2 = None
1564 if mergeable_file:
1564 if mergeable_file:
1565 fn = "mf"
1565 fn = "mf"
1566 p1 = repo[ps[0]]
1566 p1 = repo[ps[0]]
1567 if len(ps) > 1:
1567 if len(ps) > 1:
1568 p2 = repo[ps[1]]
1568 p2 = repo[ps[1]]
1569 pa = p1.ancestor(p2)
1569 pa = p1.ancestor(p2)
1570 base, local, other = [x[fn].data() for x in (pa, p1,
1570 base, local, other = [x[fn].data() for x in (pa, p1,
1571 p2)]
1571 p2)]
1572 m3 = simplemerge.Merge3Text(base, local, other)
1572 m3 = simplemerge.Merge3Text(base, local, other)
1573 ml = [l.strip() for l in m3.merge_lines()]
1573 ml = [l.strip() for l in m3.merge_lines()]
1574 ml.append("")
1574 ml.append("")
1575 elif at > 0:
1575 elif at > 0:
1576 ml = p1[fn].data().split("\n")
1576 ml = p1[fn].data().split("\n")
1577 else:
1577 else:
1578 ml = initialmergedlines
1578 ml = initialmergedlines
1579 ml[id * linesperrev] += " r%i" % id
1579 ml[id * linesperrev] += " r%i" % id
1580 mergedtext = "\n".join(ml)
1580 mergedtext = "\n".join(ml)
1581 files.append(fn)
1581 files.append(fn)
1582 fctxs[fn] = context.memfilectx(fn, mergedtext)
1582 fctxs[fn] = context.memfilectx(fn, mergedtext)
1583
1583
1584 if overwritten_file:
1584 if overwritten_file:
1585 fn = "of"
1585 fn = "of"
1586 files.append(fn)
1586 files.append(fn)
1587 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1587 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1588
1588
1589 if new_file:
1589 if new_file:
1590 fn = "nf%i" % id
1590 fn = "nf%i" % id
1591 files.append(fn)
1591 files.append(fn)
1592 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1592 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1593 if len(ps) > 1:
1593 if len(ps) > 1:
1594 if not p2:
1594 if not p2:
1595 p2 = repo[ps[1]]
1595 p2 = repo[ps[1]]
1596 for fn in p2:
1596 for fn in p2:
1597 if fn.startswith("nf"):
1597 if fn.startswith("nf"):
1598 files.append(fn)
1598 files.append(fn)
1599 fctxs[fn] = p2[fn]
1599 fctxs[fn] = p2[fn]
1600
1600
1601 def fctxfn(repo, cx, path):
1601 def fctxfn(repo, cx, path):
1602 return fctxs.get(path)
1602 return fctxs.get(path)
1603
1603
1604 if len(ps) == 0 or ps[0] < 0:
1604 if len(ps) == 0 or ps[0] < 0:
1605 pars = [None, None]
1605 pars = [None, None]
1606 elif len(ps) == 1:
1606 elif len(ps) == 1:
1607 pars = [nodeids[ps[0]], None]
1607 pars = [nodeids[ps[0]], None]
1608 else:
1608 else:
1609 pars = [nodeids[p] for p in ps]
1609 pars = [nodeids[p] for p in ps]
1610 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1610 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1611 date=(id, 0),
1611 date=(id, 0),
1612 user="debugbuilddag",
1612 user="debugbuilddag",
1613 extra={'branch': atbranch})
1613 extra={'branch': atbranch})
1614 nodeid = repo.commitctx(cx)
1614 nodeid = repo.commitctx(cx)
1615 nodeids.append(nodeid)
1615 nodeids.append(nodeid)
1616 at = id
1616 at = id
1617 elif type == 'l':
1617 elif type == 'l':
1618 id, name = data
1618 id, name = data
1619 ui.note(('tag %s\n' % name))
1619 ui.note(('tag %s\n' % name))
1620 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1620 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1621 elif type == 'a':
1621 elif type == 'a':
1622 ui.note(('branch %s\n' % data))
1622 ui.note(('branch %s\n' % data))
1623 atbranch = data
1623 atbranch = data
1624 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1624 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1625 tr.close()
1625 tr.close()
1626
1626
1627 if tags:
1627 if tags:
1628 repo.opener.write("localtags", "".join(tags))
1628 repo.opener.write("localtags", "".join(tags))
1629 finally:
1629 finally:
1630 ui.progress(_('building'), None)
1630 ui.progress(_('building'), None)
1631 release(tr, lock)
1631 release(tr, lock)
1632
1632
1633 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1633 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1634 def debugbundle(ui, bundlepath, all=None, **opts):
1634 def debugbundle(ui, bundlepath, all=None, **opts):
1635 """lists the contents of a bundle"""
1635 """lists the contents of a bundle"""
1636 f = hg.openpath(ui, bundlepath)
1636 f = hg.openpath(ui, bundlepath)
1637 try:
1637 try:
1638 gen = changegroup.readbundle(f, bundlepath)
1638 gen = changegroup.readbundle(f, bundlepath)
1639 if all:
1639 if all:
1640 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1640 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1641
1641
1642 def showchunks(named):
1642 def showchunks(named):
1643 ui.write("\n%s\n" % named)
1643 ui.write("\n%s\n" % named)
1644 chain = None
1644 chain = None
1645 while True:
1645 while True:
1646 chunkdata = gen.deltachunk(chain)
1646 chunkdata = gen.deltachunk(chain)
1647 if not chunkdata:
1647 if not chunkdata:
1648 break
1648 break
1649 node = chunkdata['node']
1649 node = chunkdata['node']
1650 p1 = chunkdata['p1']
1650 p1 = chunkdata['p1']
1651 p2 = chunkdata['p2']
1651 p2 = chunkdata['p2']
1652 cs = chunkdata['cs']
1652 cs = chunkdata['cs']
1653 deltabase = chunkdata['deltabase']
1653 deltabase = chunkdata['deltabase']
1654 delta = chunkdata['delta']
1654 delta = chunkdata['delta']
1655 ui.write("%s %s %s %s %s %s\n" %
1655 ui.write("%s %s %s %s %s %s\n" %
1656 (hex(node), hex(p1), hex(p2),
1656 (hex(node), hex(p1), hex(p2),
1657 hex(cs), hex(deltabase), len(delta)))
1657 hex(cs), hex(deltabase), len(delta)))
1658 chain = node
1658 chain = node
1659
1659
1660 chunkdata = gen.changelogheader()
1660 chunkdata = gen.changelogheader()
1661 showchunks("changelog")
1661 showchunks("changelog")
1662 chunkdata = gen.manifestheader()
1662 chunkdata = gen.manifestheader()
1663 showchunks("manifest")
1663 showchunks("manifest")
1664 while True:
1664 while True:
1665 chunkdata = gen.filelogheader()
1665 chunkdata = gen.filelogheader()
1666 if not chunkdata:
1666 if not chunkdata:
1667 break
1667 break
1668 fname = chunkdata['filename']
1668 fname = chunkdata['filename']
1669 showchunks(fname)
1669 showchunks(fname)
1670 else:
1670 else:
1671 chunkdata = gen.changelogheader()
1671 chunkdata = gen.changelogheader()
1672 chain = None
1672 chain = None
1673 while True:
1673 while True:
1674 chunkdata = gen.deltachunk(chain)
1674 chunkdata = gen.deltachunk(chain)
1675 if not chunkdata:
1675 if not chunkdata:
1676 break
1676 break
1677 node = chunkdata['node']
1677 node = chunkdata['node']
1678 ui.write("%s\n" % hex(node))
1678 ui.write("%s\n" % hex(node))
1679 chain = node
1679 chain = node
1680 finally:
1680 finally:
1681 f.close()
1681 f.close()
1682
1682
1683 @command('debugcheckstate', [], '')
1683 @command('debugcheckstate', [], '')
1684 def debugcheckstate(ui, repo):
1684 def debugcheckstate(ui, repo):
1685 """validate the correctness of the current dirstate"""
1685 """validate the correctness of the current dirstate"""
1686 parent1, parent2 = repo.dirstate.parents()
1686 parent1, parent2 = repo.dirstate.parents()
1687 m1 = repo[parent1].manifest()
1687 m1 = repo[parent1].manifest()
1688 m2 = repo[parent2].manifest()
1688 m2 = repo[parent2].manifest()
1689 errors = 0
1689 errors = 0
1690 for f in repo.dirstate:
1690 for f in repo.dirstate:
1691 state = repo.dirstate[f]
1691 state = repo.dirstate[f]
1692 if state in "nr" and f not in m1:
1692 if state in "nr" and f not in m1:
1693 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1693 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1694 errors += 1
1694 errors += 1
1695 if state in "a" and f in m1:
1695 if state in "a" and f in m1:
1696 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1696 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1697 errors += 1
1697 errors += 1
1698 if state in "m" and f not in m1 and f not in m2:
1698 if state in "m" and f not in m1 and f not in m2:
1699 ui.warn(_("%s in state %s, but not in either manifest\n") %
1699 ui.warn(_("%s in state %s, but not in either manifest\n") %
1700 (f, state))
1700 (f, state))
1701 errors += 1
1701 errors += 1
1702 for f in m1:
1702 for f in m1:
1703 state = repo.dirstate[f]
1703 state = repo.dirstate[f]
1704 if state not in "nrm":
1704 if state not in "nrm":
1705 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1705 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1706 errors += 1
1706 errors += 1
1707 if errors:
1707 if errors:
1708 error = _(".hg/dirstate inconsistent with current parent's manifest")
1708 error = _(".hg/dirstate inconsistent with current parent's manifest")
1709 raise util.Abort(error)
1709 raise util.Abort(error)
1710
1710
1711 @command('debugcommands', [], _('[COMMAND]'))
1711 @command('debugcommands', [], _('[COMMAND]'))
1712 def debugcommands(ui, cmd='', *args):
1712 def debugcommands(ui, cmd='', *args):
1713 """list all available commands and options"""
1713 """list all available commands and options"""
1714 for cmd, vals in sorted(table.iteritems()):
1714 for cmd, vals in sorted(table.iteritems()):
1715 cmd = cmd.split('|')[0].strip('^')
1715 cmd = cmd.split('|')[0].strip('^')
1716 opts = ', '.join([i[1] for i in vals[1]])
1716 opts = ', '.join([i[1] for i in vals[1]])
1717 ui.write('%s: %s\n' % (cmd, opts))
1717 ui.write('%s: %s\n' % (cmd, opts))
1718
1718
1719 @command('debugcomplete',
1719 @command('debugcomplete',
1720 [('o', 'options', None, _('show the command options'))],
1720 [('o', 'options', None, _('show the command options'))],
1721 _('[-o] CMD'))
1721 _('[-o] CMD'))
1722 def debugcomplete(ui, cmd='', **opts):
1722 def debugcomplete(ui, cmd='', **opts):
1723 """returns the completion list associated with the given command"""
1723 """returns the completion list associated with the given command"""
1724
1724
1725 if opts.get('options'):
1725 if opts.get('options'):
1726 options = []
1726 options = []
1727 otables = [globalopts]
1727 otables = [globalopts]
1728 if cmd:
1728 if cmd:
1729 aliases, entry = cmdutil.findcmd(cmd, table, False)
1729 aliases, entry = cmdutil.findcmd(cmd, table, False)
1730 otables.append(entry[1])
1730 otables.append(entry[1])
1731 for t in otables:
1731 for t in otables:
1732 for o in t:
1732 for o in t:
1733 if "(DEPRECATED)" in o[3]:
1733 if "(DEPRECATED)" in o[3]:
1734 continue
1734 continue
1735 if o[0]:
1735 if o[0]:
1736 options.append('-%s' % o[0])
1736 options.append('-%s' % o[0])
1737 options.append('--%s' % o[1])
1737 options.append('--%s' % o[1])
1738 ui.write("%s\n" % "\n".join(options))
1738 ui.write("%s\n" % "\n".join(options))
1739 return
1739 return
1740
1740
1741 cmdlist = cmdutil.findpossible(cmd, table)
1741 cmdlist = cmdutil.findpossible(cmd, table)
1742 if ui.verbose:
1742 if ui.verbose:
1743 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1743 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1744 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1744 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1745
1745
1746 @command('debugdag',
1746 @command('debugdag',
1747 [('t', 'tags', None, _('use tags as labels')),
1747 [('t', 'tags', None, _('use tags as labels')),
1748 ('b', 'branches', None, _('annotate with branch names')),
1748 ('b', 'branches', None, _('annotate with branch names')),
1749 ('', 'dots', None, _('use dots for runs')),
1749 ('', 'dots', None, _('use dots for runs')),
1750 ('s', 'spaces', None, _('separate elements by spaces'))],
1750 ('s', 'spaces', None, _('separate elements by spaces'))],
1751 _('[OPTION]... [FILE [REV]...]'))
1751 _('[OPTION]... [FILE [REV]...]'))
1752 def debugdag(ui, repo, file_=None, *revs, **opts):
1752 def debugdag(ui, repo, file_=None, *revs, **opts):
1753 """format the changelog or an index DAG as a concise textual description
1753 """format the changelog or an index DAG as a concise textual description
1754
1754
1755 If you pass a revlog index, the revlog's DAG is emitted. If you list
1755 If you pass a revlog index, the revlog's DAG is emitted. If you list
1756 revision numbers, they get labeled in the output as rN.
1756 revision numbers, they get labeled in the output as rN.
1757
1757
1758 Otherwise, the changelog DAG of the current repo is emitted.
1758 Otherwise, the changelog DAG of the current repo is emitted.
1759 """
1759 """
1760 spaces = opts.get('spaces')
1760 spaces = opts.get('spaces')
1761 dots = opts.get('dots')
1761 dots = opts.get('dots')
1762 if file_:
1762 if file_:
1763 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1763 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1764 revs = set((int(r) for r in revs))
1764 revs = set((int(r) for r in revs))
1765 def events():
1765 def events():
1766 for r in rlog:
1766 for r in rlog:
1767 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1767 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1768 if p != -1)))
1768 if p != -1)))
1769 if r in revs:
1769 if r in revs:
1770 yield 'l', (r, "r%i" % r)
1770 yield 'l', (r, "r%i" % r)
1771 elif repo:
1771 elif repo:
1772 cl = repo.changelog
1772 cl = repo.changelog
1773 tags = opts.get('tags')
1773 tags = opts.get('tags')
1774 branches = opts.get('branches')
1774 branches = opts.get('branches')
1775 if tags:
1775 if tags:
1776 labels = {}
1776 labels = {}
1777 for l, n in repo.tags().items():
1777 for l, n in repo.tags().items():
1778 labels.setdefault(cl.rev(n), []).append(l)
1778 labels.setdefault(cl.rev(n), []).append(l)
1779 def events():
1779 def events():
1780 b = "default"
1780 b = "default"
1781 for r in cl:
1781 for r in cl:
1782 if branches:
1782 if branches:
1783 newb = cl.read(cl.node(r))[5]['branch']
1783 newb = cl.read(cl.node(r))[5]['branch']
1784 if newb != b:
1784 if newb != b:
1785 yield 'a', newb
1785 yield 'a', newb
1786 b = newb
1786 b = newb
1787 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1787 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1788 if p != -1)))
1788 if p != -1)))
1789 if tags:
1789 if tags:
1790 ls = labels.get(r)
1790 ls = labels.get(r)
1791 if ls:
1791 if ls:
1792 for l in ls:
1792 for l in ls:
1793 yield 'l', (r, l)
1793 yield 'l', (r, l)
1794 else:
1794 else:
1795 raise util.Abort(_('need repo for changelog dag'))
1795 raise util.Abort(_('need repo for changelog dag'))
1796
1796
1797 for line in dagparser.dagtextlines(events(),
1797 for line in dagparser.dagtextlines(events(),
1798 addspaces=spaces,
1798 addspaces=spaces,
1799 wraplabels=True,
1799 wraplabels=True,
1800 wrapannotations=True,
1800 wrapannotations=True,
1801 wrapnonlinear=dots,
1801 wrapnonlinear=dots,
1802 usedots=dots,
1802 usedots=dots,
1803 maxlinewidth=70):
1803 maxlinewidth=70):
1804 ui.write(line)
1804 ui.write(line)
1805 ui.write("\n")
1805 ui.write("\n")
1806
1806
1807 @command('debugdata',
1807 @command('debugdata',
1808 [('c', 'changelog', False, _('open changelog')),
1808 [('c', 'changelog', False, _('open changelog')),
1809 ('m', 'manifest', False, _('open manifest'))],
1809 ('m', 'manifest', False, _('open manifest'))],
1810 _('-c|-m|FILE REV'))
1810 _('-c|-m|FILE REV'))
1811 def debugdata(ui, repo, file_, rev=None, **opts):
1811 def debugdata(ui, repo, file_, rev=None, **opts):
1812 """dump the contents of a data file revision"""
1812 """dump the contents of a data file revision"""
1813 if opts.get('changelog') or opts.get('manifest'):
1813 if opts.get('changelog') or opts.get('manifest'):
1814 file_, rev = None, file_
1814 file_, rev = None, file_
1815 elif rev is None:
1815 elif rev is None:
1816 raise error.CommandError('debugdata', _('invalid arguments'))
1816 raise error.CommandError('debugdata', _('invalid arguments'))
1817 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1817 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1818 try:
1818 try:
1819 ui.write(r.revision(r.lookup(rev)))
1819 ui.write(r.revision(r.lookup(rev)))
1820 except KeyError:
1820 except KeyError:
1821 raise util.Abort(_('invalid revision identifier %s') % rev)
1821 raise util.Abort(_('invalid revision identifier %s') % rev)
1822
1822
1823 @command('debugdate',
1823 @command('debugdate',
1824 [('e', 'extended', None, _('try extended date formats'))],
1824 [('e', 'extended', None, _('try extended date formats'))],
1825 _('[-e] DATE [RANGE]'))
1825 _('[-e] DATE [RANGE]'))
1826 def debugdate(ui, date, range=None, **opts):
1826 def debugdate(ui, date, range=None, **opts):
1827 """parse and display a date"""
1827 """parse and display a date"""
1828 if opts["extended"]:
1828 if opts["extended"]:
1829 d = util.parsedate(date, util.extendeddateformats)
1829 d = util.parsedate(date, util.extendeddateformats)
1830 else:
1830 else:
1831 d = util.parsedate(date)
1831 d = util.parsedate(date)
1832 ui.write(("internal: %s %s\n") % d)
1832 ui.write(("internal: %s %s\n") % d)
1833 ui.write(("standard: %s\n") % util.datestr(d))
1833 ui.write(("standard: %s\n") % util.datestr(d))
1834 if range:
1834 if range:
1835 m = util.matchdate(range)
1835 m = util.matchdate(range)
1836 ui.write(("match: %s\n") % m(d[0]))
1836 ui.write(("match: %s\n") % m(d[0]))
1837
1837
1838 @command('debugdiscovery',
1838 @command('debugdiscovery',
1839 [('', 'old', None, _('use old-style discovery')),
1839 [('', 'old', None, _('use old-style discovery')),
1840 ('', 'nonheads', None,
1840 ('', 'nonheads', None,
1841 _('use old-style discovery with non-heads included')),
1841 _('use old-style discovery with non-heads included')),
1842 ] + remoteopts,
1842 ] + remoteopts,
1843 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1843 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1844 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1844 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1845 """runs the changeset discovery protocol in isolation"""
1845 """runs the changeset discovery protocol in isolation"""
1846 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1846 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1847 opts.get('branch'))
1847 opts.get('branch'))
1848 remote = hg.peer(repo, opts, remoteurl)
1848 remote = hg.peer(repo, opts, remoteurl)
1849 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1849 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1850
1850
1851 # make sure tests are repeatable
1851 # make sure tests are repeatable
1852 random.seed(12323)
1852 random.seed(12323)
1853
1853
1854 def doit(localheads, remoteheads, remote=remote):
1854 def doit(localheads, remoteheads, remote=remote):
1855 if opts.get('old'):
1855 if opts.get('old'):
1856 if localheads:
1856 if localheads:
1857 raise util.Abort('cannot use localheads with old style '
1857 raise util.Abort('cannot use localheads with old style '
1858 'discovery')
1858 'discovery')
1859 if not util.safehasattr(remote, 'branches'):
1859 if not util.safehasattr(remote, 'branches'):
1860 # enable in-client legacy support
1860 # enable in-client legacy support
1861 remote = localrepo.locallegacypeer(remote.local())
1861 remote = localrepo.locallegacypeer(remote.local())
1862 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1862 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1863 force=True)
1863 force=True)
1864 common = set(common)
1864 common = set(common)
1865 if not opts.get('nonheads'):
1865 if not opts.get('nonheads'):
1866 ui.write(("unpruned common: %s\n") %
1866 ui.write(("unpruned common: %s\n") %
1867 " ".join(sorted(short(n) for n in common)))
1867 " ".join(sorted(short(n) for n in common)))
1868 dag = dagutil.revlogdag(repo.changelog)
1868 dag = dagutil.revlogdag(repo.changelog)
1869 all = dag.ancestorset(dag.internalizeall(common))
1869 all = dag.ancestorset(dag.internalizeall(common))
1870 common = dag.externalizeall(dag.headsetofconnecteds(all))
1870 common = dag.externalizeall(dag.headsetofconnecteds(all))
1871 else:
1871 else:
1872 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1872 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1873 common = set(common)
1873 common = set(common)
1874 rheads = set(hds)
1874 rheads = set(hds)
1875 lheads = set(repo.heads())
1875 lheads = set(repo.heads())
1876 ui.write(("common heads: %s\n") %
1876 ui.write(("common heads: %s\n") %
1877 " ".join(sorted(short(n) for n in common)))
1877 " ".join(sorted(short(n) for n in common)))
1878 if lheads <= common:
1878 if lheads <= common:
1879 ui.write(("local is subset\n"))
1879 ui.write(("local is subset\n"))
1880 elif rheads <= common:
1880 elif rheads <= common:
1881 ui.write(("remote is subset\n"))
1881 ui.write(("remote is subset\n"))
1882
1882
1883 serverlogs = opts.get('serverlog')
1883 serverlogs = opts.get('serverlog')
1884 if serverlogs:
1884 if serverlogs:
1885 for filename in serverlogs:
1885 for filename in serverlogs:
1886 logfile = open(filename, 'r')
1886 logfile = open(filename, 'r')
1887 try:
1887 try:
1888 line = logfile.readline()
1888 line = logfile.readline()
1889 while line:
1889 while line:
1890 parts = line.strip().split(';')
1890 parts = line.strip().split(';')
1891 op = parts[1]
1891 op = parts[1]
1892 if op == 'cg':
1892 if op == 'cg':
1893 pass
1893 pass
1894 elif op == 'cgss':
1894 elif op == 'cgss':
1895 doit(parts[2].split(' '), parts[3].split(' '))
1895 doit(parts[2].split(' '), parts[3].split(' '))
1896 elif op == 'unb':
1896 elif op == 'unb':
1897 doit(parts[3].split(' '), parts[2].split(' '))
1897 doit(parts[3].split(' '), parts[2].split(' '))
1898 line = logfile.readline()
1898 line = logfile.readline()
1899 finally:
1899 finally:
1900 logfile.close()
1900 logfile.close()
1901
1901
1902 else:
1902 else:
1903 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1903 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1904 opts.get('remote_head'))
1904 opts.get('remote_head'))
1905 localrevs = opts.get('local_head')
1905 localrevs = opts.get('local_head')
1906 doit(localrevs, remoterevs)
1906 doit(localrevs, remoterevs)
1907
1907
1908 @command('debugfileset',
1908 @command('debugfileset',
1909 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1909 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1910 _('[-r REV] FILESPEC'))
1910 _('[-r REV] FILESPEC'))
1911 def debugfileset(ui, repo, expr, **opts):
1911 def debugfileset(ui, repo, expr, **opts):
1912 '''parse and apply a fileset specification'''
1912 '''parse and apply a fileset specification'''
1913 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1913 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1914 if ui.verbose:
1914 if ui.verbose:
1915 tree = fileset.parse(expr)[0]
1915 tree = fileset.parse(expr)[0]
1916 ui.note(tree, "\n")
1916 ui.note(tree, "\n")
1917
1917
1918 for f in fileset.getfileset(ctx, expr):
1918 for f in fileset.getfileset(ctx, expr):
1919 ui.write("%s\n" % f)
1919 ui.write("%s\n" % f)
1920
1920
1921 @command('debugfsinfo', [], _('[PATH]'))
1921 @command('debugfsinfo', [], _('[PATH]'))
1922 def debugfsinfo(ui, path="."):
1922 def debugfsinfo(ui, path="."):
1923 """show information detected about current filesystem"""
1923 """show information detected about current filesystem"""
1924 util.writefile('.debugfsinfo', '')
1924 util.writefile('.debugfsinfo', '')
1925 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1925 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1926 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1926 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1927 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1927 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
1928 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1928 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1929 and 'yes' or 'no'))
1929 and 'yes' or 'no'))
1930 os.unlink('.debugfsinfo')
1930 os.unlink('.debugfsinfo')
1931
1931
1932 @command('debuggetbundle',
1932 @command('debuggetbundle',
1933 [('H', 'head', [], _('id of head node'), _('ID')),
1933 [('H', 'head', [], _('id of head node'), _('ID')),
1934 ('C', 'common', [], _('id of common node'), _('ID')),
1934 ('C', 'common', [], _('id of common node'), _('ID')),
1935 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1935 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1936 _('REPO FILE [-H|-C ID]...'))
1936 _('REPO FILE [-H|-C ID]...'))
1937 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1937 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1938 """retrieves a bundle from a repo
1938 """retrieves a bundle from a repo
1939
1939
1940 Every ID must be a full-length hex node id string. Saves the bundle to the
1940 Every ID must be a full-length hex node id string. Saves the bundle to the
1941 given file.
1941 given file.
1942 """
1942 """
1943 repo = hg.peer(ui, opts, repopath)
1943 repo = hg.peer(ui, opts, repopath)
1944 if not repo.capable('getbundle'):
1944 if not repo.capable('getbundle'):
1945 raise util.Abort("getbundle() not supported by target repository")
1945 raise util.Abort("getbundle() not supported by target repository")
1946 args = {}
1946 args = {}
1947 if common:
1947 if common:
1948 args['common'] = [bin(s) for s in common]
1948 args['common'] = [bin(s) for s in common]
1949 if head:
1949 if head:
1950 args['heads'] = [bin(s) for s in head]
1950 args['heads'] = [bin(s) for s in head]
1951 # TODO: get desired bundlecaps from command line.
1951 # TODO: get desired bundlecaps from command line.
1952 args['bundlecaps'] = None
1952 args['bundlecaps'] = None
1953 bundle = repo.getbundle('debug', **args)
1953 bundle = repo.getbundle('debug', **args)
1954
1954
1955 bundletype = opts.get('type', 'bzip2').lower()
1955 bundletype = opts.get('type', 'bzip2').lower()
1956 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1956 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1957 bundletype = btypes.get(bundletype)
1957 bundletype = btypes.get(bundletype)
1958 if bundletype not in changegroup.bundletypes:
1958 if bundletype not in changegroup.bundletypes:
1959 raise util.Abort(_('unknown bundle type specified with --type'))
1959 raise util.Abort(_('unknown bundle type specified with --type'))
1960 changegroup.writebundle(bundle, bundlepath, bundletype)
1960 changegroup.writebundle(bundle, bundlepath, bundletype)
1961
1961
1962 @command('debugignore', [], '')
1962 @command('debugignore', [], '')
1963 def debugignore(ui, repo, *values, **opts):
1963 def debugignore(ui, repo, *values, **opts):
1964 """display the combined ignore pattern"""
1964 """display the combined ignore pattern"""
1965 ignore = repo.dirstate._ignore
1965 ignore = repo.dirstate._ignore
1966 includepat = getattr(ignore, 'includepat', None)
1966 includepat = getattr(ignore, 'includepat', None)
1967 if includepat is not None:
1967 if includepat is not None:
1968 ui.write("%s\n" % includepat)
1968 ui.write("%s\n" % includepat)
1969 else:
1969 else:
1970 raise util.Abort(_("no ignore patterns found"))
1970 raise util.Abort(_("no ignore patterns found"))
1971
1971
1972 @command('debugindex',
1972 @command('debugindex',
1973 [('c', 'changelog', False, _('open changelog')),
1973 [('c', 'changelog', False, _('open changelog')),
1974 ('m', 'manifest', False, _('open manifest')),
1974 ('m', 'manifest', False, _('open manifest')),
1975 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1975 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1976 _('[-f FORMAT] -c|-m|FILE'))
1976 _('[-f FORMAT] -c|-m|FILE'))
1977 def debugindex(ui, repo, file_=None, **opts):
1977 def debugindex(ui, repo, file_=None, **opts):
1978 """dump the contents of an index file"""
1978 """dump the contents of an index file"""
1979 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1979 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1980 format = opts.get('format', 0)
1980 format = opts.get('format', 0)
1981 if format not in (0, 1):
1981 if format not in (0, 1):
1982 raise util.Abort(_("unknown format %d") % format)
1982 raise util.Abort(_("unknown format %d") % format)
1983
1983
1984 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1984 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1985 if generaldelta:
1985 if generaldelta:
1986 basehdr = ' delta'
1986 basehdr = ' delta'
1987 else:
1987 else:
1988 basehdr = ' base'
1988 basehdr = ' base'
1989
1989
1990 if format == 0:
1990 if format == 0:
1991 ui.write(" rev offset length " + basehdr + " linkrev"
1991 ui.write(" rev offset length " + basehdr + " linkrev"
1992 " nodeid p1 p2\n")
1992 " nodeid p1 p2\n")
1993 elif format == 1:
1993 elif format == 1:
1994 ui.write(" rev flag offset length"
1994 ui.write(" rev flag offset length"
1995 " size " + basehdr + " link p1 p2"
1995 " size " + basehdr + " link p1 p2"
1996 " nodeid\n")
1996 " nodeid\n")
1997
1997
1998 for i in r:
1998 for i in r:
1999 node = r.node(i)
1999 node = r.node(i)
2000 if generaldelta:
2000 if generaldelta:
2001 base = r.deltaparent(i)
2001 base = r.deltaparent(i)
2002 else:
2002 else:
2003 base = r.chainbase(i)
2003 base = r.chainbase(i)
2004 if format == 0:
2004 if format == 0:
2005 try:
2005 try:
2006 pp = r.parents(node)
2006 pp = r.parents(node)
2007 except Exception:
2007 except Exception:
2008 pp = [nullid, nullid]
2008 pp = [nullid, nullid]
2009 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2009 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2010 i, r.start(i), r.length(i), base, r.linkrev(i),
2010 i, r.start(i), r.length(i), base, r.linkrev(i),
2011 short(node), short(pp[0]), short(pp[1])))
2011 short(node), short(pp[0]), short(pp[1])))
2012 elif format == 1:
2012 elif format == 1:
2013 pr = r.parentrevs(i)
2013 pr = r.parentrevs(i)
2014 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2014 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2015 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2015 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2016 base, r.linkrev(i), pr[0], pr[1], short(node)))
2016 base, r.linkrev(i), pr[0], pr[1], short(node)))
2017
2017
2018 @command('debugindexdot', [], _('FILE'))
2018 @command('debugindexdot', [], _('FILE'))
2019 def debugindexdot(ui, repo, file_):
2019 def debugindexdot(ui, repo, file_):
2020 """dump an index DAG as a graphviz dot file"""
2020 """dump an index DAG as a graphviz dot file"""
2021 r = None
2021 r = None
2022 if repo:
2022 if repo:
2023 filelog = repo.file(file_)
2023 filelog = repo.file(file_)
2024 if len(filelog):
2024 if len(filelog):
2025 r = filelog
2025 r = filelog
2026 if not r:
2026 if not r:
2027 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2027 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2028 ui.write(("digraph G {\n"))
2028 ui.write(("digraph G {\n"))
2029 for i in r:
2029 for i in r:
2030 node = r.node(i)
2030 node = r.node(i)
2031 pp = r.parents(node)
2031 pp = r.parents(node)
2032 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2032 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2033 if pp[1] != nullid:
2033 if pp[1] != nullid:
2034 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2034 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2035 ui.write("}\n")
2035 ui.write("}\n")
2036
2036
2037 @command('debuginstall', [], '')
2037 @command('debuginstall', [], '')
2038 def debuginstall(ui):
2038 def debuginstall(ui):
2039 '''test Mercurial installation
2039 '''test Mercurial installation
2040
2040
2041 Returns 0 on success.
2041 Returns 0 on success.
2042 '''
2042 '''
2043
2043
2044 def writetemp(contents):
2044 def writetemp(contents):
2045 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2045 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2046 f = os.fdopen(fd, "wb")
2046 f = os.fdopen(fd, "wb")
2047 f.write(contents)
2047 f.write(contents)
2048 f.close()
2048 f.close()
2049 return name
2049 return name
2050
2050
2051 problems = 0
2051 problems = 0
2052
2052
2053 # encoding
2053 # encoding
2054 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2054 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2055 try:
2055 try:
2056 encoding.fromlocal("test")
2056 encoding.fromlocal("test")
2057 except util.Abort, inst:
2057 except util.Abort, inst:
2058 ui.write(" %s\n" % inst)
2058 ui.write(" %s\n" % inst)
2059 ui.write(_(" (check that your locale is properly set)\n"))
2059 ui.write(_(" (check that your locale is properly set)\n"))
2060 problems += 1
2060 problems += 1
2061
2061
2062 # Python lib
2062 # Python lib
2063 ui.status(_("checking Python lib (%s)...\n")
2063 ui.status(_("checking Python lib (%s)...\n")
2064 % os.path.dirname(os.__file__))
2064 % os.path.dirname(os.__file__))
2065
2065
2066 # compiled modules
2066 # compiled modules
2067 ui.status(_("checking installed modules (%s)...\n")
2067 ui.status(_("checking installed modules (%s)...\n")
2068 % os.path.dirname(__file__))
2068 % os.path.dirname(__file__))
2069 try:
2069 try:
2070 import bdiff, mpatch, base85, osutil
2070 import bdiff, mpatch, base85, osutil
2071 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2071 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2072 except Exception, inst:
2072 except Exception, inst:
2073 ui.write(" %s\n" % inst)
2073 ui.write(" %s\n" % inst)
2074 ui.write(_(" One or more extensions could not be found"))
2074 ui.write(_(" One or more extensions could not be found"))
2075 ui.write(_(" (check that you compiled the extensions)\n"))
2075 ui.write(_(" (check that you compiled the extensions)\n"))
2076 problems += 1
2076 problems += 1
2077
2077
2078 # templates
2078 # templates
2079 import templater
2079 import templater
2080 p = templater.templatepath()
2080 p = templater.templatepath()
2081 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2081 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2082 try:
2082 try:
2083 templater.templater(templater.templatepath("map-cmdline.default"))
2083 templater.templater(templater.templatepath("map-cmdline.default"))
2084 except Exception, inst:
2084 except Exception, inst:
2085 ui.write(" %s\n" % inst)
2085 ui.write(" %s\n" % inst)
2086 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2086 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2087 problems += 1
2087 problems += 1
2088
2088
2089 # editor
2089 # editor
2090 ui.status(_("checking commit editor...\n"))
2090 ui.status(_("checking commit editor...\n"))
2091 editor = ui.geteditor()
2091 editor = ui.geteditor()
2092 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2092 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2093 if not cmdpath:
2093 if not cmdpath:
2094 if editor == 'vi':
2094 if editor == 'vi':
2095 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2095 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2096 ui.write(_(" (specify a commit editor in your configuration"
2096 ui.write(_(" (specify a commit editor in your configuration"
2097 " file)\n"))
2097 " file)\n"))
2098 else:
2098 else:
2099 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2099 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2100 ui.write(_(" (specify a commit editor in your configuration"
2100 ui.write(_(" (specify a commit editor in your configuration"
2101 " file)\n"))
2101 " file)\n"))
2102 problems += 1
2102 problems += 1
2103
2103
2104 # check username
2104 # check username
2105 ui.status(_("checking username...\n"))
2105 ui.status(_("checking username...\n"))
2106 try:
2106 try:
2107 ui.username()
2107 ui.username()
2108 except util.Abort, e:
2108 except util.Abort, e:
2109 ui.write(" %s\n" % e)
2109 ui.write(" %s\n" % e)
2110 ui.write(_(" (specify a username in your configuration file)\n"))
2110 ui.write(_(" (specify a username in your configuration file)\n"))
2111 problems += 1
2111 problems += 1
2112
2112
2113 if not problems:
2113 if not problems:
2114 ui.status(_("no problems detected\n"))
2114 ui.status(_("no problems detected\n"))
2115 else:
2115 else:
2116 ui.write(_("%s problems detected,"
2116 ui.write(_("%s problems detected,"
2117 " please check your install!\n") % problems)
2117 " please check your install!\n") % problems)
2118
2118
2119 return problems
2119 return problems
2120
2120
2121 @command('debugknown', [], _('REPO ID...'))
2121 @command('debugknown', [], _('REPO ID...'))
2122 def debugknown(ui, repopath, *ids, **opts):
2122 def debugknown(ui, repopath, *ids, **opts):
2123 """test whether node ids are known to a repo
2123 """test whether node ids are known to a repo
2124
2124
2125 Every ID must be a full-length hex node id string. Returns a list of 0s
2125 Every ID must be a full-length hex node id string. Returns a list of 0s
2126 and 1s indicating unknown/known.
2126 and 1s indicating unknown/known.
2127 """
2127 """
2128 repo = hg.peer(ui, opts, repopath)
2128 repo = hg.peer(ui, opts, repopath)
2129 if not repo.capable('known'):
2129 if not repo.capable('known'):
2130 raise util.Abort("known() not supported by target repository")
2130 raise util.Abort("known() not supported by target repository")
2131 flags = repo.known([bin(s) for s in ids])
2131 flags = repo.known([bin(s) for s in ids])
2132 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2132 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2133
2133
2134 @command('debuglabelcomplete', [], _('LABEL...'))
2134 @command('debuglabelcomplete', [], _('LABEL...'))
2135 def debuglabelcomplete(ui, repo, *args):
2135 def debuglabelcomplete(ui, repo, *args):
2136 '''complete "labels" - tags, open branch names, bookmark names'''
2136 '''complete "labels" - tags, open branch names, bookmark names'''
2137
2137
2138 labels = set()
2138 labels = set()
2139 labels.update(t[0] for t in repo.tagslist())
2139 labels.update(t[0] for t in repo.tagslist())
2140 labels.update(repo._bookmarks.keys())
2140 labels.update(repo._bookmarks.keys())
2141 for heads in repo.branchmap().itervalues():
2141 for heads in repo.branchmap().itervalues():
2142 for h in heads:
2142 for h in heads:
2143 ctx = repo[h]
2143 ctx = repo[h]
2144 if not ctx.closesbranch():
2144 if not ctx.closesbranch():
2145 labels.add(ctx.branch())
2145 labels.add(ctx.branch())
2146 completions = set()
2146 completions = set()
2147 if not args:
2147 if not args:
2148 args = ['']
2148 args = ['']
2149 for a in args:
2149 for a in args:
2150 completions.update(l for l in labels if l.startswith(a))
2150 completions.update(l for l in labels if l.startswith(a))
2151 ui.write('\n'.join(sorted(completions)))
2151 ui.write('\n'.join(sorted(completions)))
2152 ui.write('\n')
2152 ui.write('\n')
2153
2153
2154 @command('debugobsolete',
2154 @command('debugobsolete',
2155 [('', 'flags', 0, _('markers flag')),
2155 [('', 'flags', 0, _('markers flag')),
2156 ] + commitopts2,
2156 ] + commitopts2,
2157 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2157 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2158 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2158 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2159 """create arbitrary obsolete marker
2159 """create arbitrary obsolete marker
2160
2160
2161 With no arguments, displays the list of obsolescence markers."""
2161 With no arguments, displays the list of obsolescence markers."""
2162 def parsenodeid(s):
2162 def parsenodeid(s):
2163 try:
2163 try:
2164 # We do not use revsingle/revrange functions here to accept
2164 # We do not use revsingle/revrange functions here to accept
2165 # arbitrary node identifiers, possibly not present in the
2165 # arbitrary node identifiers, possibly not present in the
2166 # local repository.
2166 # local repository.
2167 n = bin(s)
2167 n = bin(s)
2168 if len(n) != len(nullid):
2168 if len(n) != len(nullid):
2169 raise TypeError()
2169 raise TypeError()
2170 return n
2170 return n
2171 except TypeError:
2171 except TypeError:
2172 raise util.Abort('changeset references must be full hexadecimal '
2172 raise util.Abort('changeset references must be full hexadecimal '
2173 'node identifiers')
2173 'node identifiers')
2174
2174
2175 if precursor is not None:
2175 if precursor is not None:
2176 metadata = {}
2176 metadata = {}
2177 if 'date' in opts:
2177 if 'date' in opts:
2178 metadata['date'] = opts['date']
2178 metadata['date'] = opts['date']
2179 metadata['user'] = opts['user'] or ui.username()
2179 metadata['user'] = opts['user'] or ui.username()
2180 succs = tuple(parsenodeid(succ) for succ in successors)
2180 succs = tuple(parsenodeid(succ) for succ in successors)
2181 l = repo.lock()
2181 l = repo.lock()
2182 try:
2182 try:
2183 tr = repo.transaction('debugobsolete')
2183 tr = repo.transaction('debugobsolete')
2184 try:
2184 try:
2185 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2185 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2186 opts['flags'], metadata)
2186 opts['flags'], metadata)
2187 tr.close()
2187 tr.close()
2188 finally:
2188 finally:
2189 tr.release()
2189 tr.release()
2190 finally:
2190 finally:
2191 l.release()
2191 l.release()
2192 else:
2192 else:
2193 for m in obsolete.allmarkers(repo):
2193 for m in obsolete.allmarkers(repo):
2194 ui.write(hex(m.precnode()))
2194 ui.write(hex(m.precnode()))
2195 for repl in m.succnodes():
2195 for repl in m.succnodes():
2196 ui.write(' ')
2196 ui.write(' ')
2197 ui.write(hex(repl))
2197 ui.write(hex(repl))
2198 ui.write(' %X ' % m._data[2])
2198 ui.write(' %X ' % m._data[2])
2199 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2199 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2200 sorted(m.metadata().items()))))
2200 sorted(m.metadata().items()))))
2201 ui.write('\n')
2201 ui.write('\n')
2202
2202
2203 @command('debugpathcomplete',
2203 @command('debugpathcomplete',
2204 [('f', 'full', None, _('complete an entire path')),
2204 [('f', 'full', None, _('complete an entire path')),
2205 ('n', 'normal', None, _('show only normal files')),
2205 ('n', 'normal', None, _('show only normal files')),
2206 ('a', 'added', None, _('show only added files')),
2206 ('a', 'added', None, _('show only added files')),
2207 ('r', 'removed', None, _('show only removed files'))],
2207 ('r', 'removed', None, _('show only removed files'))],
2208 _('FILESPEC...'))
2208 _('FILESPEC...'))
2209 def debugpathcomplete(ui, repo, *specs, **opts):
2209 def debugpathcomplete(ui, repo, *specs, **opts):
2210 '''complete part or all of a tracked path
2210 '''complete part or all of a tracked path
2211
2211
2212 This command supports shells that offer path name completion. It
2212 This command supports shells that offer path name completion. It
2213 currently completes only files already known to the dirstate.
2213 currently completes only files already known to the dirstate.
2214
2214
2215 Completion extends only to the next path segment unless
2215 Completion extends only to the next path segment unless
2216 --full is specified, in which case entire paths are used.'''
2216 --full is specified, in which case entire paths are used.'''
2217
2217
2218 def complete(path, acceptable):
2218 def complete(path, acceptable):
2219 dirstate = repo.dirstate
2219 dirstate = repo.dirstate
2220 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2220 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2221 rootdir = repo.root + os.sep
2221 rootdir = repo.root + os.sep
2222 if spec != repo.root and not spec.startswith(rootdir):
2222 if spec != repo.root and not spec.startswith(rootdir):
2223 return [], []
2223 return [], []
2224 if os.path.isdir(spec):
2224 if os.path.isdir(spec):
2225 spec += '/'
2225 spec += '/'
2226 spec = spec[len(rootdir):]
2226 spec = spec[len(rootdir):]
2227 fixpaths = os.sep != '/'
2227 fixpaths = os.sep != '/'
2228 if fixpaths:
2228 if fixpaths:
2229 spec = spec.replace(os.sep, '/')
2229 spec = spec.replace(os.sep, '/')
2230 speclen = len(spec)
2230 speclen = len(spec)
2231 fullpaths = opts['full']
2231 fullpaths = opts['full']
2232 files, dirs = set(), set()
2232 files, dirs = set(), set()
2233 adddir, addfile = dirs.add, files.add
2233 adddir, addfile = dirs.add, files.add
2234 for f, st in dirstate.iteritems():
2234 for f, st in dirstate.iteritems():
2235 if f.startswith(spec) and st[0] in acceptable:
2235 if f.startswith(spec) and st[0] in acceptable:
2236 if fixpaths:
2236 if fixpaths:
2237 f = f.replace('/', os.sep)
2237 f = f.replace('/', os.sep)
2238 if fullpaths:
2238 if fullpaths:
2239 addfile(f)
2239 addfile(f)
2240 continue
2240 continue
2241 s = f.find(os.sep, speclen)
2241 s = f.find(os.sep, speclen)
2242 if s >= 0:
2242 if s >= 0:
2243 adddir(f[:s + 1])
2243 adddir(f[:s + 1])
2244 else:
2244 else:
2245 addfile(f)
2245 addfile(f)
2246 return files, dirs
2246 return files, dirs
2247
2247
2248 acceptable = ''
2248 acceptable = ''
2249 if opts['normal']:
2249 if opts['normal']:
2250 acceptable += 'nm'
2250 acceptable += 'nm'
2251 if opts['added']:
2251 if opts['added']:
2252 acceptable += 'a'
2252 acceptable += 'a'
2253 if opts['removed']:
2253 if opts['removed']:
2254 acceptable += 'r'
2254 acceptable += 'r'
2255 cwd = repo.getcwd()
2255 cwd = repo.getcwd()
2256 if not specs:
2256 if not specs:
2257 specs = ['.']
2257 specs = ['.']
2258
2258
2259 files, dirs = set(), set()
2259 files, dirs = set(), set()
2260 for spec in specs:
2260 for spec in specs:
2261 f, d = complete(spec, acceptable or 'nmar')
2261 f, d = complete(spec, acceptable or 'nmar')
2262 files.update(f)
2262 files.update(f)
2263 dirs.update(d)
2263 dirs.update(d)
2264 if not files and len(dirs) == 1:
2264 if not files and len(dirs) == 1:
2265 # force the shell to consider a completion that matches one
2265 # force the shell to consider a completion that matches one
2266 # directory and zero files to be ambiguous
2266 # directory and zero files to be ambiguous
2267 dirs.add(iter(dirs).next() + '.')
2267 dirs.add(iter(dirs).next() + '.')
2268 files.update(dirs)
2268 files.update(dirs)
2269 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2269 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2270 ui.write('\n')
2270 ui.write('\n')
2271
2271
2272 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2272 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2273 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2273 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2274 '''access the pushkey key/value protocol
2274 '''access the pushkey key/value protocol
2275
2275
2276 With two args, list the keys in the given namespace.
2276 With two args, list the keys in the given namespace.
2277
2277
2278 With five args, set a key to new if it currently is set to old.
2278 With five args, set a key to new if it currently is set to old.
2279 Reports success or failure.
2279 Reports success or failure.
2280 '''
2280 '''
2281
2281
2282 target = hg.peer(ui, {}, repopath)
2282 target = hg.peer(ui, {}, repopath)
2283 if keyinfo:
2283 if keyinfo:
2284 key, old, new = keyinfo
2284 key, old, new = keyinfo
2285 r = target.pushkey(namespace, key, old, new)
2285 r = target.pushkey(namespace, key, old, new)
2286 ui.status(str(r) + '\n')
2286 ui.status(str(r) + '\n')
2287 return not r
2287 return not r
2288 else:
2288 else:
2289 for k, v in sorted(target.listkeys(namespace).iteritems()):
2289 for k, v in sorted(target.listkeys(namespace).iteritems()):
2290 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2290 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2291 v.encode('string-escape')))
2291 v.encode('string-escape')))
2292
2292
2293 @command('debugpvec', [], _('A B'))
2293 @command('debugpvec', [], _('A B'))
2294 def debugpvec(ui, repo, a, b=None):
2294 def debugpvec(ui, repo, a, b=None):
2295 ca = scmutil.revsingle(repo, a)
2295 ca = scmutil.revsingle(repo, a)
2296 cb = scmutil.revsingle(repo, b)
2296 cb = scmutil.revsingle(repo, b)
2297 pa = pvec.ctxpvec(ca)
2297 pa = pvec.ctxpvec(ca)
2298 pb = pvec.ctxpvec(cb)
2298 pb = pvec.ctxpvec(cb)
2299 if pa == pb:
2299 if pa == pb:
2300 rel = "="
2300 rel = "="
2301 elif pa > pb:
2301 elif pa > pb:
2302 rel = ">"
2302 rel = ">"
2303 elif pa < pb:
2303 elif pa < pb:
2304 rel = "<"
2304 rel = "<"
2305 elif pa | pb:
2305 elif pa | pb:
2306 rel = "|"
2306 rel = "|"
2307 ui.write(_("a: %s\n") % pa)
2307 ui.write(_("a: %s\n") % pa)
2308 ui.write(_("b: %s\n") % pb)
2308 ui.write(_("b: %s\n") % pb)
2309 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2309 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2310 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2310 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2311 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2311 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2312 pa.distance(pb), rel))
2312 pa.distance(pb), rel))
2313
2313
2314 @command('debugrebuilddirstate|debugrebuildstate',
2314 @command('debugrebuilddirstate|debugrebuildstate',
2315 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2315 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2316 _('[-r REV]'))
2316 _('[-r REV]'))
2317 def debugrebuilddirstate(ui, repo, rev):
2317 def debugrebuilddirstate(ui, repo, rev):
2318 """rebuild the dirstate as it would look like for the given revision
2318 """rebuild the dirstate as it would look like for the given revision
2319
2319
2320 If no revision is specified the first current parent will be used.
2320 If no revision is specified the first current parent will be used.
2321
2321
2322 The dirstate will be set to the files of the given revision.
2322 The dirstate will be set to the files of the given revision.
2323 The actual working directory content or existing dirstate
2323 The actual working directory content or existing dirstate
2324 information such as adds or removes is not considered.
2324 information such as adds or removes is not considered.
2325
2325
2326 One use of this command is to make the next :hg:`status` invocation
2326 One use of this command is to make the next :hg:`status` invocation
2327 check the actual file content.
2327 check the actual file content.
2328 """
2328 """
2329 ctx = scmutil.revsingle(repo, rev)
2329 ctx = scmutil.revsingle(repo, rev)
2330 wlock = repo.wlock()
2330 wlock = repo.wlock()
2331 try:
2331 try:
2332 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2332 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2333 finally:
2333 finally:
2334 wlock.release()
2334 wlock.release()
2335
2335
2336 @command('debugrename',
2336 @command('debugrename',
2337 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2337 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2338 _('[-r REV] FILE'))
2338 _('[-r REV] FILE'))
2339 def debugrename(ui, repo, file1, *pats, **opts):
2339 def debugrename(ui, repo, file1, *pats, **opts):
2340 """dump rename information"""
2340 """dump rename information"""
2341
2341
2342 ctx = scmutil.revsingle(repo, opts.get('rev'))
2342 ctx = scmutil.revsingle(repo, opts.get('rev'))
2343 m = scmutil.match(ctx, (file1,) + pats, opts)
2343 m = scmutil.match(ctx, (file1,) + pats, opts)
2344 for abs in ctx.walk(m):
2344 for abs in ctx.walk(m):
2345 fctx = ctx[abs]
2345 fctx = ctx[abs]
2346 o = fctx.filelog().renamed(fctx.filenode())
2346 o = fctx.filelog().renamed(fctx.filenode())
2347 rel = m.rel(abs)
2347 rel = m.rel(abs)
2348 if o:
2348 if o:
2349 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2349 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2350 else:
2350 else:
2351 ui.write(_("%s not renamed\n") % rel)
2351 ui.write(_("%s not renamed\n") % rel)
2352
2352
2353 @command('debugrevlog',
2353 @command('debugrevlog',
2354 [('c', 'changelog', False, _('open changelog')),
2354 [('c', 'changelog', False, _('open changelog')),
2355 ('m', 'manifest', False, _('open manifest')),
2355 ('m', 'manifest', False, _('open manifest')),
2356 ('d', 'dump', False, _('dump index data'))],
2356 ('d', 'dump', False, _('dump index data'))],
2357 _('-c|-m|FILE'))
2357 _('-c|-m|FILE'))
2358 def debugrevlog(ui, repo, file_=None, **opts):
2358 def debugrevlog(ui, repo, file_=None, **opts):
2359 """show data and statistics about a revlog"""
2359 """show data and statistics about a revlog"""
2360 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2360 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2361
2361
2362 if opts.get("dump"):
2362 if opts.get("dump"):
2363 numrevs = len(r)
2363 numrevs = len(r)
2364 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2364 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2365 " rawsize totalsize compression heads\n")
2365 " rawsize totalsize compression heads\n")
2366 ts = 0
2366 ts = 0
2367 heads = set()
2367 heads = set()
2368 for rev in xrange(numrevs):
2368 for rev in xrange(numrevs):
2369 dbase = r.deltaparent(rev)
2369 dbase = r.deltaparent(rev)
2370 if dbase == -1:
2370 if dbase == -1:
2371 dbase = rev
2371 dbase = rev
2372 cbase = r.chainbase(rev)
2372 cbase = r.chainbase(rev)
2373 p1, p2 = r.parentrevs(rev)
2373 p1, p2 = r.parentrevs(rev)
2374 rs = r.rawsize(rev)
2374 rs = r.rawsize(rev)
2375 ts = ts + rs
2375 ts = ts + rs
2376 heads -= set(r.parentrevs(rev))
2376 heads -= set(r.parentrevs(rev))
2377 heads.add(rev)
2377 heads.add(rev)
2378 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2378 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2379 (rev, p1, p2, r.start(rev), r.end(rev),
2379 (rev, p1, p2, r.start(rev), r.end(rev),
2380 r.start(dbase), r.start(cbase),
2380 r.start(dbase), r.start(cbase),
2381 r.start(p1), r.start(p2),
2381 r.start(p1), r.start(p2),
2382 rs, ts, ts / r.end(rev), len(heads)))
2382 rs, ts, ts / r.end(rev), len(heads)))
2383 return 0
2383 return 0
2384
2384
2385 v = r.version
2385 v = r.version
2386 format = v & 0xFFFF
2386 format = v & 0xFFFF
2387 flags = []
2387 flags = []
2388 gdelta = False
2388 gdelta = False
2389 if v & revlog.REVLOGNGINLINEDATA:
2389 if v & revlog.REVLOGNGINLINEDATA:
2390 flags.append('inline')
2390 flags.append('inline')
2391 if v & revlog.REVLOGGENERALDELTA:
2391 if v & revlog.REVLOGGENERALDELTA:
2392 gdelta = True
2392 gdelta = True
2393 flags.append('generaldelta')
2393 flags.append('generaldelta')
2394 if not flags:
2394 if not flags:
2395 flags = ['(none)']
2395 flags = ['(none)']
2396
2396
2397 nummerges = 0
2397 nummerges = 0
2398 numfull = 0
2398 numfull = 0
2399 numprev = 0
2399 numprev = 0
2400 nump1 = 0
2400 nump1 = 0
2401 nump2 = 0
2401 nump2 = 0
2402 numother = 0
2402 numother = 0
2403 nump1prev = 0
2403 nump1prev = 0
2404 nump2prev = 0
2404 nump2prev = 0
2405 chainlengths = []
2405 chainlengths = []
2406
2406
2407 datasize = [None, 0, 0L]
2407 datasize = [None, 0, 0L]
2408 fullsize = [None, 0, 0L]
2408 fullsize = [None, 0, 0L]
2409 deltasize = [None, 0, 0L]
2409 deltasize = [None, 0, 0L]
2410
2410
2411 def addsize(size, l):
2411 def addsize(size, l):
2412 if l[0] is None or size < l[0]:
2412 if l[0] is None or size < l[0]:
2413 l[0] = size
2413 l[0] = size
2414 if size > l[1]:
2414 if size > l[1]:
2415 l[1] = size
2415 l[1] = size
2416 l[2] += size
2416 l[2] += size
2417
2417
2418 numrevs = len(r)
2418 numrevs = len(r)
2419 for rev in xrange(numrevs):
2419 for rev in xrange(numrevs):
2420 p1, p2 = r.parentrevs(rev)
2420 p1, p2 = r.parentrevs(rev)
2421 delta = r.deltaparent(rev)
2421 delta = r.deltaparent(rev)
2422 if format > 0:
2422 if format > 0:
2423 addsize(r.rawsize(rev), datasize)
2423 addsize(r.rawsize(rev), datasize)
2424 if p2 != nullrev:
2424 if p2 != nullrev:
2425 nummerges += 1
2425 nummerges += 1
2426 size = r.length(rev)
2426 size = r.length(rev)
2427 if delta == nullrev:
2427 if delta == nullrev:
2428 chainlengths.append(0)
2428 chainlengths.append(0)
2429 numfull += 1
2429 numfull += 1
2430 addsize(size, fullsize)
2430 addsize(size, fullsize)
2431 else:
2431 else:
2432 chainlengths.append(chainlengths[delta] + 1)
2432 chainlengths.append(chainlengths[delta] + 1)
2433 addsize(size, deltasize)
2433 addsize(size, deltasize)
2434 if delta == rev - 1:
2434 if delta == rev - 1:
2435 numprev += 1
2435 numprev += 1
2436 if delta == p1:
2436 if delta == p1:
2437 nump1prev += 1
2437 nump1prev += 1
2438 elif delta == p2:
2438 elif delta == p2:
2439 nump2prev += 1
2439 nump2prev += 1
2440 elif delta == p1:
2440 elif delta == p1:
2441 nump1 += 1
2441 nump1 += 1
2442 elif delta == p2:
2442 elif delta == p2:
2443 nump2 += 1
2443 nump2 += 1
2444 elif delta != nullrev:
2444 elif delta != nullrev:
2445 numother += 1
2445 numother += 1
2446
2446
2447 # Adjust size min value for empty cases
2447 # Adjust size min value for empty cases
2448 for size in (datasize, fullsize, deltasize):
2448 for size in (datasize, fullsize, deltasize):
2449 if size[0] is None:
2449 if size[0] is None:
2450 size[0] = 0
2450 size[0] = 0
2451
2451
2452 numdeltas = numrevs - numfull
2452 numdeltas = numrevs - numfull
2453 numoprev = numprev - nump1prev - nump2prev
2453 numoprev = numprev - nump1prev - nump2prev
2454 totalrawsize = datasize[2]
2454 totalrawsize = datasize[2]
2455 datasize[2] /= numrevs
2455 datasize[2] /= numrevs
2456 fulltotal = fullsize[2]
2456 fulltotal = fullsize[2]
2457 fullsize[2] /= numfull
2457 fullsize[2] /= numfull
2458 deltatotal = deltasize[2]
2458 deltatotal = deltasize[2]
2459 if numrevs - numfull > 0:
2459 if numrevs - numfull > 0:
2460 deltasize[2] /= numrevs - numfull
2460 deltasize[2] /= numrevs - numfull
2461 totalsize = fulltotal + deltatotal
2461 totalsize = fulltotal + deltatotal
2462 avgchainlen = sum(chainlengths) / numrevs
2462 avgchainlen = sum(chainlengths) / numrevs
2463 compratio = totalrawsize / totalsize
2463 compratio = totalrawsize / totalsize
2464
2464
2465 basedfmtstr = '%%%dd\n'
2465 basedfmtstr = '%%%dd\n'
2466 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2466 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2467
2467
2468 def dfmtstr(max):
2468 def dfmtstr(max):
2469 return basedfmtstr % len(str(max))
2469 return basedfmtstr % len(str(max))
2470 def pcfmtstr(max, padding=0):
2470 def pcfmtstr(max, padding=0):
2471 return basepcfmtstr % (len(str(max)), ' ' * padding)
2471 return basepcfmtstr % (len(str(max)), ' ' * padding)
2472
2472
2473 def pcfmt(value, total):
2473 def pcfmt(value, total):
2474 return (value, 100 * float(value) / total)
2474 return (value, 100 * float(value) / total)
2475
2475
2476 ui.write(('format : %d\n') % format)
2476 ui.write(('format : %d\n') % format)
2477 ui.write(('flags : %s\n') % ', '.join(flags))
2477 ui.write(('flags : %s\n') % ', '.join(flags))
2478
2478
2479 ui.write('\n')
2479 ui.write('\n')
2480 fmt = pcfmtstr(totalsize)
2480 fmt = pcfmtstr(totalsize)
2481 fmt2 = dfmtstr(totalsize)
2481 fmt2 = dfmtstr(totalsize)
2482 ui.write(('revisions : ') + fmt2 % numrevs)
2482 ui.write(('revisions : ') + fmt2 % numrevs)
2483 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2483 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2484 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2484 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2485 ui.write(('revisions : ') + fmt2 % numrevs)
2485 ui.write(('revisions : ') + fmt2 % numrevs)
2486 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2486 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2487 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2487 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2488 ui.write(('revision size : ') + fmt2 % totalsize)
2488 ui.write(('revision size : ') + fmt2 % totalsize)
2489 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2489 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2490 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2490 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2491
2491
2492 ui.write('\n')
2492 ui.write('\n')
2493 fmt = dfmtstr(max(avgchainlen, compratio))
2493 fmt = dfmtstr(max(avgchainlen, compratio))
2494 ui.write(('avg chain length : ') + fmt % avgchainlen)
2494 ui.write(('avg chain length : ') + fmt % avgchainlen)
2495 ui.write(('compression ratio : ') + fmt % compratio)
2495 ui.write(('compression ratio : ') + fmt % compratio)
2496
2496
2497 if format > 0:
2497 if format > 0:
2498 ui.write('\n')
2498 ui.write('\n')
2499 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2499 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2500 % tuple(datasize))
2500 % tuple(datasize))
2501 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2501 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2502 % tuple(fullsize))
2502 % tuple(fullsize))
2503 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2503 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2504 % tuple(deltasize))
2504 % tuple(deltasize))
2505
2505
2506 if numdeltas > 0:
2506 if numdeltas > 0:
2507 ui.write('\n')
2507 ui.write('\n')
2508 fmt = pcfmtstr(numdeltas)
2508 fmt = pcfmtstr(numdeltas)
2509 fmt2 = pcfmtstr(numdeltas, 4)
2509 fmt2 = pcfmtstr(numdeltas, 4)
2510 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2510 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2511 if numprev > 0:
2511 if numprev > 0:
2512 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2512 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2513 numprev))
2513 numprev))
2514 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2514 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2515 numprev))
2515 numprev))
2516 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2516 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2517 numprev))
2517 numprev))
2518 if gdelta:
2518 if gdelta:
2519 ui.write(('deltas against p1 : ')
2519 ui.write(('deltas against p1 : ')
2520 + fmt % pcfmt(nump1, numdeltas))
2520 + fmt % pcfmt(nump1, numdeltas))
2521 ui.write(('deltas against p2 : ')
2521 ui.write(('deltas against p2 : ')
2522 + fmt % pcfmt(nump2, numdeltas))
2522 + fmt % pcfmt(nump2, numdeltas))
2523 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2523 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2524 numdeltas))
2524 numdeltas))
2525
2525
2526 @command('debugrevspec', [], ('REVSPEC'))
2526 @command('debugrevspec', [], ('REVSPEC'))
2527 def debugrevspec(ui, repo, expr):
2527 def debugrevspec(ui, repo, expr):
2528 """parse and apply a revision specification
2528 """parse and apply a revision specification
2529
2529
2530 Use --verbose to print the parsed tree before and after aliases
2530 Use --verbose to print the parsed tree before and after aliases
2531 expansion.
2531 expansion.
2532 """
2532 """
2533 if ui.verbose:
2533 if ui.verbose:
2534 tree = revset.parse(expr)[0]
2534 tree = revset.parse(expr)[0]
2535 ui.note(revset.prettyformat(tree), "\n")
2535 ui.note(revset.prettyformat(tree), "\n")
2536 newtree = revset.findaliases(ui, tree)
2536 newtree = revset.findaliases(ui, tree)
2537 if newtree != tree:
2537 if newtree != tree:
2538 ui.note(revset.prettyformat(newtree), "\n")
2538 ui.note(revset.prettyformat(newtree), "\n")
2539 func = revset.match(ui, expr)
2539 func = revset.match(ui, expr)
2540 for c in func(repo, range(len(repo))):
2540 for c in func(repo, range(len(repo))):
2541 ui.write("%s\n" % c)
2541 ui.write("%s\n" % c)
2542
2542
2543 @command('debugsetparents', [], _('REV1 [REV2]'))
2543 @command('debugsetparents', [], _('REV1 [REV2]'))
2544 def debugsetparents(ui, repo, rev1, rev2=None):
2544 def debugsetparents(ui, repo, rev1, rev2=None):
2545 """manually set the parents of the current working directory
2545 """manually set the parents of the current working directory
2546
2546
2547 This is useful for writing repository conversion tools, but should
2547 This is useful for writing repository conversion tools, but should
2548 be used with care.
2548 be used with care.
2549
2549
2550 Returns 0 on success.
2550 Returns 0 on success.
2551 """
2551 """
2552
2552
2553 r1 = scmutil.revsingle(repo, rev1).node()
2553 r1 = scmutil.revsingle(repo, rev1).node()
2554 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2554 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2555
2555
2556 wlock = repo.wlock()
2556 wlock = repo.wlock()
2557 try:
2557 try:
2558 repo.setparents(r1, r2)
2558 repo.setparents(r1, r2)
2559 finally:
2559 finally:
2560 wlock.release()
2560 wlock.release()
2561
2561
2562 @command('debugdirstate|debugstate',
2562 @command('debugdirstate|debugstate',
2563 [('', 'nodates', None, _('do not display the saved mtime')),
2563 [('', 'nodates', None, _('do not display the saved mtime')),
2564 ('', 'datesort', None, _('sort by saved mtime'))],
2564 ('', 'datesort', None, _('sort by saved mtime'))],
2565 _('[OPTION]...'))
2565 _('[OPTION]...'))
2566 def debugstate(ui, repo, nodates=None, datesort=None):
2566 def debugstate(ui, repo, nodates=None, datesort=None):
2567 """show the contents of the current dirstate"""
2567 """show the contents of the current dirstate"""
2568 timestr = ""
2568 timestr = ""
2569 showdate = not nodates
2569 showdate = not nodates
2570 if datesort:
2570 if datesort:
2571 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2571 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2572 else:
2572 else:
2573 keyfunc = None # sort by filename
2573 keyfunc = None # sort by filename
2574 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2574 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2575 if showdate:
2575 if showdate:
2576 if ent[3] == -1:
2576 if ent[3] == -1:
2577 # Pad or slice to locale representation
2577 # Pad or slice to locale representation
2578 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2578 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2579 time.localtime(0)))
2579 time.localtime(0)))
2580 timestr = 'unset'
2580 timestr = 'unset'
2581 timestr = (timestr[:locale_len] +
2581 timestr = (timestr[:locale_len] +
2582 ' ' * (locale_len - len(timestr)))
2582 ' ' * (locale_len - len(timestr)))
2583 else:
2583 else:
2584 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2584 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2585 time.localtime(ent[3]))
2585 time.localtime(ent[3]))
2586 if ent[1] & 020000:
2586 if ent[1] & 020000:
2587 mode = 'lnk'
2587 mode = 'lnk'
2588 else:
2588 else:
2589 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2589 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2590 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2590 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2591 for f in repo.dirstate.copies():
2591 for f in repo.dirstate.copies():
2592 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2592 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2593
2593
2594 @command('debugsub',
2594 @command('debugsub',
2595 [('r', 'rev', '',
2595 [('r', 'rev', '',
2596 _('revision to check'), _('REV'))],
2596 _('revision to check'), _('REV'))],
2597 _('[-r REV] [REV]'))
2597 _('[-r REV] [REV]'))
2598 def debugsub(ui, repo, rev=None):
2598 def debugsub(ui, repo, rev=None):
2599 ctx = scmutil.revsingle(repo, rev, None)
2599 ctx = scmutil.revsingle(repo, rev, None)
2600 for k, v in sorted(ctx.substate.items()):
2600 for k, v in sorted(ctx.substate.items()):
2601 ui.write(('path %s\n') % k)
2601 ui.write(('path %s\n') % k)
2602 ui.write((' source %s\n') % v[0])
2602 ui.write((' source %s\n') % v[0])
2603 ui.write((' revision %s\n') % v[1])
2603 ui.write((' revision %s\n') % v[1])
2604
2604
2605 @command('debugsuccessorssets',
2605 @command('debugsuccessorssets',
2606 [],
2606 [],
2607 _('[REV]'))
2607 _('[REV]'))
2608 def debugsuccessorssets(ui, repo, *revs):
2608 def debugsuccessorssets(ui, repo, *revs):
2609 """show set of successors for revision
2609 """show set of successors for revision
2610
2610
2611 A successors set of changeset A is a consistent group of revisions that
2611 A successors set of changeset A is a consistent group of revisions that
2612 succeed A. It contains non-obsolete changesets only.
2612 succeed A. It contains non-obsolete changesets only.
2613
2613
2614 In most cases a changeset A has a single successors set containing a single
2614 In most cases a changeset A has a single successors set containing a single
2615 successor (changeset A replaced by A').
2615 successor (changeset A replaced by A').
2616
2616
2617 A changeset that is made obsolete with no successors are called "pruned".
2617 A changeset that is made obsolete with no successors are called "pruned".
2618 Such changesets have no successors sets at all.
2618 Such changesets have no successors sets at all.
2619
2619
2620 A changeset that has been "split" will have a successors set containing
2620 A changeset that has been "split" will have a successors set containing
2621 more than one successor.
2621 more than one successor.
2622
2622
2623 A changeset that has been rewritten in multiple different ways is called
2623 A changeset that has been rewritten in multiple different ways is called
2624 "divergent". Such changesets have multiple successor sets (each of which
2624 "divergent". Such changesets have multiple successor sets (each of which
2625 may also be split, i.e. have multiple successors).
2625 may also be split, i.e. have multiple successors).
2626
2626
2627 Results are displayed as follows::
2627 Results are displayed as follows::
2628
2628
2629 <rev1>
2629 <rev1>
2630 <successors-1A>
2630 <successors-1A>
2631 <rev2>
2631 <rev2>
2632 <successors-2A>
2632 <successors-2A>
2633 <successors-2B1> <successors-2B2> <successors-2B3>
2633 <successors-2B1> <successors-2B2> <successors-2B3>
2634
2634
2635 Here rev2 has two possible (i.e. divergent) successors sets. The first
2635 Here rev2 has two possible (i.e. divergent) successors sets. The first
2636 holds one element, whereas the second holds three (i.e. the changeset has
2636 holds one element, whereas the second holds three (i.e. the changeset has
2637 been split).
2637 been split).
2638 """
2638 """
2639 # passed to successorssets caching computation from one call to another
2639 # passed to successorssets caching computation from one call to another
2640 cache = {}
2640 cache = {}
2641 ctx2str = str
2641 ctx2str = str
2642 node2str = short
2642 node2str = short
2643 if ui.debug():
2643 if ui.debug():
2644 def ctx2str(ctx):
2644 def ctx2str(ctx):
2645 return ctx.hex()
2645 return ctx.hex()
2646 node2str = hex
2646 node2str = hex
2647 for rev in scmutil.revrange(repo, revs):
2647 for rev in scmutil.revrange(repo, revs):
2648 ctx = repo[rev]
2648 ctx = repo[rev]
2649 ui.write('%s\n'% ctx2str(ctx))
2649 ui.write('%s\n'% ctx2str(ctx))
2650 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2650 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2651 if succsset:
2651 if succsset:
2652 ui.write(' ')
2652 ui.write(' ')
2653 ui.write(node2str(succsset[0]))
2653 ui.write(node2str(succsset[0]))
2654 for node in succsset[1:]:
2654 for node in succsset[1:]:
2655 ui.write(' ')
2655 ui.write(' ')
2656 ui.write(node2str(node))
2656 ui.write(node2str(node))
2657 ui.write('\n')
2657 ui.write('\n')
2658
2658
2659 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2659 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2660 def debugwalk(ui, repo, *pats, **opts):
2660 def debugwalk(ui, repo, *pats, **opts):
2661 """show how files match on given patterns"""
2661 """show how files match on given patterns"""
2662 m = scmutil.match(repo[None], pats, opts)
2662 m = scmutil.match(repo[None], pats, opts)
2663 items = list(repo.walk(m))
2663 items = list(repo.walk(m))
2664 if not items:
2664 if not items:
2665 return
2665 return
2666 f = lambda fn: fn
2666 f = lambda fn: fn
2667 if ui.configbool('ui', 'slash') and os.sep != '/':
2667 if ui.configbool('ui', 'slash') and os.sep != '/':
2668 f = lambda fn: util.normpath(fn)
2668 f = lambda fn: util.normpath(fn)
2669 fmt = 'f %%-%ds %%-%ds %%s' % (
2669 fmt = 'f %%-%ds %%-%ds %%s' % (
2670 max([len(abs) for abs in items]),
2670 max([len(abs) for abs in items]),
2671 max([len(m.rel(abs)) for abs in items]))
2671 max([len(m.rel(abs)) for abs in items]))
2672 for abs in items:
2672 for abs in items:
2673 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2673 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2674 ui.write("%s\n" % line.rstrip())
2674 ui.write("%s\n" % line.rstrip())
2675
2675
2676 @command('debugwireargs',
2676 @command('debugwireargs',
2677 [('', 'three', '', 'three'),
2677 [('', 'three', '', 'three'),
2678 ('', 'four', '', 'four'),
2678 ('', 'four', '', 'four'),
2679 ('', 'five', '', 'five'),
2679 ('', 'five', '', 'five'),
2680 ] + remoteopts,
2680 ] + remoteopts,
2681 _('REPO [OPTIONS]... [ONE [TWO]]'))
2681 _('REPO [OPTIONS]... [ONE [TWO]]'))
2682 def debugwireargs(ui, repopath, *vals, **opts):
2682 def debugwireargs(ui, repopath, *vals, **opts):
2683 repo = hg.peer(ui, opts, repopath)
2683 repo = hg.peer(ui, opts, repopath)
2684 for opt in remoteopts:
2684 for opt in remoteopts:
2685 del opts[opt[1]]
2685 del opts[opt[1]]
2686 args = {}
2686 args = {}
2687 for k, v in opts.iteritems():
2687 for k, v in opts.iteritems():
2688 if v:
2688 if v:
2689 args[k] = v
2689 args[k] = v
2690 # run twice to check that we don't mess up the stream for the next command
2690 # run twice to check that we don't mess up the stream for the next command
2691 res1 = repo.debugwireargs(*vals, **args)
2691 res1 = repo.debugwireargs(*vals, **args)
2692 res2 = repo.debugwireargs(*vals, **args)
2692 res2 = repo.debugwireargs(*vals, **args)
2693 ui.write("%s\n" % res1)
2693 ui.write("%s\n" % res1)
2694 if res1 != res2:
2694 if res1 != res2:
2695 ui.warn("%s\n" % res2)
2695 ui.warn("%s\n" % res2)
2696
2696
2697 @command('^diff',
2697 @command('^diff',
2698 [('r', 'rev', [], _('revision'), _('REV')),
2698 [('r', 'rev', [], _('revision'), _('REV')),
2699 ('c', 'change', '', _('change made by revision'), _('REV'))
2699 ('c', 'change', '', _('change made by revision'), _('REV'))
2700 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2700 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2701 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2701 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2702 def diff(ui, repo, *pats, **opts):
2702 def diff(ui, repo, *pats, **opts):
2703 """diff repository (or selected files)
2703 """diff repository (or selected files)
2704
2704
2705 Show differences between revisions for the specified files.
2705 Show differences between revisions for the specified files.
2706
2706
2707 Differences between files are shown using the unified diff format.
2707 Differences between files are shown using the unified diff format.
2708
2708
2709 .. note::
2709 .. note::
2710 diff may generate unexpected results for merges, as it will
2710 diff may generate unexpected results for merges, as it will
2711 default to comparing against the working directory's first
2711 default to comparing against the working directory's first
2712 parent changeset if no revisions are specified.
2712 parent changeset if no revisions are specified.
2713
2713
2714 When two revision arguments are given, then changes are shown
2714 When two revision arguments are given, then changes are shown
2715 between those revisions. If only one revision is specified then
2715 between those revisions. If only one revision is specified then
2716 that revision is compared to the working directory, and, when no
2716 that revision is compared to the working directory, and, when no
2717 revisions are specified, the working directory files are compared
2717 revisions are specified, the working directory files are compared
2718 to its parent.
2718 to its parent.
2719
2719
2720 Alternatively you can specify -c/--change with a revision to see
2720 Alternatively you can specify -c/--change with a revision to see
2721 the changes in that changeset relative to its first parent.
2721 the changes in that changeset relative to its first parent.
2722
2722
2723 Without the -a/--text option, diff will avoid generating diffs of
2723 Without the -a/--text option, diff will avoid generating diffs of
2724 files it detects as binary. With -a, diff will generate a diff
2724 files it detects as binary. With -a, diff will generate a diff
2725 anyway, probably with undesirable results.
2725 anyway, probably with undesirable results.
2726
2726
2727 Use the -g/--git option to generate diffs in the git extended diff
2727 Use the -g/--git option to generate diffs in the git extended diff
2728 format. For more information, read :hg:`help diffs`.
2728 format. For more information, read :hg:`help diffs`.
2729
2729
2730 .. container:: verbose
2730 .. container:: verbose
2731
2731
2732 Examples:
2732 Examples:
2733
2733
2734 - compare a file in the current working directory to its parent::
2734 - compare a file in the current working directory to its parent::
2735
2735
2736 hg diff foo.c
2736 hg diff foo.c
2737
2737
2738 - compare two historical versions of a directory, with rename info::
2738 - compare two historical versions of a directory, with rename info::
2739
2739
2740 hg diff --git -r 1.0:1.2 lib/
2740 hg diff --git -r 1.0:1.2 lib/
2741
2741
2742 - get change stats relative to the last change on some date::
2742 - get change stats relative to the last change on some date::
2743
2743
2744 hg diff --stat -r "date('may 2')"
2744 hg diff --stat -r "date('may 2')"
2745
2745
2746 - diff all newly-added files that contain a keyword::
2746 - diff all newly-added files that contain a keyword::
2747
2747
2748 hg diff "set:added() and grep(GNU)"
2748 hg diff "set:added() and grep(GNU)"
2749
2749
2750 - compare a revision and its parents::
2750 - compare a revision and its parents::
2751
2751
2752 hg diff -c 9353 # compare against first parent
2752 hg diff -c 9353 # compare against first parent
2753 hg diff -r 9353^:9353 # same using revset syntax
2753 hg diff -r 9353^:9353 # same using revset syntax
2754 hg diff -r 9353^2:9353 # compare against the second parent
2754 hg diff -r 9353^2:9353 # compare against the second parent
2755
2755
2756 Returns 0 on success.
2756 Returns 0 on success.
2757 """
2757 """
2758
2758
2759 revs = opts.get('rev')
2759 revs = opts.get('rev')
2760 change = opts.get('change')
2760 change = opts.get('change')
2761 stat = opts.get('stat')
2761 stat = opts.get('stat')
2762 reverse = opts.get('reverse')
2762 reverse = opts.get('reverse')
2763
2763
2764 if revs and change:
2764 if revs and change:
2765 msg = _('cannot specify --rev and --change at the same time')
2765 msg = _('cannot specify --rev and --change at the same time')
2766 raise util.Abort(msg)
2766 raise util.Abort(msg)
2767 elif change:
2767 elif change:
2768 node2 = scmutil.revsingle(repo, change, None).node()
2768 node2 = scmutil.revsingle(repo, change, None).node()
2769 node1 = repo[node2].p1().node()
2769 node1 = repo[node2].p1().node()
2770 else:
2770 else:
2771 node1, node2 = scmutil.revpair(repo, revs)
2771 node1, node2 = scmutil.revpair(repo, revs)
2772
2772
2773 if reverse:
2773 if reverse:
2774 node1, node2 = node2, node1
2774 node1, node2 = node2, node1
2775
2775
2776 diffopts = patch.diffopts(ui, opts)
2776 diffopts = patch.diffopts(ui, opts)
2777 m = scmutil.match(repo[node2], pats, opts)
2777 m = scmutil.match(repo[node2], pats, opts)
2778 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2778 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2779 listsubrepos=opts.get('subrepos'))
2779 listsubrepos=opts.get('subrepos'))
2780
2780
2781 @command('^export',
2781 @command('^export',
2782 [('o', 'output', '',
2782 [('o', 'output', '',
2783 _('print output to file with formatted name'), _('FORMAT')),
2783 _('print output to file with formatted name'), _('FORMAT')),
2784 ('', 'switch-parent', None, _('diff against the second parent')),
2784 ('', 'switch-parent', None, _('diff against the second parent')),
2785 ('r', 'rev', [], _('revisions to export'), _('REV')),
2785 ('r', 'rev', [], _('revisions to export'), _('REV')),
2786 ] + diffopts,
2786 ] + diffopts,
2787 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2787 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2788 def export(ui, repo, *changesets, **opts):
2788 def export(ui, repo, *changesets, **opts):
2789 """dump the header and diffs for one or more changesets
2789 """dump the header and diffs for one or more changesets
2790
2790
2791 Print the changeset header and diffs for one or more revisions.
2791 Print the changeset header and diffs for one or more revisions.
2792 If no revision is given, the parent of the working directory is used.
2792 If no revision is given, the parent of the working directory is used.
2793
2793
2794 The information shown in the changeset header is: author, date,
2794 The information shown in the changeset header is: author, date,
2795 branch name (if non-default), changeset hash, parent(s) and commit
2795 branch name (if non-default), changeset hash, parent(s) and commit
2796 comment.
2796 comment.
2797
2797
2798 .. note::
2798 .. note::
2799 export may generate unexpected diff output for merge
2799 export may generate unexpected diff output for merge
2800 changesets, as it will compare the merge changeset against its
2800 changesets, as it will compare the merge changeset against its
2801 first parent only.
2801 first parent only.
2802
2802
2803 Output may be to a file, in which case the name of the file is
2803 Output may be to a file, in which case the name of the file is
2804 given using a format string. The formatting rules are as follows:
2804 given using a format string. The formatting rules are as follows:
2805
2805
2806 :``%%``: literal "%" character
2806 :``%%``: literal "%" character
2807 :``%H``: changeset hash (40 hexadecimal digits)
2807 :``%H``: changeset hash (40 hexadecimal digits)
2808 :``%N``: number of patches being generated
2808 :``%N``: number of patches being generated
2809 :``%R``: changeset revision number
2809 :``%R``: changeset revision number
2810 :``%b``: basename of the exporting repository
2810 :``%b``: basename of the exporting repository
2811 :``%h``: short-form changeset hash (12 hexadecimal digits)
2811 :``%h``: short-form changeset hash (12 hexadecimal digits)
2812 :``%m``: first line of the commit message (only alphanumeric characters)
2812 :``%m``: first line of the commit message (only alphanumeric characters)
2813 :``%n``: zero-padded sequence number, starting at 1
2813 :``%n``: zero-padded sequence number, starting at 1
2814 :``%r``: zero-padded changeset revision number
2814 :``%r``: zero-padded changeset revision number
2815
2815
2816 Without the -a/--text option, export will avoid generating diffs
2816 Without the -a/--text option, export will avoid generating diffs
2817 of files it detects as binary. With -a, export will generate a
2817 of files it detects as binary. With -a, export will generate a
2818 diff anyway, probably with undesirable results.
2818 diff anyway, probably with undesirable results.
2819
2819
2820 Use the -g/--git option to generate diffs in the git extended diff
2820 Use the -g/--git option to generate diffs in the git extended diff
2821 format. See :hg:`help diffs` for more information.
2821 format. See :hg:`help diffs` for more information.
2822
2822
2823 With the --switch-parent option, the diff will be against the
2823 With the --switch-parent option, the diff will be against the
2824 second parent. It can be useful to review a merge.
2824 second parent. It can be useful to review a merge.
2825
2825
2826 .. container:: verbose
2826 .. container:: verbose
2827
2827
2828 Examples:
2828 Examples:
2829
2829
2830 - use export and import to transplant a bugfix to the current
2830 - use export and import to transplant a bugfix to the current
2831 branch::
2831 branch::
2832
2832
2833 hg export -r 9353 | hg import -
2833 hg export -r 9353 | hg import -
2834
2834
2835 - export all the changesets between two revisions to a file with
2835 - export all the changesets between two revisions to a file with
2836 rename information::
2836 rename information::
2837
2837
2838 hg export --git -r 123:150 > changes.txt
2838 hg export --git -r 123:150 > changes.txt
2839
2839
2840 - split outgoing changes into a series of patches with
2840 - split outgoing changes into a series of patches with
2841 descriptive names::
2841 descriptive names::
2842
2842
2843 hg export -r "outgoing()" -o "%n-%m.patch"
2843 hg export -r "outgoing()" -o "%n-%m.patch"
2844
2844
2845 Returns 0 on success.
2845 Returns 0 on success.
2846 """
2846 """
2847 changesets += tuple(opts.get('rev', []))
2847 changesets += tuple(opts.get('rev', []))
2848 if not changesets:
2848 if not changesets:
2849 changesets = ['.']
2849 changesets = ['.']
2850 revs = scmutil.revrange(repo, changesets)
2850 revs = scmutil.revrange(repo, changesets)
2851 if not revs:
2851 if not revs:
2852 raise util.Abort(_("export requires at least one changeset"))
2852 raise util.Abort(_("export requires at least one changeset"))
2853 if len(revs) > 1:
2853 if len(revs) > 1:
2854 ui.note(_('exporting patches:\n'))
2854 ui.note(_('exporting patches:\n'))
2855 else:
2855 else:
2856 ui.note(_('exporting patch:\n'))
2856 ui.note(_('exporting patch:\n'))
2857 cmdutil.export(repo, revs, template=opts.get('output'),
2857 cmdutil.export(repo, revs, template=opts.get('output'),
2858 switch_parent=opts.get('switch_parent'),
2858 switch_parent=opts.get('switch_parent'),
2859 opts=patch.diffopts(ui, opts))
2859 opts=patch.diffopts(ui, opts))
2860
2860
2861 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2861 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2862 def forget(ui, repo, *pats, **opts):
2862 def forget(ui, repo, *pats, **opts):
2863 """forget the specified files on the next commit
2863 """forget the specified files on the next commit
2864
2864
2865 Mark the specified files so they will no longer be tracked
2865 Mark the specified files so they will no longer be tracked
2866 after the next commit.
2866 after the next commit.
2867
2867
2868 This only removes files from the current branch, not from the
2868 This only removes files from the current branch, not from the
2869 entire project history, and it does not delete them from the
2869 entire project history, and it does not delete them from the
2870 working directory.
2870 working directory.
2871
2871
2872 To undo a forget before the next commit, see :hg:`add`.
2872 To undo a forget before the next commit, see :hg:`add`.
2873
2873
2874 .. container:: verbose
2874 .. container:: verbose
2875
2875
2876 Examples:
2876 Examples:
2877
2877
2878 - forget newly-added binary files::
2878 - forget newly-added binary files::
2879
2879
2880 hg forget "set:added() and binary()"
2880 hg forget "set:added() and binary()"
2881
2881
2882 - forget files that would be excluded by .hgignore::
2882 - forget files that would be excluded by .hgignore::
2883
2883
2884 hg forget "set:hgignore()"
2884 hg forget "set:hgignore()"
2885
2885
2886 Returns 0 on success.
2886 Returns 0 on success.
2887 """
2887 """
2888
2888
2889 if not pats:
2889 if not pats:
2890 raise util.Abort(_('no files specified'))
2890 raise util.Abort(_('no files specified'))
2891
2891
2892 m = scmutil.match(repo[None], pats, opts)
2892 m = scmutil.match(repo[None], pats, opts)
2893 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2893 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2894 return rejected and 1 or 0
2894 return rejected and 1 or 0
2895
2895
2896 @command(
2896 @command(
2897 'graft',
2897 'graft',
2898 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2898 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2899 ('c', 'continue', False, _('resume interrupted graft')),
2899 ('c', 'continue', False, _('resume interrupted graft')),
2900 ('e', 'edit', False, _('invoke editor on commit messages')),
2900 ('e', 'edit', False, _('invoke editor on commit messages')),
2901 ('', 'log', None, _('append graft info to log message')),
2901 ('', 'log', None, _('append graft info to log message')),
2902 ('D', 'currentdate', False,
2902 ('D', 'currentdate', False,
2903 _('record the current date as commit date')),
2903 _('record the current date as commit date')),
2904 ('U', 'currentuser', False,
2904 ('U', 'currentuser', False,
2905 _('record the current user as committer'), _('DATE'))]
2905 _('record the current user as committer'), _('DATE'))]
2906 + commitopts2 + mergetoolopts + dryrunopts,
2906 + commitopts2 + mergetoolopts + dryrunopts,
2907 _('[OPTION]... [-r] REV...'))
2907 _('[OPTION]... [-r] REV...'))
2908 def graft(ui, repo, *revs, **opts):
2908 def graft(ui, repo, *revs, **opts):
2909 '''copy changes from other branches onto the current branch
2909 '''copy changes from other branches onto the current branch
2910
2910
2911 This command uses Mercurial's merge logic to copy individual
2911 This command uses Mercurial's merge logic to copy individual
2912 changes from other branches without merging branches in the
2912 changes from other branches without merging branches in the
2913 history graph. This is sometimes known as 'backporting' or
2913 history graph. This is sometimes known as 'backporting' or
2914 'cherry-picking'. By default, graft will copy user, date, and
2914 'cherry-picking'. By default, graft will copy user, date, and
2915 description from the source changesets.
2915 description from the source changesets.
2916
2916
2917 Changesets that are ancestors of the current revision, that have
2917 Changesets that are ancestors of the current revision, that have
2918 already been grafted, or that are merges will be skipped.
2918 already been grafted, or that are merges will be skipped.
2919
2919
2920 If --log is specified, log messages will have a comment appended
2920 If --log is specified, log messages will have a comment appended
2921 of the form::
2921 of the form::
2922
2922
2923 (grafted from CHANGESETHASH)
2923 (grafted from CHANGESETHASH)
2924
2924
2925 If a graft merge results in conflicts, the graft process is
2925 If a graft merge results in conflicts, the graft process is
2926 interrupted so that the current merge can be manually resolved.
2926 interrupted so that the current merge can be manually resolved.
2927 Once all conflicts are addressed, the graft process can be
2927 Once all conflicts are addressed, the graft process can be
2928 continued with the -c/--continue option.
2928 continued with the -c/--continue option.
2929
2929
2930 .. note::
2930 .. note::
2931 The -c/--continue option does not reapply earlier options.
2931 The -c/--continue option does not reapply earlier options.
2932
2932
2933 .. container:: verbose
2933 .. container:: verbose
2934
2934
2935 Examples:
2935 Examples:
2936
2936
2937 - copy a single change to the stable branch and edit its description::
2937 - copy a single change to the stable branch and edit its description::
2938
2938
2939 hg update stable
2939 hg update stable
2940 hg graft --edit 9393
2940 hg graft --edit 9393
2941
2941
2942 - graft a range of changesets with one exception, updating dates::
2942 - graft a range of changesets with one exception, updating dates::
2943
2943
2944 hg graft -D "2085::2093 and not 2091"
2944 hg graft -D "2085::2093 and not 2091"
2945
2945
2946 - continue a graft after resolving conflicts::
2946 - continue a graft after resolving conflicts::
2947
2947
2948 hg graft -c
2948 hg graft -c
2949
2949
2950 - show the source of a grafted changeset::
2950 - show the source of a grafted changeset::
2951
2951
2952 hg log --debug -r .
2952 hg log --debug -r .
2953
2953
2954 Returns 0 on successful completion.
2954 Returns 0 on successful completion.
2955 '''
2955 '''
2956
2956
2957 revs = list(revs)
2957 revs = list(revs)
2958 revs.extend(opts['rev'])
2958 revs.extend(opts['rev'])
2959
2959
2960 if not opts.get('user') and opts.get('currentuser'):
2960 if not opts.get('user') and opts.get('currentuser'):
2961 opts['user'] = ui.username()
2961 opts['user'] = ui.username()
2962 if not opts.get('date') and opts.get('currentdate'):
2962 if not opts.get('date') and opts.get('currentdate'):
2963 opts['date'] = "%d %d" % util.makedate()
2963 opts['date'] = "%d %d" % util.makedate()
2964
2964
2965 editor = None
2965 editor = None
2966 if opts.get('edit'):
2966 if opts.get('edit'):
2967 editor = cmdutil.commitforceeditor
2967 editor = cmdutil.commitforceeditor
2968
2968
2969 cont = False
2969 cont = False
2970 if opts['continue']:
2970 if opts['continue']:
2971 cont = True
2971 cont = True
2972 if revs:
2972 if revs:
2973 raise util.Abort(_("can't specify --continue and revisions"))
2973 raise util.Abort(_("can't specify --continue and revisions"))
2974 # read in unfinished revisions
2974 # read in unfinished revisions
2975 try:
2975 try:
2976 nodes = repo.opener.read('graftstate').splitlines()
2976 nodes = repo.opener.read('graftstate').splitlines()
2977 revs = [repo[node].rev() for node in nodes]
2977 revs = [repo[node].rev() for node in nodes]
2978 except IOError, inst:
2978 except IOError, inst:
2979 if inst.errno != errno.ENOENT:
2979 if inst.errno != errno.ENOENT:
2980 raise
2980 raise
2981 raise util.Abort(_("no graft state found, can't continue"))
2981 raise util.Abort(_("no graft state found, can't continue"))
2982 else:
2982 else:
2983 cmdutil.checkunfinished(repo)
2983 cmdutil.checkunfinished(repo)
2984 cmdutil.bailifchanged(repo)
2984 cmdutil.bailifchanged(repo)
2985 if not revs:
2985 if not revs:
2986 raise util.Abort(_('no revisions specified'))
2986 raise util.Abort(_('no revisions specified'))
2987 revs = scmutil.revrange(repo, revs)
2987 revs = scmutil.revrange(repo, revs)
2988
2988
2989 # check for merges
2989 # check for merges
2990 for rev in repo.revs('%ld and merge()', revs):
2990 for rev in repo.revs('%ld and merge()', revs):
2991 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2991 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2992 revs.remove(rev)
2992 revs.remove(rev)
2993 if not revs:
2993 if not revs:
2994 return -1
2994 return -1
2995
2995
2996 # check for ancestors of dest branch
2996 # check for ancestors of dest branch
2997 crev = repo['.'].rev()
2997 crev = repo['.'].rev()
2998 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2998 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2999 # don't mutate while iterating, create a copy
2999 # don't mutate while iterating, create a copy
3000 for rev in list(revs):
3000 for rev in list(revs):
3001 if rev in ancestors:
3001 if rev in ancestors:
3002 ui.warn(_('skipping ancestor revision %s\n') % rev)
3002 ui.warn(_('skipping ancestor revision %s\n') % rev)
3003 revs.remove(rev)
3003 revs.remove(rev)
3004 if not revs:
3004 if not revs:
3005 return -1
3005 return -1
3006
3006
3007 # analyze revs for earlier grafts
3007 # analyze revs for earlier grafts
3008 ids = {}
3008 ids = {}
3009 for ctx in repo.set("%ld", revs):
3009 for ctx in repo.set("%ld", revs):
3010 ids[ctx.hex()] = ctx.rev()
3010 ids[ctx.hex()] = ctx.rev()
3011 n = ctx.extra().get('source')
3011 n = ctx.extra().get('source')
3012 if n:
3012 if n:
3013 ids[n] = ctx.rev()
3013 ids[n] = ctx.rev()
3014
3014
3015 # check ancestors for earlier grafts
3015 # check ancestors for earlier grafts
3016 ui.debug('scanning for duplicate grafts\n')
3016 ui.debug('scanning for duplicate grafts\n')
3017
3017
3018 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3018 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3019 ctx = repo[rev]
3019 ctx = repo[rev]
3020 n = ctx.extra().get('source')
3020 n = ctx.extra().get('source')
3021 if n in ids:
3021 if n in ids:
3022 r = repo[n].rev()
3022 r = repo[n].rev()
3023 if r in revs:
3023 if r in revs:
3024 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3024 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3025 % (r, rev))
3025 % (r, rev))
3026 revs.remove(r)
3026 revs.remove(r)
3027 elif ids[n] in revs:
3027 elif ids[n] in revs:
3028 ui.warn(_('skipping already grafted revision %s '
3028 ui.warn(_('skipping already grafted revision %s '
3029 '(%s also has origin %d)\n') % (ids[n], rev, r))
3029 '(%s also has origin %d)\n') % (ids[n], rev, r))
3030 revs.remove(ids[n])
3030 revs.remove(ids[n])
3031 elif ctx.hex() in ids:
3031 elif ctx.hex() in ids:
3032 r = ids[ctx.hex()]
3032 r = ids[ctx.hex()]
3033 ui.warn(_('skipping already grafted revision %s '
3033 ui.warn(_('skipping already grafted revision %s '
3034 '(was grafted from %d)\n') % (r, rev))
3034 '(was grafted from %d)\n') % (r, rev))
3035 revs.remove(r)
3035 revs.remove(r)
3036 if not revs:
3036 if not revs:
3037 return -1
3037 return -1
3038
3038
3039 wlock = repo.wlock()
3039 wlock = repo.wlock()
3040 try:
3040 try:
3041 current = repo['.']
3041 current = repo['.']
3042 for pos, ctx in enumerate(repo.set("%ld", revs)):
3042 for pos, ctx in enumerate(repo.set("%ld", revs)):
3043
3043
3044 ui.status(_('grafting revision %s\n') % ctx.rev())
3044 ui.status(_('grafting revision %s\n') % ctx.rev())
3045 if opts.get('dry_run'):
3045 if opts.get('dry_run'):
3046 continue
3046 continue
3047
3047
3048 source = ctx.extra().get('source')
3048 source = ctx.extra().get('source')
3049 if not source:
3049 if not source:
3050 source = ctx.hex()
3050 source = ctx.hex()
3051 extra = {'source': source}
3051 extra = {'source': source}
3052 user = ctx.user()
3052 user = ctx.user()
3053 if opts.get('user'):
3053 if opts.get('user'):
3054 user = opts['user']
3054 user = opts['user']
3055 date = ctx.date()
3055 date = ctx.date()
3056 if opts.get('date'):
3056 if opts.get('date'):
3057 date = opts['date']
3057 date = opts['date']
3058 message = ctx.description()
3058 message = ctx.description()
3059 if opts.get('log'):
3059 if opts.get('log'):
3060 message += '\n(grafted from %s)' % ctx.hex()
3060 message += '\n(grafted from %s)' % ctx.hex()
3061
3061
3062 # we don't merge the first commit when continuing
3062 # we don't merge the first commit when continuing
3063 if not cont:
3063 if not cont:
3064 # perform the graft merge with p1(rev) as 'ancestor'
3064 # perform the graft merge with p1(rev) as 'ancestor'
3065 try:
3065 try:
3066 # ui.forcemerge is an internal variable, do not document
3066 # ui.forcemerge is an internal variable, do not document
3067 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3067 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3068 stats = mergemod.update(repo, ctx.node(), True, True, False,
3068 stats = mergemod.update(repo, ctx.node(), True, True, False,
3069 ctx.p1().node())
3069 ctx.p1().node())
3070 finally:
3070 finally:
3071 repo.ui.setconfig('ui', 'forcemerge', '')
3071 repo.ui.setconfig('ui', 'forcemerge', '')
3072 # report any conflicts
3072 # report any conflicts
3073 if stats and stats[3] > 0:
3073 if stats and stats[3] > 0:
3074 # write out state for --continue
3074 # write out state for --continue
3075 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3075 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3076 repo.opener.write('graftstate', ''.join(nodelines))
3076 repo.opener.write('graftstate', ''.join(nodelines))
3077 raise util.Abort(
3077 raise util.Abort(
3078 _("unresolved conflicts, can't continue"),
3078 _("unresolved conflicts, can't continue"),
3079 hint=_('use hg resolve and hg graft --continue'))
3079 hint=_('use hg resolve and hg graft --continue'))
3080 else:
3080 else:
3081 cont = False
3081 cont = False
3082
3082
3083 # drop the second merge parent
3083 # drop the second merge parent
3084 repo.setparents(current.node(), nullid)
3084 repo.setparents(current.node(), nullid)
3085 repo.dirstate.write()
3085 repo.dirstate.write()
3086 # fix up dirstate for copies and renames
3086 # fix up dirstate for copies and renames
3087 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3087 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3088
3088
3089 # commit
3089 # commit
3090 node = repo.commit(text=message, user=user,
3090 node = repo.commit(text=message, user=user,
3091 date=date, extra=extra, editor=editor)
3091 date=date, extra=extra, editor=editor)
3092 if node is None:
3092 if node is None:
3093 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3093 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3094 else:
3094 else:
3095 current = repo[node]
3095 current = repo[node]
3096 finally:
3096 finally:
3097 wlock.release()
3097 wlock.release()
3098
3098
3099 # remove state when we complete successfully
3099 # remove state when we complete successfully
3100 if not opts.get('dry_run'):
3100 if not opts.get('dry_run'):
3101 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3101 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3102
3102
3103 return 0
3103 return 0
3104
3104
3105 @command('grep',
3105 @command('grep',
3106 [('0', 'print0', None, _('end fields with NUL')),
3106 [('0', 'print0', None, _('end fields with NUL')),
3107 ('', 'all', None, _('print all revisions that match')),
3107 ('', 'all', None, _('print all revisions that match')),
3108 ('a', 'text', None, _('treat all files as text')),
3108 ('a', 'text', None, _('treat all files as text')),
3109 ('f', 'follow', None,
3109 ('f', 'follow', None,
3110 _('follow changeset history,'
3110 _('follow changeset history,'
3111 ' or file history across copies and renames')),
3111 ' or file history across copies and renames')),
3112 ('i', 'ignore-case', None, _('ignore case when matching')),
3112 ('i', 'ignore-case', None, _('ignore case when matching')),
3113 ('l', 'files-with-matches', None,
3113 ('l', 'files-with-matches', None,
3114 _('print only filenames and revisions that match')),
3114 _('print only filenames and revisions that match')),
3115 ('n', 'line-number', None, _('print matching line numbers')),
3115 ('n', 'line-number', None, _('print matching line numbers')),
3116 ('r', 'rev', [],
3116 ('r', 'rev', [],
3117 _('only search files changed within revision range'), _('REV')),
3117 _('only search files changed within revision range'), _('REV')),
3118 ('u', 'user', None, _('list the author (long with -v)')),
3118 ('u', 'user', None, _('list the author (long with -v)')),
3119 ('d', 'date', None, _('list the date (short with -q)')),
3119 ('d', 'date', None, _('list the date (short with -q)')),
3120 ] + walkopts,
3120 ] + walkopts,
3121 _('[OPTION]... PATTERN [FILE]...'))
3121 _('[OPTION]... PATTERN [FILE]...'))
3122 def grep(ui, repo, pattern, *pats, **opts):
3122 def grep(ui, repo, pattern, *pats, **opts):
3123 """search for a pattern in specified files and revisions
3123 """search for a pattern in specified files and revisions
3124
3124
3125 Search revisions of files for a regular expression.
3125 Search revisions of files for a regular expression.
3126
3126
3127 This command behaves differently than Unix grep. It only accepts
3127 This command behaves differently than Unix grep. It only accepts
3128 Python/Perl regexps. It searches repository history, not the
3128 Python/Perl regexps. It searches repository history, not the
3129 working directory. It always prints the revision number in which a
3129 working directory. It always prints the revision number in which a
3130 match appears.
3130 match appears.
3131
3131
3132 By default, grep only prints output for the first revision of a
3132 By default, grep only prints output for the first revision of a
3133 file in which it finds a match. To get it to print every revision
3133 file in which it finds a match. To get it to print every revision
3134 that contains a change in match status ("-" for a match that
3134 that contains a change in match status ("-" for a match that
3135 becomes a non-match, or "+" for a non-match that becomes a match),
3135 becomes a non-match, or "+" for a non-match that becomes a match),
3136 use the --all flag.
3136 use the --all flag.
3137
3137
3138 Returns 0 if a match is found, 1 otherwise.
3138 Returns 0 if a match is found, 1 otherwise.
3139 """
3139 """
3140 reflags = re.M
3140 reflags = re.M
3141 if opts.get('ignore_case'):
3141 if opts.get('ignore_case'):
3142 reflags |= re.I
3142 reflags |= re.I
3143 try:
3143 try:
3144 regexp = util.compilere(pattern, reflags)
3144 regexp = util.compilere(pattern, reflags)
3145 except re.error, inst:
3145 except re.error, inst:
3146 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3146 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3147 return 1
3147 return 1
3148 sep, eol = ':', '\n'
3148 sep, eol = ':', '\n'
3149 if opts.get('print0'):
3149 if opts.get('print0'):
3150 sep = eol = '\0'
3150 sep = eol = '\0'
3151
3151
3152 getfile = util.lrucachefunc(repo.file)
3152 getfile = util.lrucachefunc(repo.file)
3153
3153
3154 def matchlines(body):
3154 def matchlines(body):
3155 begin = 0
3155 begin = 0
3156 linenum = 0
3156 linenum = 0
3157 while begin < len(body):
3157 while begin < len(body):
3158 match = regexp.search(body, begin)
3158 match = regexp.search(body, begin)
3159 if not match:
3159 if not match:
3160 break
3160 break
3161 mstart, mend = match.span()
3161 mstart, mend = match.span()
3162 linenum += body.count('\n', begin, mstart) + 1
3162 linenum += body.count('\n', begin, mstart) + 1
3163 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3163 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3164 begin = body.find('\n', mend) + 1 or len(body) + 1
3164 begin = body.find('\n', mend) + 1 or len(body) + 1
3165 lend = begin - 1
3165 lend = begin - 1
3166 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3166 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3167
3167
3168 class linestate(object):
3168 class linestate(object):
3169 def __init__(self, line, linenum, colstart, colend):
3169 def __init__(self, line, linenum, colstart, colend):
3170 self.line = line
3170 self.line = line
3171 self.linenum = linenum
3171 self.linenum = linenum
3172 self.colstart = colstart
3172 self.colstart = colstart
3173 self.colend = colend
3173 self.colend = colend
3174
3174
3175 def __hash__(self):
3175 def __hash__(self):
3176 return hash((self.linenum, self.line))
3176 return hash((self.linenum, self.line))
3177
3177
3178 def __eq__(self, other):
3178 def __eq__(self, other):
3179 return self.line == other.line
3179 return self.line == other.line
3180
3180
3181 matches = {}
3181 matches = {}
3182 copies = {}
3182 copies = {}
3183 def grepbody(fn, rev, body):
3183 def grepbody(fn, rev, body):
3184 matches[rev].setdefault(fn, [])
3184 matches[rev].setdefault(fn, [])
3185 m = matches[rev][fn]
3185 m = matches[rev][fn]
3186 for lnum, cstart, cend, line in matchlines(body):
3186 for lnum, cstart, cend, line in matchlines(body):
3187 s = linestate(line, lnum, cstart, cend)
3187 s = linestate(line, lnum, cstart, cend)
3188 m.append(s)
3188 m.append(s)
3189
3189
3190 def difflinestates(a, b):
3190 def difflinestates(a, b):
3191 sm = difflib.SequenceMatcher(None, a, b)
3191 sm = difflib.SequenceMatcher(None, a, b)
3192 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3192 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3193 if tag == 'insert':
3193 if tag == 'insert':
3194 for i in xrange(blo, bhi):
3194 for i in xrange(blo, bhi):
3195 yield ('+', b[i])
3195 yield ('+', b[i])
3196 elif tag == 'delete':
3196 elif tag == 'delete':
3197 for i in xrange(alo, ahi):
3197 for i in xrange(alo, ahi):
3198 yield ('-', a[i])
3198 yield ('-', a[i])
3199 elif tag == 'replace':
3199 elif tag == 'replace':
3200 for i in xrange(alo, ahi):
3200 for i in xrange(alo, ahi):
3201 yield ('-', a[i])
3201 yield ('-', a[i])
3202 for i in xrange(blo, bhi):
3202 for i in xrange(blo, bhi):
3203 yield ('+', b[i])
3203 yield ('+', b[i])
3204
3204
3205 def display(fn, ctx, pstates, states):
3205 def display(fn, ctx, pstates, states):
3206 rev = ctx.rev()
3206 rev = ctx.rev()
3207 datefunc = ui.quiet and util.shortdate or util.datestr
3207 datefunc = ui.quiet and util.shortdate or util.datestr
3208 found = False
3208 found = False
3209 filerevmatches = {}
3209 filerevmatches = {}
3210 def binary():
3210 def binary():
3211 flog = getfile(fn)
3211 flog = getfile(fn)
3212 return util.binary(flog.read(ctx.filenode(fn)))
3212 return util.binary(flog.read(ctx.filenode(fn)))
3213
3213
3214 if opts.get('all'):
3214 if opts.get('all'):
3215 iter = difflinestates(pstates, states)
3215 iter = difflinestates(pstates, states)
3216 else:
3216 else:
3217 iter = [('', l) for l in states]
3217 iter = [('', l) for l in states]
3218 for change, l in iter:
3218 for change, l in iter:
3219 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3219 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3220 before, match, after = None, None, None
3220 before, match, after = None, None, None
3221
3221
3222 if opts.get('line_number'):
3222 if opts.get('line_number'):
3223 cols.append((str(l.linenum), 'grep.linenumber'))
3223 cols.append((str(l.linenum), 'grep.linenumber'))
3224 if opts.get('all'):
3224 if opts.get('all'):
3225 cols.append((change, 'grep.change'))
3225 cols.append((change, 'grep.change'))
3226 if opts.get('user'):
3226 if opts.get('user'):
3227 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3227 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3228 if opts.get('date'):
3228 if opts.get('date'):
3229 cols.append((datefunc(ctx.date()), 'grep.date'))
3229 cols.append((datefunc(ctx.date()), 'grep.date'))
3230 if opts.get('files_with_matches'):
3230 if opts.get('files_with_matches'):
3231 c = (fn, rev)
3231 c = (fn, rev)
3232 if c in filerevmatches:
3232 if c in filerevmatches:
3233 continue
3233 continue
3234 filerevmatches[c] = 1
3234 filerevmatches[c] = 1
3235 else:
3235 else:
3236 before = l.line[:l.colstart]
3236 before = l.line[:l.colstart]
3237 match = l.line[l.colstart:l.colend]
3237 match = l.line[l.colstart:l.colend]
3238 after = l.line[l.colend:]
3238 after = l.line[l.colend:]
3239 for col, label in cols[:-1]:
3239 for col, label in cols[:-1]:
3240 ui.write(col, label=label)
3240 ui.write(col, label=label)
3241 ui.write(sep, label='grep.sep')
3241 ui.write(sep, label='grep.sep')
3242 ui.write(cols[-1][0], label=cols[-1][1])
3242 ui.write(cols[-1][0], label=cols[-1][1])
3243 if before is not None:
3243 if before is not None:
3244 ui.write(sep, label='grep.sep')
3244 ui.write(sep, label='grep.sep')
3245 if not opts.get('text') and binary():
3245 if not opts.get('text') and binary():
3246 ui.write(" Binary file matches")
3246 ui.write(" Binary file matches")
3247 else:
3247 else:
3248 ui.write(before)
3248 ui.write(before)
3249 ui.write(match, label='grep.match')
3249 ui.write(match, label='grep.match')
3250 ui.write(after)
3250 ui.write(after)
3251 ui.write(eol)
3251 ui.write(eol)
3252 found = True
3252 found = True
3253 return found
3253 return found
3254
3254
3255 skip = {}
3255 skip = {}
3256 revfiles = {}
3256 revfiles = {}
3257 matchfn = scmutil.match(repo[None], pats, opts)
3257 matchfn = scmutil.match(repo[None], pats, opts)
3258 found = False
3258 found = False
3259 follow = opts.get('follow')
3259 follow = opts.get('follow')
3260
3260
3261 def prep(ctx, fns):
3261 def prep(ctx, fns):
3262 rev = ctx.rev()
3262 rev = ctx.rev()
3263 pctx = ctx.p1()
3263 pctx = ctx.p1()
3264 parent = pctx.rev()
3264 parent = pctx.rev()
3265 matches.setdefault(rev, {})
3265 matches.setdefault(rev, {})
3266 matches.setdefault(parent, {})
3266 matches.setdefault(parent, {})
3267 files = revfiles.setdefault(rev, [])
3267 files = revfiles.setdefault(rev, [])
3268 for fn in fns:
3268 for fn in fns:
3269 flog = getfile(fn)
3269 flog = getfile(fn)
3270 try:
3270 try:
3271 fnode = ctx.filenode(fn)
3271 fnode = ctx.filenode(fn)
3272 except error.LookupError:
3272 except error.LookupError:
3273 continue
3273 continue
3274
3274
3275 copied = flog.renamed(fnode)
3275 copied = flog.renamed(fnode)
3276 copy = follow and copied and copied[0]
3276 copy = follow and copied and copied[0]
3277 if copy:
3277 if copy:
3278 copies.setdefault(rev, {})[fn] = copy
3278 copies.setdefault(rev, {})[fn] = copy
3279 if fn in skip:
3279 if fn in skip:
3280 if copy:
3280 if copy:
3281 skip[copy] = True
3281 skip[copy] = True
3282 continue
3282 continue
3283 files.append(fn)
3283 files.append(fn)
3284
3284
3285 if fn not in matches[rev]:
3285 if fn not in matches[rev]:
3286 grepbody(fn, rev, flog.read(fnode))
3286 grepbody(fn, rev, flog.read(fnode))
3287
3287
3288 pfn = copy or fn
3288 pfn = copy or fn
3289 if pfn not in matches[parent]:
3289 if pfn not in matches[parent]:
3290 try:
3290 try:
3291 fnode = pctx.filenode(pfn)
3291 fnode = pctx.filenode(pfn)
3292 grepbody(pfn, parent, flog.read(fnode))
3292 grepbody(pfn, parent, flog.read(fnode))
3293 except error.LookupError:
3293 except error.LookupError:
3294 pass
3294 pass
3295
3295
3296 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3296 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3297 rev = ctx.rev()
3297 rev = ctx.rev()
3298 parent = ctx.p1().rev()
3298 parent = ctx.p1().rev()
3299 for fn in sorted(revfiles.get(rev, [])):
3299 for fn in sorted(revfiles.get(rev, [])):
3300 states = matches[rev][fn]
3300 states = matches[rev][fn]
3301 copy = copies.get(rev, {}).get(fn)
3301 copy = copies.get(rev, {}).get(fn)
3302 if fn in skip:
3302 if fn in skip:
3303 if copy:
3303 if copy:
3304 skip[copy] = True
3304 skip[copy] = True
3305 continue
3305 continue
3306 pstates = matches.get(parent, {}).get(copy or fn, [])
3306 pstates = matches.get(parent, {}).get(copy or fn, [])
3307 if pstates or states:
3307 if pstates or states:
3308 r = display(fn, ctx, pstates, states)
3308 r = display(fn, ctx, pstates, states)
3309 found = found or r
3309 found = found or r
3310 if r and not opts.get('all'):
3310 if r and not opts.get('all'):
3311 skip[fn] = True
3311 skip[fn] = True
3312 if copy:
3312 if copy:
3313 skip[copy] = True
3313 skip[copy] = True
3314 del matches[rev]
3314 del matches[rev]
3315 del revfiles[rev]
3315 del revfiles[rev]
3316
3316
3317 return not found
3317 return not found
3318
3318
3319 @command('heads',
3319 @command('heads',
3320 [('r', 'rev', '',
3320 [('r', 'rev', '',
3321 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3321 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3322 ('t', 'topo', False, _('show topological heads only')),
3322 ('t', 'topo', False, _('show topological heads only')),
3323 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3323 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3324 ('c', 'closed', False, _('show normal and closed branch heads')),
3324 ('c', 'closed', False, _('show normal and closed branch heads')),
3325 ] + templateopts,
3325 ] + templateopts,
3326 _('[-ct] [-r STARTREV] [REV]...'))
3326 _('[-ct] [-r STARTREV] [REV]...'))
3327 def heads(ui, repo, *branchrevs, **opts):
3327 def heads(ui, repo, *branchrevs, **opts):
3328 """show branch heads
3328 """show branch heads
3329
3329
3330 With no arguments, show all open branch heads in the repository.
3330 With no arguments, show all open branch heads in the repository.
3331 Branch heads are changesets that have no descendants on the
3331 Branch heads are changesets that have no descendants on the
3332 same branch. They are where development generally takes place and
3332 same branch. They are where development generally takes place and
3333 are the usual targets for update and merge operations.
3333 are the usual targets for update and merge operations.
3334
3334
3335 If one or more REVs are given, only open branch heads on the
3335 If one or more REVs are given, only open branch heads on the
3336 branches associated with the specified changesets are shown. This
3336 branches associated with the specified changesets are shown. This
3337 means that you can use :hg:`heads .` to see the heads on the
3337 means that you can use :hg:`heads .` to see the heads on the
3338 currently checked-out branch.
3338 currently checked-out branch.
3339
3339
3340 If -c/--closed is specified, also show branch heads marked closed
3340 If -c/--closed is specified, also show branch heads marked closed
3341 (see :hg:`commit --close-branch`).
3341 (see :hg:`commit --close-branch`).
3342
3342
3343 If STARTREV is specified, only those heads that are descendants of
3343 If STARTREV is specified, only those heads that are descendants of
3344 STARTREV will be displayed.
3344 STARTREV will be displayed.
3345
3345
3346 If -t/--topo is specified, named branch mechanics will be ignored and only
3346 If -t/--topo is specified, named branch mechanics will be ignored and only
3347 topological heads (changesets with no children) will be shown.
3347 topological heads (changesets with no children) will be shown.
3348
3348
3349 Returns 0 if matching heads are found, 1 if not.
3349 Returns 0 if matching heads are found, 1 if not.
3350 """
3350 """
3351
3351
3352 start = None
3352 start = None
3353 if 'rev' in opts:
3353 if 'rev' in opts:
3354 start = scmutil.revsingle(repo, opts['rev'], None).node()
3354 start = scmutil.revsingle(repo, opts['rev'], None).node()
3355
3355
3356 if opts.get('topo'):
3356 if opts.get('topo'):
3357 heads = [repo[h] for h in repo.heads(start)]
3357 heads = [repo[h] for h in repo.heads(start)]
3358 else:
3358 else:
3359 heads = []
3359 heads = []
3360 for branch in repo.branchmap():
3360 for branch in repo.branchmap():
3361 heads += repo.branchheads(branch, start, opts.get('closed'))
3361 heads += repo.branchheads(branch, start, opts.get('closed'))
3362 heads = [repo[h] for h in heads]
3362 heads = [repo[h] for h in heads]
3363
3363
3364 if branchrevs:
3364 if branchrevs:
3365 branches = set(repo[br].branch() for br in branchrevs)
3365 branches = set(repo[br].branch() for br in branchrevs)
3366 heads = [h for h in heads if h.branch() in branches]
3366 heads = [h for h in heads if h.branch() in branches]
3367
3367
3368 if opts.get('active') and branchrevs:
3368 if opts.get('active') and branchrevs:
3369 dagheads = repo.heads(start)
3369 dagheads = repo.heads(start)
3370 heads = [h for h in heads if h.node() in dagheads]
3370 heads = [h for h in heads if h.node() in dagheads]
3371
3371
3372 if branchrevs:
3372 if branchrevs:
3373 haveheads = set(h.branch() for h in heads)
3373 haveheads = set(h.branch() for h in heads)
3374 if branches - haveheads:
3374 if branches - haveheads:
3375 headless = ', '.join(b for b in branches - haveheads)
3375 headless = ', '.join(b for b in branches - haveheads)
3376 msg = _('no open branch heads found on branches %s')
3376 msg = _('no open branch heads found on branches %s')
3377 if opts.get('rev'):
3377 if opts.get('rev'):
3378 msg += _(' (started at %s)') % opts['rev']
3378 msg += _(' (started at %s)') % opts['rev']
3379 ui.warn((msg + '\n') % headless)
3379 ui.warn((msg + '\n') % headless)
3380
3380
3381 if not heads:
3381 if not heads:
3382 return 1
3382 return 1
3383
3383
3384 heads = sorted(heads, key=lambda x: -x.rev())
3384 heads = sorted(heads, key=lambda x: -x.rev())
3385 displayer = cmdutil.show_changeset(ui, repo, opts)
3385 displayer = cmdutil.show_changeset(ui, repo, opts)
3386 for ctx in heads:
3386 for ctx in heads:
3387 displayer.show(ctx)
3387 displayer.show(ctx)
3388 displayer.close()
3388 displayer.close()
3389
3389
3390 @command('help',
3390 @command('help',
3391 [('e', 'extension', None, _('show only help for extensions')),
3391 [('e', 'extension', None, _('show only help for extensions')),
3392 ('c', 'command', None, _('show only help for commands')),
3392 ('c', 'command', None, _('show only help for commands')),
3393 ('k', 'keyword', '', _('show topics matching keyword')),
3393 ('k', 'keyword', '', _('show topics matching keyword')),
3394 ],
3394 ],
3395 _('[-ec] [TOPIC]'))
3395 _('[-ec] [TOPIC]'))
3396 def help_(ui, name=None, **opts):
3396 def help_(ui, name=None, **opts):
3397 """show help for a given topic or a help overview
3397 """show help for a given topic or a help overview
3398
3398
3399 With no arguments, print a list of commands with short help messages.
3399 With no arguments, print a list of commands with short help messages.
3400
3400
3401 Given a topic, extension, or command name, print help for that
3401 Given a topic, extension, or command name, print help for that
3402 topic.
3402 topic.
3403
3403
3404 Returns 0 if successful.
3404 Returns 0 if successful.
3405 """
3405 """
3406
3406
3407 textwidth = min(ui.termwidth(), 80) - 2
3407 textwidth = min(ui.termwidth(), 80) - 2
3408
3408
3409 keep = ui.verbose and ['verbose'] or []
3409 keep = ui.verbose and ['verbose'] or []
3410 text = help.help_(ui, name, **opts)
3410 text = help.help_(ui, name, **opts)
3411
3411
3412 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3412 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3413 if 'verbose' in pruned:
3413 if 'verbose' in pruned:
3414 keep.append('omitted')
3414 keep.append('omitted')
3415 else:
3415 else:
3416 keep.append('notomitted')
3416 keep.append('notomitted')
3417 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3417 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3418 ui.write(formatted)
3418 ui.write(formatted)
3419
3419
3420
3420
3421 @command('identify|id',
3421 @command('identify|id',
3422 [('r', 'rev', '',
3422 [('r', 'rev', '',
3423 _('identify the specified revision'), _('REV')),
3423 _('identify the specified revision'), _('REV')),
3424 ('n', 'num', None, _('show local revision number')),
3424 ('n', 'num', None, _('show local revision number')),
3425 ('i', 'id', None, _('show global revision id')),
3425 ('i', 'id', None, _('show global revision id')),
3426 ('b', 'branch', None, _('show branch')),
3426 ('b', 'branch', None, _('show branch')),
3427 ('t', 'tags', None, _('show tags')),
3427 ('t', 'tags', None, _('show tags')),
3428 ('B', 'bookmarks', None, _('show bookmarks')),
3428 ('B', 'bookmarks', None, _('show bookmarks')),
3429 ] + remoteopts,
3429 ] + remoteopts,
3430 _('[-nibtB] [-r REV] [SOURCE]'))
3430 _('[-nibtB] [-r REV] [SOURCE]'))
3431 def identify(ui, repo, source=None, rev=None,
3431 def identify(ui, repo, source=None, rev=None,
3432 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3432 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3433 """identify the working copy or specified revision
3433 """identify the working copy or specified revision
3434
3434
3435 Print a summary identifying the repository state at REV using one or
3435 Print a summary identifying the repository state at REV using one or
3436 two parent hash identifiers, followed by a "+" if the working
3436 two parent hash identifiers, followed by a "+" if the working
3437 directory has uncommitted changes, the branch name (if not default),
3437 directory has uncommitted changes, the branch name (if not default),
3438 a list of tags, and a list of bookmarks.
3438 a list of tags, and a list of bookmarks.
3439
3439
3440 When REV is not given, print a summary of the current state of the
3440 When REV is not given, print a summary of the current state of the
3441 repository.
3441 repository.
3442
3442
3443 Specifying a path to a repository root or Mercurial bundle will
3443 Specifying a path to a repository root or Mercurial bundle will
3444 cause lookup to operate on that repository/bundle.
3444 cause lookup to operate on that repository/bundle.
3445
3445
3446 .. container:: verbose
3446 .. container:: verbose
3447
3447
3448 Examples:
3448 Examples:
3449
3449
3450 - generate a build identifier for the working directory::
3450 - generate a build identifier for the working directory::
3451
3451
3452 hg id --id > build-id.dat
3452 hg id --id > build-id.dat
3453
3453
3454 - find the revision corresponding to a tag::
3454 - find the revision corresponding to a tag::
3455
3455
3456 hg id -n -r 1.3
3456 hg id -n -r 1.3
3457
3457
3458 - check the most recent revision of a remote repository::
3458 - check the most recent revision of a remote repository::
3459
3459
3460 hg id -r tip http://selenic.com/hg/
3460 hg id -r tip http://selenic.com/hg/
3461
3461
3462 Returns 0 if successful.
3462 Returns 0 if successful.
3463 """
3463 """
3464
3464
3465 if not repo and not source:
3465 if not repo and not source:
3466 raise util.Abort(_("there is no Mercurial repository here "
3466 raise util.Abort(_("there is no Mercurial repository here "
3467 "(.hg not found)"))
3467 "(.hg not found)"))
3468
3468
3469 hexfunc = ui.debugflag and hex or short
3469 hexfunc = ui.debugflag and hex or short
3470 default = not (num or id or branch or tags or bookmarks)
3470 default = not (num or id or branch or tags or bookmarks)
3471 output = []
3471 output = []
3472 revs = []
3472 revs = []
3473
3473
3474 if source:
3474 if source:
3475 source, branches = hg.parseurl(ui.expandpath(source))
3475 source, branches = hg.parseurl(ui.expandpath(source))
3476 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3476 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3477 repo = peer.local()
3477 repo = peer.local()
3478 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3478 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3479
3479
3480 if not repo:
3480 if not repo:
3481 if num or branch or tags:
3481 if num or branch or tags:
3482 raise util.Abort(
3482 raise util.Abort(
3483 _("can't query remote revision number, branch, or tags"))
3483 _("can't query remote revision number, branch, or tags"))
3484 if not rev and revs:
3484 if not rev and revs:
3485 rev = revs[0]
3485 rev = revs[0]
3486 if not rev:
3486 if not rev:
3487 rev = "tip"
3487 rev = "tip"
3488
3488
3489 remoterev = peer.lookup(rev)
3489 remoterev = peer.lookup(rev)
3490 if default or id:
3490 if default or id:
3491 output = [hexfunc(remoterev)]
3491 output = [hexfunc(remoterev)]
3492
3492
3493 def getbms():
3493 def getbms():
3494 bms = []
3494 bms = []
3495
3495
3496 if 'bookmarks' in peer.listkeys('namespaces'):
3496 if 'bookmarks' in peer.listkeys('namespaces'):
3497 hexremoterev = hex(remoterev)
3497 hexremoterev = hex(remoterev)
3498 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3498 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3499 if bmr == hexremoterev]
3499 if bmr == hexremoterev]
3500
3500
3501 return sorted(bms)
3501 return sorted(bms)
3502
3502
3503 if bookmarks:
3503 if bookmarks:
3504 output.extend(getbms())
3504 output.extend(getbms())
3505 elif default and not ui.quiet:
3505 elif default and not ui.quiet:
3506 # multiple bookmarks for a single parent separated by '/'
3506 # multiple bookmarks for a single parent separated by '/'
3507 bm = '/'.join(getbms())
3507 bm = '/'.join(getbms())
3508 if bm:
3508 if bm:
3509 output.append(bm)
3509 output.append(bm)
3510 else:
3510 else:
3511 if not rev:
3511 if not rev:
3512 ctx = repo[None]
3512 ctx = repo[None]
3513 parents = ctx.parents()
3513 parents = ctx.parents()
3514 changed = ""
3514 changed = ""
3515 if default or id or num:
3515 if default or id or num:
3516 if (util.any(repo.status())
3516 if (util.any(repo.status())
3517 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3517 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3518 changed = '+'
3518 changed = '+'
3519 if default or id:
3519 if default or id:
3520 output = ["%s%s" %
3520 output = ["%s%s" %
3521 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3521 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3522 if num:
3522 if num:
3523 output.append("%s%s" %
3523 output.append("%s%s" %
3524 ('+'.join([str(p.rev()) for p in parents]), changed))
3524 ('+'.join([str(p.rev()) for p in parents]), changed))
3525 else:
3525 else:
3526 ctx = scmutil.revsingle(repo, rev)
3526 ctx = scmutil.revsingle(repo, rev)
3527 if default or id:
3527 if default or id:
3528 output = [hexfunc(ctx.node())]
3528 output = [hexfunc(ctx.node())]
3529 if num:
3529 if num:
3530 output.append(str(ctx.rev()))
3530 output.append(str(ctx.rev()))
3531
3531
3532 if default and not ui.quiet:
3532 if default and not ui.quiet:
3533 b = ctx.branch()
3533 b = ctx.branch()
3534 if b != 'default':
3534 if b != 'default':
3535 output.append("(%s)" % b)
3535 output.append("(%s)" % b)
3536
3536
3537 # multiple tags for a single parent separated by '/'
3537 # multiple tags for a single parent separated by '/'
3538 t = '/'.join(ctx.tags())
3538 t = '/'.join(ctx.tags())
3539 if t:
3539 if t:
3540 output.append(t)
3540 output.append(t)
3541
3541
3542 # multiple bookmarks for a single parent separated by '/'
3542 # multiple bookmarks for a single parent separated by '/'
3543 bm = '/'.join(ctx.bookmarks())
3543 bm = '/'.join(ctx.bookmarks())
3544 if bm:
3544 if bm:
3545 output.append(bm)
3545 output.append(bm)
3546 else:
3546 else:
3547 if branch:
3547 if branch:
3548 output.append(ctx.branch())
3548 output.append(ctx.branch())
3549
3549
3550 if tags:
3550 if tags:
3551 output.extend(ctx.tags())
3551 output.extend(ctx.tags())
3552
3552
3553 if bookmarks:
3553 if bookmarks:
3554 output.extend(ctx.bookmarks())
3554 output.extend(ctx.bookmarks())
3555
3555
3556 ui.write("%s\n" % ' '.join(output))
3556 ui.write("%s\n" % ' '.join(output))
3557
3557
3558 @command('import|patch',
3558 @command('import|patch',
3559 [('p', 'strip', 1,
3559 [('p', 'strip', 1,
3560 _('directory strip option for patch. This has the same '
3560 _('directory strip option for patch. This has the same '
3561 'meaning as the corresponding patch option'), _('NUM')),
3561 'meaning as the corresponding patch option'), _('NUM')),
3562 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3562 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3563 ('e', 'edit', False, _('invoke editor on commit messages')),
3563 ('e', 'edit', False, _('invoke editor on commit messages')),
3564 ('f', 'force', None,
3564 ('f', 'force', None,
3565 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3565 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3566 ('', 'no-commit', None,
3566 ('', 'no-commit', None,
3567 _("don't commit, just update the working directory")),
3567 _("don't commit, just update the working directory")),
3568 ('', 'bypass', None,
3568 ('', 'bypass', None,
3569 _("apply patch without touching the working directory")),
3569 _("apply patch without touching the working directory")),
3570 ('', 'exact', None,
3570 ('', 'exact', None,
3571 _('apply patch to the nodes from which it was generated')),
3571 _('apply patch to the nodes from which it was generated')),
3572 ('', 'import-branch', None,
3572 ('', 'import-branch', None,
3573 _('use any branch information in patch (implied by --exact)'))] +
3573 _('use any branch information in patch (implied by --exact)'))] +
3574 commitopts + commitopts2 + similarityopts,
3574 commitopts + commitopts2 + similarityopts,
3575 _('[OPTION]... PATCH...'))
3575 _('[OPTION]... PATCH...'))
3576 def import_(ui, repo, patch1=None, *patches, **opts):
3576 def import_(ui, repo, patch1=None, *patches, **opts):
3577 """import an ordered set of patches
3577 """import an ordered set of patches
3578
3578
3579 Import a list of patches and commit them individually (unless
3579 Import a list of patches and commit them individually (unless
3580 --no-commit is specified).
3580 --no-commit is specified).
3581
3581
3582 Because import first applies changes to the working directory,
3582 Because import first applies changes to the working directory,
3583 import will abort if there are outstanding changes.
3583 import will abort if there are outstanding changes.
3584
3584
3585 You can import a patch straight from a mail message. Even patches
3585 You can import a patch straight from a mail message. Even patches
3586 as attachments work (to use the body part, it must have type
3586 as attachments work (to use the body part, it must have type
3587 text/plain or text/x-patch). From and Subject headers of email
3587 text/plain or text/x-patch). From and Subject headers of email
3588 message are used as default committer and commit message. All
3588 message are used as default committer and commit message. All
3589 text/plain body parts before first diff are added to commit
3589 text/plain body parts before first diff are added to commit
3590 message.
3590 message.
3591
3591
3592 If the imported patch was generated by :hg:`export`, user and
3592 If the imported patch was generated by :hg:`export`, user and
3593 description from patch override values from message headers and
3593 description from patch override values from message headers and
3594 body. Values given on command line with -m/--message and -u/--user
3594 body. Values given on command line with -m/--message and -u/--user
3595 override these.
3595 override these.
3596
3596
3597 If --exact is specified, import will set the working directory to
3597 If --exact is specified, import will set the working directory to
3598 the parent of each patch before applying it, and will abort if the
3598 the parent of each patch before applying it, and will abort if the
3599 resulting changeset has a different ID than the one recorded in
3599 resulting changeset has a different ID than the one recorded in
3600 the patch. This may happen due to character set problems or other
3600 the patch. This may happen due to character set problems or other
3601 deficiencies in the text patch format.
3601 deficiencies in the text patch format.
3602
3602
3603 Use --bypass to apply and commit patches directly to the
3603 Use --bypass to apply and commit patches directly to the
3604 repository, not touching the working directory. Without --exact,
3604 repository, not touching the working directory. Without --exact,
3605 patches will be applied on top of the working directory parent
3605 patches will be applied on top of the working directory parent
3606 revision.
3606 revision.
3607
3607
3608 With -s/--similarity, hg will attempt to discover renames and
3608 With -s/--similarity, hg will attempt to discover renames and
3609 copies in the patch in the same way as :hg:`addremove`.
3609 copies in the patch in the same way as :hg:`addremove`.
3610
3610
3611 To read a patch from standard input, use "-" as the patch name. If
3611 To read a patch from standard input, use "-" as the patch name. If
3612 a URL is specified, the patch will be downloaded from it.
3612 a URL is specified, the patch will be downloaded from it.
3613 See :hg:`help dates` for a list of formats valid for -d/--date.
3613 See :hg:`help dates` for a list of formats valid for -d/--date.
3614
3614
3615 .. container:: verbose
3615 .. container:: verbose
3616
3616
3617 Examples:
3617 Examples:
3618
3618
3619 - import a traditional patch from a website and detect renames::
3619 - import a traditional patch from a website and detect renames::
3620
3620
3621 hg import -s 80 http://example.com/bugfix.patch
3621 hg import -s 80 http://example.com/bugfix.patch
3622
3622
3623 - import a changeset from an hgweb server::
3623 - import a changeset from an hgweb server::
3624
3624
3625 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3625 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3626
3626
3627 - import all the patches in an Unix-style mbox::
3627 - import all the patches in an Unix-style mbox::
3628
3628
3629 hg import incoming-patches.mbox
3629 hg import incoming-patches.mbox
3630
3630
3631 - attempt to exactly restore an exported changeset (not always
3631 - attempt to exactly restore an exported changeset (not always
3632 possible)::
3632 possible)::
3633
3633
3634 hg import --exact proposed-fix.patch
3634 hg import --exact proposed-fix.patch
3635
3635
3636 Returns 0 on success.
3636 Returns 0 on success.
3637 """
3637 """
3638
3638
3639 if not patch1:
3639 if not patch1:
3640 raise util.Abort(_('need at least one patch to import'))
3640 raise util.Abort(_('need at least one patch to import'))
3641
3641
3642 patches = (patch1,) + patches
3642 patches = (patch1,) + patches
3643
3643
3644 date = opts.get('date')
3644 date = opts.get('date')
3645 if date:
3645 if date:
3646 opts['date'] = util.parsedate(date)
3646 opts['date'] = util.parsedate(date)
3647
3647
3648 editor = cmdutil.commiteditor
3648 editor = cmdutil.commiteditor
3649 if opts.get('edit'):
3649 if opts.get('edit'):
3650 editor = cmdutil.commitforceeditor
3650 editor = cmdutil.commitforceeditor
3651
3651
3652 update = not opts.get('bypass')
3652 update = not opts.get('bypass')
3653 if not update and opts.get('no_commit'):
3653 if not update and opts.get('no_commit'):
3654 raise util.Abort(_('cannot use --no-commit with --bypass'))
3654 raise util.Abort(_('cannot use --no-commit with --bypass'))
3655 try:
3655 try:
3656 sim = float(opts.get('similarity') or 0)
3656 sim = float(opts.get('similarity') or 0)
3657 except ValueError:
3657 except ValueError:
3658 raise util.Abort(_('similarity must be a number'))
3658 raise util.Abort(_('similarity must be a number'))
3659 if sim < 0 or sim > 100:
3659 if sim < 0 or sim > 100:
3660 raise util.Abort(_('similarity must be between 0 and 100'))
3660 raise util.Abort(_('similarity must be between 0 and 100'))
3661 if sim and not update:
3661 if sim and not update:
3662 raise util.Abort(_('cannot use --similarity with --bypass'))
3662 raise util.Abort(_('cannot use --similarity with --bypass'))
3663
3663
3664 if update:
3664 if update:
3665 cmdutil.checkunfinished(repo)
3665 cmdutil.checkunfinished(repo)
3666 if (opts.get('exact') or not opts.get('force')) and update:
3666 if (opts.get('exact') or not opts.get('force')) and update:
3667 cmdutil.bailifchanged(repo)
3667 cmdutil.bailifchanged(repo)
3668
3668
3669 base = opts["base"]
3669 base = opts["base"]
3670 strip = opts["strip"]
3670 strip = opts["strip"]
3671 wlock = lock = tr = None
3671 wlock = lock = tr = None
3672 msgs = []
3672 msgs = []
3673
3673
3674 def tryone(ui, hunk, parents):
3674 def tryone(ui, hunk, parents):
3675 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3675 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3676 patch.extract(ui, hunk)
3676 patch.extract(ui, hunk)
3677
3677
3678 if not tmpname:
3678 if not tmpname:
3679 return (None, None)
3679 return (None, None)
3680 msg = _('applied to working directory')
3680 msg = _('applied to working directory')
3681
3681
3682 try:
3682 try:
3683 cmdline_message = cmdutil.logmessage(ui, opts)
3683 cmdline_message = cmdutil.logmessage(ui, opts)
3684 if cmdline_message:
3684 if cmdline_message:
3685 # pickup the cmdline msg
3685 # pickup the cmdline msg
3686 message = cmdline_message
3686 message = cmdline_message
3687 elif message:
3687 elif message:
3688 # pickup the patch msg
3688 # pickup the patch msg
3689 message = message.strip()
3689 message = message.strip()
3690 else:
3690 else:
3691 # launch the editor
3691 # launch the editor
3692 message = None
3692 message = None
3693 ui.debug('message:\n%s\n' % message)
3693 ui.debug('message:\n%s\n' % message)
3694
3694
3695 if len(parents) == 1:
3695 if len(parents) == 1:
3696 parents.append(repo[nullid])
3696 parents.append(repo[nullid])
3697 if opts.get('exact'):
3697 if opts.get('exact'):
3698 if not nodeid or not p1:
3698 if not nodeid or not p1:
3699 raise util.Abort(_('not a Mercurial patch'))
3699 raise util.Abort(_('not a Mercurial patch'))
3700 p1 = repo[p1]
3700 p1 = repo[p1]
3701 p2 = repo[p2 or nullid]
3701 p2 = repo[p2 or nullid]
3702 elif p2:
3702 elif p2:
3703 try:
3703 try:
3704 p1 = repo[p1]
3704 p1 = repo[p1]
3705 p2 = repo[p2]
3705 p2 = repo[p2]
3706 # Without any options, consider p2 only if the
3706 # Without any options, consider p2 only if the
3707 # patch is being applied on top of the recorded
3707 # patch is being applied on top of the recorded
3708 # first parent.
3708 # first parent.
3709 if p1 != parents[0]:
3709 if p1 != parents[0]:
3710 p1 = parents[0]
3710 p1 = parents[0]
3711 p2 = repo[nullid]
3711 p2 = repo[nullid]
3712 except error.RepoError:
3712 except error.RepoError:
3713 p1, p2 = parents
3713 p1, p2 = parents
3714 else:
3714 else:
3715 p1, p2 = parents
3715 p1, p2 = parents
3716
3716
3717 n = None
3717 n = None
3718 if update:
3718 if update:
3719 if p1 != parents[0]:
3719 if p1 != parents[0]:
3720 hg.clean(repo, p1.node())
3720 hg.clean(repo, p1.node())
3721 if p2 != parents[1]:
3721 if p2 != parents[1]:
3722 repo.setparents(p1.node(), p2.node())
3722 repo.setparents(p1.node(), p2.node())
3723
3723
3724 if opts.get('exact') or opts.get('import_branch'):
3724 if opts.get('exact') or opts.get('import_branch'):
3725 repo.dirstate.setbranch(branch or 'default')
3725 repo.dirstate.setbranch(branch or 'default')
3726
3726
3727 files = set()
3727 files = set()
3728 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3728 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3729 eolmode=None, similarity=sim / 100.0)
3729 eolmode=None, similarity=sim / 100.0)
3730 files = list(files)
3730 files = list(files)
3731 if opts.get('no_commit'):
3731 if opts.get('no_commit'):
3732 if message:
3732 if message:
3733 msgs.append(message)
3733 msgs.append(message)
3734 else:
3734 else:
3735 if opts.get('exact') or p2:
3735 if opts.get('exact') or p2:
3736 # If you got here, you either use --force and know what
3736 # If you got here, you either use --force and know what
3737 # you are doing or used --exact or a merge patch while
3737 # you are doing or used --exact or a merge patch while
3738 # being updated to its first parent.
3738 # being updated to its first parent.
3739 m = None
3739 m = None
3740 else:
3740 else:
3741 m = scmutil.matchfiles(repo, files or [])
3741 m = scmutil.matchfiles(repo, files or [])
3742 n = repo.commit(message, opts.get('user') or user,
3742 n = repo.commit(message, opts.get('user') or user,
3743 opts.get('date') or date, match=m,
3743 opts.get('date') or date, match=m,
3744 editor=editor)
3744 editor=editor)
3745 else:
3745 else:
3746 if opts.get('exact') or opts.get('import_branch'):
3746 if opts.get('exact') or opts.get('import_branch'):
3747 branch = branch or 'default'
3747 branch = branch or 'default'
3748 else:
3748 else:
3749 branch = p1.branch()
3749 branch = p1.branch()
3750 store = patch.filestore()
3750 store = patch.filestore()
3751 try:
3751 try:
3752 files = set()
3752 files = set()
3753 try:
3753 try:
3754 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3754 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3755 files, eolmode=None)
3755 files, eolmode=None)
3756 except patch.PatchError, e:
3756 except patch.PatchError, e:
3757 raise util.Abort(str(e))
3757 raise util.Abort(str(e))
3758 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3758 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3759 message,
3759 message,
3760 opts.get('user') or user,
3760 opts.get('user') or user,
3761 opts.get('date') or date,
3761 opts.get('date') or date,
3762 branch, files, store,
3762 branch, files, store,
3763 editor=cmdutil.commiteditor)
3763 editor=cmdutil.commiteditor)
3764 repo.savecommitmessage(memctx.description())
3764 repo.savecommitmessage(memctx.description())
3765 n = memctx.commit()
3765 n = memctx.commit()
3766 finally:
3766 finally:
3767 store.close()
3767 store.close()
3768 if opts.get('exact') and hex(n) != nodeid:
3768 if opts.get('exact') and hex(n) != nodeid:
3769 raise util.Abort(_('patch is damaged or loses information'))
3769 raise util.Abort(_('patch is damaged or loses information'))
3770 if n:
3770 if n:
3771 # i18n: refers to a short changeset id
3771 # i18n: refers to a short changeset id
3772 msg = _('created %s') % short(n)
3772 msg = _('created %s') % short(n)
3773 return (msg, n)
3773 return (msg, n)
3774 finally:
3774 finally:
3775 os.unlink(tmpname)
3775 os.unlink(tmpname)
3776
3776
3777 try:
3777 try:
3778 try:
3778 try:
3779 wlock = repo.wlock()
3779 wlock = repo.wlock()
3780 if not opts.get('no_commit'):
3780 if not opts.get('no_commit'):
3781 lock = repo.lock()
3781 lock = repo.lock()
3782 tr = repo.transaction('import')
3782 tr = repo.transaction('import')
3783 parents = repo.parents()
3783 parents = repo.parents()
3784 for patchurl in patches:
3784 for patchurl in patches:
3785 if patchurl == '-':
3785 if patchurl == '-':
3786 ui.status(_('applying patch from stdin\n'))
3786 ui.status(_('applying patch from stdin\n'))
3787 patchfile = ui.fin
3787 patchfile = ui.fin
3788 patchurl = 'stdin' # for error message
3788 patchurl = 'stdin' # for error message
3789 else:
3789 else:
3790 patchurl = os.path.join(base, patchurl)
3790 patchurl = os.path.join(base, patchurl)
3791 ui.status(_('applying %s\n') % patchurl)
3791 ui.status(_('applying %s\n') % patchurl)
3792 patchfile = hg.openpath(ui, patchurl)
3792 patchfile = hg.openpath(ui, patchurl)
3793
3793
3794 haspatch = False
3794 haspatch = False
3795 for hunk in patch.split(patchfile):
3795 for hunk in patch.split(patchfile):
3796 (msg, node) = tryone(ui, hunk, parents)
3796 (msg, node) = tryone(ui, hunk, parents)
3797 if msg:
3797 if msg:
3798 haspatch = True
3798 haspatch = True
3799 ui.note(msg + '\n')
3799 ui.note(msg + '\n')
3800 if update or opts.get('exact'):
3800 if update or opts.get('exact'):
3801 parents = repo.parents()
3801 parents = repo.parents()
3802 else:
3802 else:
3803 parents = [repo[node]]
3803 parents = [repo[node]]
3804
3804
3805 if not haspatch:
3805 if not haspatch:
3806 raise util.Abort(_('%s: no diffs found') % patchurl)
3806 raise util.Abort(_('%s: no diffs found') % patchurl)
3807
3807
3808 if tr:
3808 if tr:
3809 tr.close()
3809 tr.close()
3810 if msgs:
3810 if msgs:
3811 repo.savecommitmessage('\n* * *\n'.join(msgs))
3811 repo.savecommitmessage('\n* * *\n'.join(msgs))
3812 except: # re-raises
3812 except: # re-raises
3813 # wlock.release() indirectly calls dirstate.write(): since
3813 # wlock.release() indirectly calls dirstate.write(): since
3814 # we're crashing, we do not want to change the working dir
3814 # we're crashing, we do not want to change the working dir
3815 # parent after all, so make sure it writes nothing
3815 # parent after all, so make sure it writes nothing
3816 repo.dirstate.invalidate()
3816 repo.dirstate.invalidate()
3817 raise
3817 raise
3818 finally:
3818 finally:
3819 if tr:
3819 if tr:
3820 tr.release()
3820 tr.release()
3821 release(lock, wlock)
3821 release(lock, wlock)
3822
3822
3823 @command('incoming|in',
3823 @command('incoming|in',
3824 [('f', 'force', None,
3824 [('f', 'force', None,
3825 _('run even if remote repository is unrelated')),
3825 _('run even if remote repository is unrelated')),
3826 ('n', 'newest-first', None, _('show newest record first')),
3826 ('n', 'newest-first', None, _('show newest record first')),
3827 ('', 'bundle', '',
3827 ('', 'bundle', '',
3828 _('file to store the bundles into'), _('FILE')),
3828 _('file to store the bundles into'), _('FILE')),
3829 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3829 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3830 ('B', 'bookmarks', False, _("compare bookmarks")),
3830 ('B', 'bookmarks', False, _("compare bookmarks")),
3831 ('b', 'branch', [],
3831 ('b', 'branch', [],
3832 _('a specific branch you would like to pull'), _('BRANCH')),
3832 _('a specific branch you would like to pull'), _('BRANCH')),
3833 ] + logopts + remoteopts + subrepoopts,
3833 ] + logopts + remoteopts + subrepoopts,
3834 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3834 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3835 def incoming(ui, repo, source="default", **opts):
3835 def incoming(ui, repo, source="default", **opts):
3836 """show new changesets found in source
3836 """show new changesets found in source
3837
3837
3838 Show new changesets found in the specified path/URL or the default
3838 Show new changesets found in the specified path/URL or the default
3839 pull location. These are the changesets that would have been pulled
3839 pull location. These are the changesets that would have been pulled
3840 if a pull at the time you issued this command.
3840 if a pull at the time you issued this command.
3841
3841
3842 For remote repository, using --bundle avoids downloading the
3842 For remote repository, using --bundle avoids downloading the
3843 changesets twice if the incoming is followed by a pull.
3843 changesets twice if the incoming is followed by a pull.
3844
3844
3845 See pull for valid source format details.
3845 See pull for valid source format details.
3846
3846
3847 Returns 0 if there are incoming changes, 1 otherwise.
3847 Returns 0 if there are incoming changes, 1 otherwise.
3848 """
3848 """
3849 if opts.get('graph'):
3849 if opts.get('graph'):
3850 cmdutil.checkunsupportedgraphflags([], opts)
3850 cmdutil.checkunsupportedgraphflags([], opts)
3851 def display(other, chlist, displayer):
3851 def display(other, chlist, displayer):
3852 revdag = cmdutil.graphrevs(other, chlist, opts)
3852 revdag = cmdutil.graphrevs(other, chlist, opts)
3853 showparents = [ctx.node() for ctx in repo[None].parents()]
3853 showparents = [ctx.node() for ctx in repo[None].parents()]
3854 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3854 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3855 graphmod.asciiedges)
3855 graphmod.asciiedges)
3856
3856
3857 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3857 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3858 return 0
3858 return 0
3859
3859
3860 if opts.get('bundle') and opts.get('subrepos'):
3860 if opts.get('bundle') and opts.get('subrepos'):
3861 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3861 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3862
3862
3863 if opts.get('bookmarks'):
3863 if opts.get('bookmarks'):
3864 source, branches = hg.parseurl(ui.expandpath(source),
3864 source, branches = hg.parseurl(ui.expandpath(source),
3865 opts.get('branch'))
3865 opts.get('branch'))
3866 other = hg.peer(repo, opts, source)
3866 other = hg.peer(repo, opts, source)
3867 if 'bookmarks' not in other.listkeys('namespaces'):
3867 if 'bookmarks' not in other.listkeys('namespaces'):
3868 ui.warn(_("remote doesn't support bookmarks\n"))
3868 ui.warn(_("remote doesn't support bookmarks\n"))
3869 return 0
3869 return 0
3870 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3870 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3871 return bookmarks.diff(ui, repo, other)
3871 return bookmarks.diff(ui, repo, other)
3872
3872
3873 repo._subtoppath = ui.expandpath(source)
3873 repo._subtoppath = ui.expandpath(source)
3874 try:
3874 try:
3875 return hg.incoming(ui, repo, source, opts)
3875 return hg.incoming(ui, repo, source, opts)
3876 finally:
3876 finally:
3877 del repo._subtoppath
3877 del repo._subtoppath
3878
3878
3879
3879
3880 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3880 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3881 def init(ui, dest=".", **opts):
3881 def init(ui, dest=".", **opts):
3882 """create a new repository in the given directory
3882 """create a new repository in the given directory
3883
3883
3884 Initialize a new repository in the given directory. If the given
3884 Initialize a new repository in the given directory. If the given
3885 directory does not exist, it will be created.
3885 directory does not exist, it will be created.
3886
3886
3887 If no directory is given, the current directory is used.
3887 If no directory is given, the current directory is used.
3888
3888
3889 It is possible to specify an ``ssh://`` URL as the destination.
3889 It is possible to specify an ``ssh://`` URL as the destination.
3890 See :hg:`help urls` for more information.
3890 See :hg:`help urls` for more information.
3891
3891
3892 Returns 0 on success.
3892 Returns 0 on success.
3893 """
3893 """
3894 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3894 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3895
3895
3896 @command('locate',
3896 @command('locate',
3897 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3897 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3898 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3898 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3899 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3899 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3900 ] + walkopts,
3900 ] + walkopts,
3901 _('[OPTION]... [PATTERN]...'))
3901 _('[OPTION]... [PATTERN]...'))
3902 def locate(ui, repo, *pats, **opts):
3902 def locate(ui, repo, *pats, **opts):
3903 """locate files matching specific patterns
3903 """locate files matching specific patterns
3904
3904
3905 Print files under Mercurial control in the working directory whose
3905 Print files under Mercurial control in the working directory whose
3906 names match the given patterns.
3906 names match the given patterns.
3907
3907
3908 By default, this command searches all directories in the working
3908 By default, this command searches all directories in the working
3909 directory. To search just the current directory and its
3909 directory. To search just the current directory and its
3910 subdirectories, use "--include .".
3910 subdirectories, use "--include .".
3911
3911
3912 If no patterns are given to match, this command prints the names
3912 If no patterns are given to match, this command prints the names
3913 of all files under Mercurial control in the working directory.
3913 of all files under Mercurial control in the working directory.
3914
3914
3915 If you want to feed the output of this command into the "xargs"
3915 If you want to feed the output of this command into the "xargs"
3916 command, use the -0 option to both this command and "xargs". This
3916 command, use the -0 option to both this command and "xargs". This
3917 will avoid the problem of "xargs" treating single filenames that
3917 will avoid the problem of "xargs" treating single filenames that
3918 contain whitespace as multiple filenames.
3918 contain whitespace as multiple filenames.
3919
3919
3920 Returns 0 if a match is found, 1 otherwise.
3920 Returns 0 if a match is found, 1 otherwise.
3921 """
3921 """
3922 end = opts.get('print0') and '\0' or '\n'
3922 end = opts.get('print0') and '\0' or '\n'
3923 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3923 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3924
3924
3925 ret = 1
3925 ret = 1
3926 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3926 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3927 m.bad = lambda x, y: False
3927 m.bad = lambda x, y: False
3928 for abs in repo[rev].walk(m):
3928 for abs in repo[rev].walk(m):
3929 if not rev and abs not in repo.dirstate:
3929 if not rev and abs not in repo.dirstate:
3930 continue
3930 continue
3931 if opts.get('fullpath'):
3931 if opts.get('fullpath'):
3932 ui.write(repo.wjoin(abs), end)
3932 ui.write(repo.wjoin(abs), end)
3933 else:
3933 else:
3934 ui.write(((pats and m.rel(abs)) or abs), end)
3934 ui.write(((pats and m.rel(abs)) or abs), end)
3935 ret = 0
3935 ret = 0
3936
3936
3937 return ret
3937 return ret
3938
3938
3939 @command('^log|history',
3939 @command('^log|history',
3940 [('f', 'follow', None,
3940 [('f', 'follow', None,
3941 _('follow changeset history, or file history across copies and renames')),
3941 _('follow changeset history, or file history across copies and renames')),
3942 ('', 'follow-first', None,
3942 ('', 'follow-first', None,
3943 _('only follow the first parent of merge changesets (DEPRECATED)')),
3943 _('only follow the first parent of merge changesets (DEPRECATED)')),
3944 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3944 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3945 ('C', 'copies', None, _('show copied files')),
3945 ('C', 'copies', None, _('show copied files')),
3946 ('k', 'keyword', [],
3946 ('k', 'keyword', [],
3947 _('do case-insensitive search for a given text'), _('TEXT')),
3947 _('do case-insensitive search for a given text'), _('TEXT')),
3948 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3948 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3949 ('', 'removed', None, _('include revisions where files were removed')),
3949 ('', 'removed', None, _('include revisions where files were removed')),
3950 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3950 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3951 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3951 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3952 ('', 'only-branch', [],
3952 ('', 'only-branch', [],
3953 _('show only changesets within the given named branch (DEPRECATED)'),
3953 _('show only changesets within the given named branch (DEPRECATED)'),
3954 _('BRANCH')),
3954 _('BRANCH')),
3955 ('b', 'branch', [],
3955 ('b', 'branch', [],
3956 _('show changesets within the given named branch'), _('BRANCH')),
3956 _('show changesets within the given named branch'), _('BRANCH')),
3957 ('P', 'prune', [],
3957 ('P', 'prune', [],
3958 _('do not display revision or any of its ancestors'), _('REV')),
3958 _('do not display revision or any of its ancestors'), _('REV')),
3959 ] + logopts + walkopts,
3959 ] + logopts + walkopts,
3960 _('[OPTION]... [FILE]'))
3960 _('[OPTION]... [FILE]'))
3961 def log(ui, repo, *pats, **opts):
3961 def log(ui, repo, *pats, **opts):
3962 """show revision history of entire repository or files
3962 """show revision history of entire repository or files
3963
3963
3964 Print the revision history of the specified files or the entire
3964 Print the revision history of the specified files or the entire
3965 project.
3965 project.
3966
3966
3967 If no revision range is specified, the default is ``tip:0`` unless
3967 If no revision range is specified, the default is ``tip:0`` unless
3968 --follow is set, in which case the working directory parent is
3968 --follow is set, in which case the working directory parent is
3969 used as the starting revision.
3969 used as the starting revision.
3970
3970
3971 File history is shown without following rename or copy history of
3971 File history is shown without following rename or copy history of
3972 files. Use -f/--follow with a filename to follow history across
3972 files. Use -f/--follow with a filename to follow history across
3973 renames and copies. --follow without a filename will only show
3973 renames and copies. --follow without a filename will only show
3974 ancestors or descendants of the starting revision.
3974 ancestors or descendants of the starting revision.
3975
3975
3976 By default this command prints revision number and changeset id,
3976 By default this command prints revision number and changeset id,
3977 tags, non-trivial parents, user, date and time, and a summary for
3977 tags, non-trivial parents, user, date and time, and a summary for
3978 each commit. When the -v/--verbose switch is used, the list of
3978 each commit. When the -v/--verbose switch is used, the list of
3979 changed files and full commit message are shown.
3979 changed files and full commit message are shown.
3980
3980
3981 .. note::
3981 .. note::
3982 log -p/--patch may generate unexpected diff output for merge
3982 log -p/--patch may generate unexpected diff output for merge
3983 changesets, as it will only compare the merge changeset against
3983 changesets, as it will only compare the merge changeset against
3984 its first parent. Also, only files different from BOTH parents
3984 its first parent. Also, only files different from BOTH parents
3985 will appear in files:.
3985 will appear in files:.
3986
3986
3987 .. note::
3987 .. note::
3988 for performance reasons, log FILE may omit duplicate changes
3988 for performance reasons, log FILE may omit duplicate changes
3989 made on branches and will not show deletions. To see all
3989 made on branches and will not show deletions. To see all
3990 changes including duplicates and deletions, use the --removed
3990 changes including duplicates and deletions, use the --removed
3991 switch.
3991 switch.
3992
3992
3993 .. container:: verbose
3993 .. container:: verbose
3994
3994
3995 Some examples:
3995 Some examples:
3996
3996
3997 - changesets with full descriptions and file lists::
3997 - changesets with full descriptions and file lists::
3998
3998
3999 hg log -v
3999 hg log -v
4000
4000
4001 - changesets ancestral to the working directory::
4001 - changesets ancestral to the working directory::
4002
4002
4003 hg log -f
4003 hg log -f
4004
4004
4005 - last 10 commits on the current branch::
4005 - last 10 commits on the current branch::
4006
4006
4007 hg log -l 10 -b .
4007 hg log -l 10 -b .
4008
4008
4009 - changesets showing all modifications of a file, including removals::
4009 - changesets showing all modifications of a file, including removals::
4010
4010
4011 hg log --removed file.c
4011 hg log --removed file.c
4012
4012
4013 - all changesets that touch a directory, with diffs, excluding merges::
4013 - all changesets that touch a directory, with diffs, excluding merges::
4014
4014
4015 hg log -Mp lib/
4015 hg log -Mp lib/
4016
4016
4017 - all revision numbers that match a keyword::
4017 - all revision numbers that match a keyword::
4018
4018
4019 hg log -k bug --template "{rev}\\n"
4019 hg log -k bug --template "{rev}\\n"
4020
4020
4021 - check if a given changeset is included is a tagged release::
4021 - check if a given changeset is included is a tagged release::
4022
4022
4023 hg log -r "a21ccf and ancestor(1.9)"
4023 hg log -r "a21ccf and ancestor(1.9)"
4024
4024
4025 - find all changesets by some user in a date range::
4025 - find all changesets by some user in a date range::
4026
4026
4027 hg log -k alice -d "may 2008 to jul 2008"
4027 hg log -k alice -d "may 2008 to jul 2008"
4028
4028
4029 - summary of all changesets after the last tag::
4029 - summary of all changesets after the last tag::
4030
4030
4031 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4031 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4032
4032
4033 See :hg:`help dates` for a list of formats valid for -d/--date.
4033 See :hg:`help dates` for a list of formats valid for -d/--date.
4034
4034
4035 See :hg:`help revisions` and :hg:`help revsets` for more about
4035 See :hg:`help revisions` and :hg:`help revsets` for more about
4036 specifying revisions.
4036 specifying revisions.
4037
4037
4038 See :hg:`help templates` for more about pre-packaged styles and
4038 See :hg:`help templates` for more about pre-packaged styles and
4039 specifying custom templates.
4039 specifying custom templates.
4040
4040
4041 Returns 0 on success.
4041 Returns 0 on success.
4042 """
4042 """
4043 if opts.get('graph'):
4043 if opts.get('graph'):
4044 return cmdutil.graphlog(ui, repo, *pats, **opts)
4044 return cmdutil.graphlog(ui, repo, *pats, **opts)
4045
4045
4046 matchfn = scmutil.match(repo[None], pats, opts)
4046 matchfn = scmutil.match(repo[None], pats, opts)
4047 limit = cmdutil.loglimit(opts)
4047 limit = cmdutil.loglimit(opts)
4048 count = 0
4048 count = 0
4049
4049
4050 getrenamed, endrev = None, None
4050 getrenamed, endrev = None, None
4051 if opts.get('copies'):
4051 if opts.get('copies'):
4052 if opts.get('rev'):
4052 if opts.get('rev'):
4053 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4053 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4054 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4054 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4055
4055
4056 df = False
4056 df = False
4057 if opts.get("date"):
4057 if opts.get("date"):
4058 df = util.matchdate(opts["date"])
4058 df = util.matchdate(opts["date"])
4059
4059
4060 branches = opts.get('branch', []) + opts.get('only_branch', [])
4060 branches = opts.get('branch', []) + opts.get('only_branch', [])
4061 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4061 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4062
4062
4063 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4063 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4064 def prep(ctx, fns):
4064 def prep(ctx, fns):
4065 rev = ctx.rev()
4065 rev = ctx.rev()
4066 parents = [p for p in repo.changelog.parentrevs(rev)
4066 parents = [p for p in repo.changelog.parentrevs(rev)
4067 if p != nullrev]
4067 if p != nullrev]
4068 if opts.get('no_merges') and len(parents) == 2:
4068 if opts.get('no_merges') and len(parents) == 2:
4069 return
4069 return
4070 if opts.get('only_merges') and len(parents) != 2:
4070 if opts.get('only_merges') and len(parents) != 2:
4071 return
4071 return
4072 if opts.get('branch') and ctx.branch() not in opts['branch']:
4072 if opts.get('branch') and ctx.branch() not in opts['branch']:
4073 return
4073 return
4074 if df and not df(ctx.date()[0]):
4074 if df and not df(ctx.date()[0]):
4075 return
4075 return
4076
4076
4077 lower = encoding.lower
4077 lower = encoding.lower
4078 if opts.get('user'):
4078 if opts.get('user'):
4079 luser = lower(ctx.user())
4079 luser = lower(ctx.user())
4080 for k in [lower(x) for x in opts['user']]:
4080 for k in [lower(x) for x in opts['user']]:
4081 if (k in luser):
4081 if (k in luser):
4082 break
4082 break
4083 else:
4083 else:
4084 return
4084 return
4085 if opts.get('keyword'):
4085 if opts.get('keyword'):
4086 luser = lower(ctx.user())
4086 luser = lower(ctx.user())
4087 ldesc = lower(ctx.description())
4087 ldesc = lower(ctx.description())
4088 lfiles = lower(" ".join(ctx.files()))
4088 lfiles = lower(" ".join(ctx.files()))
4089 for k in [lower(x) for x in opts['keyword']]:
4089 for k in [lower(x) for x in opts['keyword']]:
4090 if (k in luser or k in ldesc or k in lfiles):
4090 if (k in luser or k in ldesc or k in lfiles):
4091 break
4091 break
4092 else:
4092 else:
4093 return
4093 return
4094
4094
4095 copies = None
4095 copies = None
4096 if getrenamed is not None and rev:
4096 if getrenamed is not None and rev:
4097 copies = []
4097 copies = []
4098 for fn in ctx.files():
4098 for fn in ctx.files():
4099 rename = getrenamed(fn, rev)
4099 rename = getrenamed(fn, rev)
4100 if rename:
4100 if rename:
4101 copies.append((fn, rename[0]))
4101 copies.append((fn, rename[0]))
4102
4102
4103 revmatchfn = None
4103 revmatchfn = None
4104 if opts.get('patch') or opts.get('stat'):
4104 if opts.get('patch') or opts.get('stat'):
4105 if opts.get('follow') or opts.get('follow_first'):
4105 if opts.get('follow') or opts.get('follow_first'):
4106 # note: this might be wrong when following through merges
4106 # note: this might be wrong when following through merges
4107 revmatchfn = scmutil.match(repo[None], fns, default='path')
4107 revmatchfn = scmutil.match(repo[None], fns, default='path')
4108 else:
4108 else:
4109 revmatchfn = matchfn
4109 revmatchfn = matchfn
4110
4110
4111 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4111 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4112
4112
4113 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4113 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4114 if displayer.flush(ctx.rev()):
4114 if displayer.flush(ctx.rev()):
4115 count += 1
4115 count += 1
4116 if count == limit:
4116 if count == limit:
4117 break
4117 break
4118 displayer.close()
4118 displayer.close()
4119
4119
4120 @command('manifest',
4120 @command('manifest',
4121 [('r', 'rev', '', _('revision to display'), _('REV')),
4121 [('r', 'rev', '', _('revision to display'), _('REV')),
4122 ('', 'all', False, _("list files from all revisions"))],
4122 ('', 'all', False, _("list files from all revisions"))],
4123 _('[-r REV]'))
4123 _('[-r REV]'))
4124 def manifest(ui, repo, node=None, rev=None, **opts):
4124 def manifest(ui, repo, node=None, rev=None, **opts):
4125 """output the current or given revision of the project manifest
4125 """output the current or given revision of the project manifest
4126
4126
4127 Print a list of version controlled files for the given revision.
4127 Print a list of version controlled files for the given revision.
4128 If no revision is given, the first parent of the working directory
4128 If no revision is given, the first parent of the working directory
4129 is used, or the null revision if no revision is checked out.
4129 is used, or the null revision if no revision is checked out.
4130
4130
4131 With -v, print file permissions, symlink and executable bits.
4131 With -v, print file permissions, symlink and executable bits.
4132 With --debug, print file revision hashes.
4132 With --debug, print file revision hashes.
4133
4133
4134 If option --all is specified, the list of all files from all revisions
4134 If option --all is specified, the list of all files from all revisions
4135 is printed. This includes deleted and renamed files.
4135 is printed. This includes deleted and renamed files.
4136
4136
4137 Returns 0 on success.
4137 Returns 0 on success.
4138 """
4138 """
4139
4139
4140 fm = ui.formatter('manifest', opts)
4140 fm = ui.formatter('manifest', opts)
4141
4141
4142 if opts.get('all'):
4142 if opts.get('all'):
4143 if rev or node:
4143 if rev or node:
4144 raise util.Abort(_("can't specify a revision with --all"))
4144 raise util.Abort(_("can't specify a revision with --all"))
4145
4145
4146 res = []
4146 res = []
4147 prefix = "data/"
4147 prefix = "data/"
4148 suffix = ".i"
4148 suffix = ".i"
4149 plen = len(prefix)
4149 plen = len(prefix)
4150 slen = len(suffix)
4150 slen = len(suffix)
4151 lock = repo.lock()
4151 lock = repo.lock()
4152 try:
4152 try:
4153 for fn, b, size in repo.store.datafiles():
4153 for fn, b, size in repo.store.datafiles():
4154 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4154 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4155 res.append(fn[plen:-slen])
4155 res.append(fn[plen:-slen])
4156 finally:
4156 finally:
4157 lock.release()
4157 lock.release()
4158 for f in res:
4158 for f in res:
4159 fm.startitem()
4159 fm.startitem()
4160 fm.write("path", '%s\n', f)
4160 fm.write("path", '%s\n', f)
4161 fm.end()
4161 fm.end()
4162 return
4162 return
4163
4163
4164 if rev and node:
4164 if rev and node:
4165 raise util.Abort(_("please specify just one revision"))
4165 raise util.Abort(_("please specify just one revision"))
4166
4166
4167 if not node:
4167 if not node:
4168 node = rev
4168 node = rev
4169
4169
4170 char = {'l': '@', 'x': '*', '': ''}
4170 char = {'l': '@', 'x': '*', '': ''}
4171 mode = {'l': '644', 'x': '755', '': '644'}
4171 mode = {'l': '644', 'x': '755', '': '644'}
4172 ctx = scmutil.revsingle(repo, node)
4172 ctx = scmutil.revsingle(repo, node)
4173 mf = ctx.manifest()
4173 mf = ctx.manifest()
4174 for f in ctx:
4174 for f in ctx:
4175 fm.startitem()
4175 fm.startitem()
4176 fl = ctx[f].flags()
4176 fl = ctx[f].flags()
4177 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4177 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4178 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4178 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4179 fm.write('path', '%s\n', f)
4179 fm.write('path', '%s\n', f)
4180 fm.end()
4180 fm.end()
4181
4181
4182 @command('^merge',
4182 @command('^merge',
4183 [('f', 'force', None,
4183 [('f', 'force', None,
4184 _('force a merge including outstanding changes (DEPRECATED)')),
4184 _('force a merge including outstanding changes (DEPRECATED)')),
4185 ('r', 'rev', '', _('revision to merge'), _('REV')),
4185 ('r', 'rev', '', _('revision to merge'), _('REV')),
4186 ('P', 'preview', None,
4186 ('P', 'preview', None,
4187 _('review revisions to merge (no merge is performed)'))
4187 _('review revisions to merge (no merge is performed)'))
4188 ] + mergetoolopts,
4188 ] + mergetoolopts,
4189 _('[-P] [-f] [[-r] REV]'))
4189 _('[-P] [-f] [[-r] REV]'))
4190 def merge(ui, repo, node=None, **opts):
4190 def merge(ui, repo, node=None, **opts):
4191 """merge working directory with another revision
4191 """merge working directory with another revision
4192
4192
4193 The current working directory is updated with all changes made in
4193 The current working directory is updated with all changes made in
4194 the requested revision since the last common predecessor revision.
4194 the requested revision since the last common predecessor revision.
4195
4195
4196 Files that changed between either parent are marked as changed for
4196 Files that changed between either parent are marked as changed for
4197 the next commit and a commit must be performed before any further
4197 the next commit and a commit must be performed before any further
4198 updates to the repository are allowed. The next commit will have
4198 updates to the repository are allowed. The next commit will have
4199 two parents.
4199 two parents.
4200
4200
4201 ``--tool`` can be used to specify the merge tool used for file
4201 ``--tool`` can be used to specify the merge tool used for file
4202 merges. It overrides the HGMERGE environment variable and your
4202 merges. It overrides the HGMERGE environment variable and your
4203 configuration files. See :hg:`help merge-tools` for options.
4203 configuration files. See :hg:`help merge-tools` for options.
4204
4204
4205 If no revision is specified, the working directory's parent is a
4205 If no revision is specified, the working directory's parent is a
4206 head revision, and the current branch contains exactly one other
4206 head revision, and the current branch contains exactly one other
4207 head, the other head is merged with by default. Otherwise, an
4207 head, the other head is merged with by default. Otherwise, an
4208 explicit revision with which to merge with must be provided.
4208 explicit revision with which to merge with must be provided.
4209
4209
4210 :hg:`resolve` must be used to resolve unresolved files.
4210 :hg:`resolve` must be used to resolve unresolved files.
4211
4211
4212 To undo an uncommitted merge, use :hg:`update --clean .` which
4212 To undo an uncommitted merge, use :hg:`update --clean .` which
4213 will check out a clean copy of the original merge parent, losing
4213 will check out a clean copy of the original merge parent, losing
4214 all changes.
4214 all changes.
4215
4215
4216 Returns 0 on success, 1 if there are unresolved files.
4216 Returns 0 on success, 1 if there are unresolved files.
4217 """
4217 """
4218
4218
4219 if opts.get('rev') and node:
4219 if opts.get('rev') and node:
4220 raise util.Abort(_("please specify just one revision"))
4220 raise util.Abort(_("please specify just one revision"))
4221 if not node:
4221 if not node:
4222 node = opts.get('rev')
4222 node = opts.get('rev')
4223
4223
4224 if node:
4224 if node:
4225 node = scmutil.revsingle(repo, node).node()
4225 node = scmutil.revsingle(repo, node).node()
4226
4226
4227 if not node and repo._bookmarkcurrent:
4227 if not node and repo._bookmarkcurrent:
4228 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4228 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4229 curhead = repo[repo._bookmarkcurrent].node()
4229 curhead = repo[repo._bookmarkcurrent].node()
4230 if len(bmheads) == 2:
4230 if len(bmheads) == 2:
4231 if curhead == bmheads[0]:
4231 if curhead == bmheads[0]:
4232 node = bmheads[1]
4232 node = bmheads[1]
4233 else:
4233 else:
4234 node = bmheads[0]
4234 node = bmheads[0]
4235 elif len(bmheads) > 2:
4235 elif len(bmheads) > 2:
4236 raise util.Abort(_("multiple matching bookmarks to merge - "
4236 raise util.Abort(_("multiple matching bookmarks to merge - "
4237 "please merge with an explicit rev or bookmark"),
4237 "please merge with an explicit rev or bookmark"),
4238 hint=_("run 'hg heads' to see all heads"))
4238 hint=_("run 'hg heads' to see all heads"))
4239 elif len(bmheads) <= 1:
4239 elif len(bmheads) <= 1:
4240 raise util.Abort(_("no matching bookmark to merge - "
4240 raise util.Abort(_("no matching bookmark to merge - "
4241 "please merge with an explicit rev or bookmark"),
4241 "please merge with an explicit rev or bookmark"),
4242 hint=_("run 'hg heads' to see all heads"))
4242 hint=_("run 'hg heads' to see all heads"))
4243
4243
4244 if not node and not repo._bookmarkcurrent:
4244 if not node and not repo._bookmarkcurrent:
4245 branch = repo[None].branch()
4245 branch = repo[None].branch()
4246 bheads = repo.branchheads(branch)
4246 bheads = repo.branchheads(branch)
4247 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4247 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4248
4248
4249 if len(nbhs) > 2:
4249 if len(nbhs) > 2:
4250 raise util.Abort(_("branch '%s' has %d heads - "
4250 raise util.Abort(_("branch '%s' has %d heads - "
4251 "please merge with an explicit rev")
4251 "please merge with an explicit rev")
4252 % (branch, len(bheads)),
4252 % (branch, len(bheads)),
4253 hint=_("run 'hg heads .' to see heads"))
4253 hint=_("run 'hg heads .' to see heads"))
4254
4254
4255 parent = repo.dirstate.p1()
4255 parent = repo.dirstate.p1()
4256 if len(nbhs) <= 1:
4256 if len(nbhs) <= 1:
4257 if len(bheads) > 1:
4257 if len(bheads) > 1:
4258 raise util.Abort(_("heads are bookmarked - "
4258 raise util.Abort(_("heads are bookmarked - "
4259 "please merge with an explicit rev"),
4259 "please merge with an explicit rev"),
4260 hint=_("run 'hg heads' to see all heads"))
4260 hint=_("run 'hg heads' to see all heads"))
4261 if len(repo.heads()) > 1:
4261 if len(repo.heads()) > 1:
4262 raise util.Abort(_("branch '%s' has one head - "
4262 raise util.Abort(_("branch '%s' has one head - "
4263 "please merge with an explicit rev")
4263 "please merge with an explicit rev")
4264 % branch,
4264 % branch,
4265 hint=_("run 'hg heads' to see all heads"))
4265 hint=_("run 'hg heads' to see all heads"))
4266 msg, hint = _('nothing to merge'), None
4266 msg, hint = _('nothing to merge'), None
4267 if parent != repo.lookup(branch):
4267 if parent != repo.lookup(branch):
4268 hint = _("use 'hg update' instead")
4268 hint = _("use 'hg update' instead")
4269 raise util.Abort(msg, hint=hint)
4269 raise util.Abort(msg, hint=hint)
4270
4270
4271 if parent not in bheads:
4271 if parent not in bheads:
4272 raise util.Abort(_('working directory not at a head revision'),
4272 raise util.Abort(_('working directory not at a head revision'),
4273 hint=_("use 'hg update' or merge with an "
4273 hint=_("use 'hg update' or merge with an "
4274 "explicit revision"))
4274 "explicit revision"))
4275 if parent == nbhs[0]:
4275 if parent == nbhs[0]:
4276 node = nbhs[-1]
4276 node = nbhs[-1]
4277 else:
4277 else:
4278 node = nbhs[0]
4278 node = nbhs[0]
4279
4279
4280 if opts.get('preview'):
4280 if opts.get('preview'):
4281 # find nodes that are ancestors of p2 but not of p1
4281 # find nodes that are ancestors of p2 but not of p1
4282 p1 = repo.lookup('.')
4282 p1 = repo.lookup('.')
4283 p2 = repo.lookup(node)
4283 p2 = repo.lookup(node)
4284 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4284 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4285
4285
4286 displayer = cmdutil.show_changeset(ui, repo, opts)
4286 displayer = cmdutil.show_changeset(ui, repo, opts)
4287 for node in nodes:
4287 for node in nodes:
4288 displayer.show(repo[node])
4288 displayer.show(repo[node])
4289 displayer.close()
4289 displayer.close()
4290 return 0
4290 return 0
4291
4291
4292 try:
4292 try:
4293 # ui.forcemerge is an internal variable, do not document
4293 # ui.forcemerge is an internal variable, do not document
4294 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4294 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4295 return hg.merge(repo, node, force=opts.get('force'))
4295 return hg.merge(repo, node, force=opts.get('force'))
4296 finally:
4296 finally:
4297 ui.setconfig('ui', 'forcemerge', '')
4297 ui.setconfig('ui', 'forcemerge', '')
4298
4298
4299 @command('outgoing|out',
4299 @command('outgoing|out',
4300 [('f', 'force', None, _('run even when the destination is unrelated')),
4300 [('f', 'force', None, _('run even when the destination is unrelated')),
4301 ('r', 'rev', [],
4301 ('r', 'rev', [],
4302 _('a changeset intended to be included in the destination'), _('REV')),
4302 _('a changeset intended to be included in the destination'), _('REV')),
4303 ('n', 'newest-first', None, _('show newest record first')),
4303 ('n', 'newest-first', None, _('show newest record first')),
4304 ('B', 'bookmarks', False, _('compare bookmarks')),
4304 ('B', 'bookmarks', False, _('compare bookmarks')),
4305 ('b', 'branch', [], _('a specific branch you would like to push'),
4305 ('b', 'branch', [], _('a specific branch you would like to push'),
4306 _('BRANCH')),
4306 _('BRANCH')),
4307 ] + logopts + remoteopts + subrepoopts,
4307 ] + logopts + remoteopts + subrepoopts,
4308 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4308 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4309 def outgoing(ui, repo, dest=None, **opts):
4309 def outgoing(ui, repo, dest=None, **opts):
4310 """show changesets not found in the destination
4310 """show changesets not found in the destination
4311
4311
4312 Show changesets not found in the specified destination repository
4312 Show changesets not found in the specified destination repository
4313 or the default push location. These are the changesets that would
4313 or the default push location. These are the changesets that would
4314 be pushed if a push was requested.
4314 be pushed if a push was requested.
4315
4315
4316 See pull for details of valid destination formats.
4316 See pull for details of valid destination formats.
4317
4317
4318 Returns 0 if there are outgoing changes, 1 otherwise.
4318 Returns 0 if there are outgoing changes, 1 otherwise.
4319 """
4319 """
4320 if opts.get('graph'):
4320 if opts.get('graph'):
4321 cmdutil.checkunsupportedgraphflags([], opts)
4321 cmdutil.checkunsupportedgraphflags([], opts)
4322 o = hg._outgoing(ui, repo, dest, opts)
4322 o = hg._outgoing(ui, repo, dest, opts)
4323 if o is None:
4323 if o is None:
4324 return
4324 return
4325
4325
4326 revdag = cmdutil.graphrevs(repo, o, opts)
4326 revdag = cmdutil.graphrevs(repo, o, opts)
4327 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4327 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4328 showparents = [ctx.node() for ctx in repo[None].parents()]
4328 showparents = [ctx.node() for ctx in repo[None].parents()]
4329 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4329 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4330 graphmod.asciiedges)
4330 graphmod.asciiedges)
4331 return 0
4331 return 0
4332
4332
4333 if opts.get('bookmarks'):
4333 if opts.get('bookmarks'):
4334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4334 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4335 dest, branches = hg.parseurl(dest, opts.get('branch'))
4335 dest, branches = hg.parseurl(dest, opts.get('branch'))
4336 other = hg.peer(repo, opts, dest)
4336 other = hg.peer(repo, opts, dest)
4337 if 'bookmarks' not in other.listkeys('namespaces'):
4337 if 'bookmarks' not in other.listkeys('namespaces'):
4338 ui.warn(_("remote doesn't support bookmarks\n"))
4338 ui.warn(_("remote doesn't support bookmarks\n"))
4339 return 0
4339 return 0
4340 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4340 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4341 return bookmarks.diff(ui, other, repo)
4341 return bookmarks.diff(ui, other, repo)
4342
4342
4343 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4343 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4344 try:
4344 try:
4345 return hg.outgoing(ui, repo, dest, opts)
4345 return hg.outgoing(ui, repo, dest, opts)
4346 finally:
4346 finally:
4347 del repo._subtoppath
4347 del repo._subtoppath
4348
4348
4349 @command('parents',
4349 @command('parents',
4350 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4350 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4351 ] + templateopts,
4351 ] + templateopts,
4352 _('[-r REV] [FILE]'))
4352 _('[-r REV] [FILE]'))
4353 def parents(ui, repo, file_=None, **opts):
4353 def parents(ui, repo, file_=None, **opts):
4354 """show the parents of the working directory or revision
4354 """show the parents of the working directory or revision
4355
4355
4356 Print the working directory's parent revisions. If a revision is
4356 Print the working directory's parent revisions. If a revision is
4357 given via -r/--rev, the parent of that revision will be printed.
4357 given via -r/--rev, the parent of that revision will be printed.
4358 If a file argument is given, the revision in which the file was
4358 If a file argument is given, the revision in which the file was
4359 last changed (before the working directory revision or the
4359 last changed (before the working directory revision or the
4360 argument to --rev if given) is printed.
4360 argument to --rev if given) is printed.
4361
4361
4362 Returns 0 on success.
4362 Returns 0 on success.
4363 """
4363 """
4364
4364
4365 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4365 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4366
4366
4367 if file_:
4367 if file_:
4368 m = scmutil.match(ctx, (file_,), opts)
4368 m = scmutil.match(ctx, (file_,), opts)
4369 if m.anypats() or len(m.files()) != 1:
4369 if m.anypats() or len(m.files()) != 1:
4370 raise util.Abort(_('can only specify an explicit filename'))
4370 raise util.Abort(_('can only specify an explicit filename'))
4371 file_ = m.files()[0]
4371 file_ = m.files()[0]
4372 filenodes = []
4372 filenodes = []
4373 for cp in ctx.parents():
4373 for cp in ctx.parents():
4374 if not cp:
4374 if not cp:
4375 continue
4375 continue
4376 try:
4376 try:
4377 filenodes.append(cp.filenode(file_))
4377 filenodes.append(cp.filenode(file_))
4378 except error.LookupError:
4378 except error.LookupError:
4379 pass
4379 pass
4380 if not filenodes:
4380 if not filenodes:
4381 raise util.Abort(_("'%s' not found in manifest!") % file_)
4381 raise util.Abort(_("'%s' not found in manifest!") % file_)
4382 p = []
4382 p = []
4383 for fn in filenodes:
4383 for fn in filenodes:
4384 fctx = repo.filectx(file_, fileid=fn)
4384 fctx = repo.filectx(file_, fileid=fn)
4385 p.append(fctx.node())
4385 p.append(fctx.node())
4386 else:
4386 else:
4387 p = [cp.node() for cp in ctx.parents()]
4387 p = [cp.node() for cp in ctx.parents()]
4388
4388
4389 displayer = cmdutil.show_changeset(ui, repo, opts)
4389 displayer = cmdutil.show_changeset(ui, repo, opts)
4390 for n in p:
4390 for n in p:
4391 if n != nullid:
4391 if n != nullid:
4392 displayer.show(repo[n])
4392 displayer.show(repo[n])
4393 displayer.close()
4393 displayer.close()
4394
4394
4395 @command('paths', [], _('[NAME]'))
4395 @command('paths', [], _('[NAME]'))
4396 def paths(ui, repo, search=None):
4396 def paths(ui, repo, search=None):
4397 """show aliases for remote repositories
4397 """show aliases for remote repositories
4398
4398
4399 Show definition of symbolic path name NAME. If no name is given,
4399 Show definition of symbolic path name NAME. If no name is given,
4400 show definition of all available names.
4400 show definition of all available names.
4401
4401
4402 Option -q/--quiet suppresses all output when searching for NAME
4402 Option -q/--quiet suppresses all output when searching for NAME
4403 and shows only the path names when listing all definitions.
4403 and shows only the path names when listing all definitions.
4404
4404
4405 Path names are defined in the [paths] section of your
4405 Path names are defined in the [paths] section of your
4406 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4406 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4407 repository, ``.hg/hgrc`` is used, too.
4407 repository, ``.hg/hgrc`` is used, too.
4408
4408
4409 The path names ``default`` and ``default-push`` have a special
4409 The path names ``default`` and ``default-push`` have a special
4410 meaning. When performing a push or pull operation, they are used
4410 meaning. When performing a push or pull operation, they are used
4411 as fallbacks if no location is specified on the command-line.
4411 as fallbacks if no location is specified on the command-line.
4412 When ``default-push`` is set, it will be used for push and
4412 When ``default-push`` is set, it will be used for push and
4413 ``default`` will be used for pull; otherwise ``default`` is used
4413 ``default`` will be used for pull; otherwise ``default`` is used
4414 as the fallback for both. When cloning a repository, the clone
4414 as the fallback for both. When cloning a repository, the clone
4415 source is written as ``default`` in ``.hg/hgrc``. Note that
4415 source is written as ``default`` in ``.hg/hgrc``. Note that
4416 ``default`` and ``default-push`` apply to all inbound (e.g.
4416 ``default`` and ``default-push`` apply to all inbound (e.g.
4417 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4417 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4418 :hg:`bundle`) operations.
4418 :hg:`bundle`) operations.
4419
4419
4420 See :hg:`help urls` for more information.
4420 See :hg:`help urls` for more information.
4421
4421
4422 Returns 0 on success.
4422 Returns 0 on success.
4423 """
4423 """
4424 if search:
4424 if search:
4425 for name, path in ui.configitems("paths"):
4425 for name, path in ui.configitems("paths"):
4426 if name == search:
4426 if name == search:
4427 ui.status("%s\n" % util.hidepassword(path))
4427 ui.status("%s\n" % util.hidepassword(path))
4428 return
4428 return
4429 if not ui.quiet:
4429 if not ui.quiet:
4430 ui.warn(_("not found!\n"))
4430 ui.warn(_("not found!\n"))
4431 return 1
4431 return 1
4432 else:
4432 else:
4433 for name, path in ui.configitems("paths"):
4433 for name, path in ui.configitems("paths"):
4434 if ui.quiet:
4434 if ui.quiet:
4435 ui.write("%s\n" % name)
4435 ui.write("%s\n" % name)
4436 else:
4436 else:
4437 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4437 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4438
4438
4439 @command('phase',
4439 @command('phase',
4440 [('p', 'public', False, _('set changeset phase to public')),
4440 [('p', 'public', False, _('set changeset phase to public')),
4441 ('d', 'draft', False, _('set changeset phase to draft')),
4441 ('d', 'draft', False, _('set changeset phase to draft')),
4442 ('s', 'secret', False, _('set changeset phase to secret')),
4442 ('s', 'secret', False, _('set changeset phase to secret')),
4443 ('f', 'force', False, _('allow to move boundary backward')),
4443 ('f', 'force', False, _('allow to move boundary backward')),
4444 ('r', 'rev', [], _('target revision'), _('REV')),
4444 ('r', 'rev', [], _('target revision'), _('REV')),
4445 ],
4445 ],
4446 _('[-p|-d|-s] [-f] [-r] REV...'))
4446 _('[-p|-d|-s] [-f] [-r] REV...'))
4447 def phase(ui, repo, *revs, **opts):
4447 def phase(ui, repo, *revs, **opts):
4448 """set or show the current phase name
4448 """set or show the current phase name
4449
4449
4450 With no argument, show the phase name of specified revisions.
4450 With no argument, show the phase name of specified revisions.
4451
4451
4452 With one of -p/--public, -d/--draft or -s/--secret, change the
4452 With one of -p/--public, -d/--draft or -s/--secret, change the
4453 phase value of the specified revisions.
4453 phase value of the specified revisions.
4454
4454
4455 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4455 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4456 lower phase to an higher phase. Phases are ordered as follows::
4456 lower phase to an higher phase. Phases are ordered as follows::
4457
4457
4458 public < draft < secret
4458 public < draft < secret
4459
4459
4460 Return 0 on success, 1 if no phases were changed or some could not
4460 Return 0 on success, 1 if no phases were changed or some could not
4461 be changed.
4461 be changed.
4462 """
4462 """
4463 # search for a unique phase argument
4463 # search for a unique phase argument
4464 targetphase = None
4464 targetphase = None
4465 for idx, name in enumerate(phases.phasenames):
4465 for idx, name in enumerate(phases.phasenames):
4466 if opts[name]:
4466 if opts[name]:
4467 if targetphase is not None:
4467 if targetphase is not None:
4468 raise util.Abort(_('only one phase can be specified'))
4468 raise util.Abort(_('only one phase can be specified'))
4469 targetphase = idx
4469 targetphase = idx
4470
4470
4471 # look for specified revision
4471 # look for specified revision
4472 revs = list(revs)
4472 revs = list(revs)
4473 revs.extend(opts['rev'])
4473 revs.extend(opts['rev'])
4474 if not revs:
4474 if not revs:
4475 raise util.Abort(_('no revisions specified'))
4475 raise util.Abort(_('no revisions specified'))
4476
4476
4477 revs = scmutil.revrange(repo, revs)
4477 revs = scmutil.revrange(repo, revs)
4478
4478
4479 lock = None
4479 lock = None
4480 ret = 0
4480 ret = 0
4481 if targetphase is None:
4481 if targetphase is None:
4482 # display
4482 # display
4483 for r in revs:
4483 for r in revs:
4484 ctx = repo[r]
4484 ctx = repo[r]
4485 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4485 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4486 else:
4486 else:
4487 lock = repo.lock()
4487 lock = repo.lock()
4488 try:
4488 try:
4489 # set phase
4489 # set phase
4490 if not revs:
4490 if not revs:
4491 raise util.Abort(_('empty revision set'))
4491 raise util.Abort(_('empty revision set'))
4492 nodes = [repo[r].node() for r in revs]
4492 nodes = [repo[r].node() for r in revs]
4493 olddata = repo._phasecache.getphaserevs(repo)[:]
4493 olddata = repo._phasecache.getphaserevs(repo)[:]
4494 phases.advanceboundary(repo, targetphase, nodes)
4494 phases.advanceboundary(repo, targetphase, nodes)
4495 if opts['force']:
4495 if opts['force']:
4496 phases.retractboundary(repo, targetphase, nodes)
4496 phases.retractboundary(repo, targetphase, nodes)
4497 finally:
4497 finally:
4498 lock.release()
4498 lock.release()
4499 # moving revision from public to draft may hide them
4499 # moving revision from public to draft may hide them
4500 # We have to check result on an unfiltered repository
4500 # We have to check result on an unfiltered repository
4501 unfi = repo.unfiltered()
4501 unfi = repo.unfiltered()
4502 newdata = repo._phasecache.getphaserevs(unfi)
4502 newdata = repo._phasecache.getphaserevs(unfi)
4503 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4503 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4504 cl = unfi.changelog
4504 cl = unfi.changelog
4505 rejected = [n for n in nodes
4505 rejected = [n for n in nodes
4506 if newdata[cl.rev(n)] < targetphase]
4506 if newdata[cl.rev(n)] < targetphase]
4507 if rejected:
4507 if rejected:
4508 ui.warn(_('cannot move %i changesets to a more permissive '
4508 ui.warn(_('cannot move %i changesets to a more permissive '
4509 'phase, use --force\n') % len(rejected))
4509 'phase, use --force\n') % len(rejected))
4510 ret = 1
4510 ret = 1
4511 if changes:
4511 if changes:
4512 msg = _('phase changed for %i changesets\n') % changes
4512 msg = _('phase changed for %i changesets\n') % changes
4513 if ret:
4513 if ret:
4514 ui.status(msg)
4514 ui.status(msg)
4515 else:
4515 else:
4516 ui.note(msg)
4516 ui.note(msg)
4517 else:
4517 else:
4518 ui.warn(_('no phases changed\n'))
4518 ui.warn(_('no phases changed\n'))
4519 ret = 1
4519 ret = 1
4520 return ret
4520 return ret
4521
4521
4522 def postincoming(ui, repo, modheads, optupdate, checkout):
4522 def postincoming(ui, repo, modheads, optupdate, checkout):
4523 if modheads == 0:
4523 if modheads == 0:
4524 return
4524 return
4525 if optupdate:
4525 if optupdate:
4526 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4526 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4527 try:
4527 try:
4528 ret = hg.update(repo, checkout)
4528 ret = hg.update(repo, checkout)
4529 except util.Abort, inst:
4529 except util.Abort, inst:
4530 ui.warn(_("not updating: %s\n") % str(inst))
4530 ui.warn(_("not updating: %s\n") % str(inst))
4531 if inst.hint:
4531 if inst.hint:
4532 ui.warn(_("(%s)\n") % inst.hint)
4532 ui.warn(_("(%s)\n") % inst.hint)
4533 return 0
4533 return 0
4534 if not ret and not checkout:
4534 if not ret and not checkout:
4535 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4535 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4536 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4536 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4537 return ret
4537 return ret
4538 if modheads > 1:
4538 if modheads > 1:
4539 currentbranchheads = len(repo.branchheads())
4539 currentbranchheads = len(repo.branchheads())
4540 if currentbranchheads == modheads:
4540 if currentbranchheads == modheads:
4541 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4541 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4542 elif currentbranchheads > 1:
4542 elif currentbranchheads > 1:
4543 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4543 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4544 "merge)\n"))
4544 "merge)\n"))
4545 else:
4545 else:
4546 ui.status(_("(run 'hg heads' to see heads)\n"))
4546 ui.status(_("(run 'hg heads' to see heads)\n"))
4547 else:
4547 else:
4548 ui.status(_("(run 'hg update' to get a working copy)\n"))
4548 ui.status(_("(run 'hg update' to get a working copy)\n"))
4549
4549
4550 @command('^pull',
4550 @command('^pull',
4551 [('u', 'update', None,
4551 [('u', 'update', None,
4552 _('update to new branch head if changesets were pulled')),
4552 _('update to new branch head if changesets were pulled')),
4553 ('f', 'force', None, _('run even when remote repository is unrelated')),
4553 ('f', 'force', None, _('run even when remote repository is unrelated')),
4554 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4554 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4555 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4555 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4556 ('b', 'branch', [], _('a specific branch you would like to pull'),
4556 ('b', 'branch', [], _('a specific branch you would like to pull'),
4557 _('BRANCH')),
4557 _('BRANCH')),
4558 ] + remoteopts,
4558 ] + remoteopts,
4559 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4559 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4560 def pull(ui, repo, source="default", **opts):
4560 def pull(ui, repo, source="default", **opts):
4561 """pull changes from the specified source
4561 """pull changes from the specified source
4562
4562
4563 Pull changes from a remote repository to a local one.
4563 Pull changes from a remote repository to a local one.
4564
4564
4565 This finds all changes from the repository at the specified path
4565 This finds all changes from the repository at the specified path
4566 or URL and adds them to a local repository (the current one unless
4566 or URL and adds them to a local repository (the current one unless
4567 -R is specified). By default, this does not update the copy of the
4567 -R is specified). By default, this does not update the copy of the
4568 project in the working directory.
4568 project in the working directory.
4569
4569
4570 Use :hg:`incoming` if you want to see what would have been added
4570 Use :hg:`incoming` if you want to see what would have been added
4571 by a pull at the time you issued this command. If you then decide
4571 by a pull at the time you issued this command. If you then decide
4572 to add those changes to the repository, you should use :hg:`pull
4572 to add those changes to the repository, you should use :hg:`pull
4573 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4573 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4574
4574
4575 If SOURCE is omitted, the 'default' path will be used.
4575 If SOURCE is omitted, the 'default' path will be used.
4576 See :hg:`help urls` for more information.
4576 See :hg:`help urls` for more information.
4577
4577
4578 Returns 0 on success, 1 if an update had unresolved files.
4578 Returns 0 on success, 1 if an update had unresolved files.
4579 """
4579 """
4580 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4580 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4581 other = hg.peer(repo, opts, source)
4581 other = hg.peer(repo, opts, source)
4582 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4582 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4583 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4583 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4584
4584
4585 remotebookmarks = other.listkeys('bookmarks')
4585 remotebookmarks = other.listkeys('bookmarks')
4586
4586
4587 if opts.get('bookmark'):
4587 if opts.get('bookmark'):
4588 if not revs:
4588 if not revs:
4589 revs = []
4589 revs = []
4590 for b in opts['bookmark']:
4590 for b in opts['bookmark']:
4591 if b not in remotebookmarks:
4591 if b not in remotebookmarks:
4592 raise util.Abort(_('remote bookmark %s not found!') % b)
4592 raise util.Abort(_('remote bookmark %s not found!') % b)
4593 revs.append(remotebookmarks[b])
4593 revs.append(remotebookmarks[b])
4594
4594
4595 if revs:
4595 if revs:
4596 try:
4596 try:
4597 revs = [other.lookup(rev) for rev in revs]
4597 revs = [other.lookup(rev) for rev in revs]
4598 except error.CapabilityError:
4598 except error.CapabilityError:
4599 err = _("other repository doesn't support revision lookup, "
4599 err = _("other repository doesn't support revision lookup, "
4600 "so a rev cannot be specified.")
4600 "so a rev cannot be specified.")
4601 raise util.Abort(err)
4601 raise util.Abort(err)
4602
4602
4603 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4603 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4604 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4604 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4605 if checkout:
4605 if checkout:
4606 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4606 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4607 repo._subtoppath = source
4607 repo._subtoppath = source
4608 try:
4608 try:
4609 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4609 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4610
4610
4611 finally:
4611 finally:
4612 del repo._subtoppath
4612 del repo._subtoppath
4613
4613
4614 # update specified bookmarks
4614 # update specified bookmarks
4615 if opts.get('bookmark'):
4615 if opts.get('bookmark'):
4616 marks = repo._bookmarks
4616 marks = repo._bookmarks
4617 for b in opts['bookmark']:
4617 for b in opts['bookmark']:
4618 # explicit pull overrides local bookmark if any
4618 # explicit pull overrides local bookmark if any
4619 ui.status(_("importing bookmark %s\n") % b)
4619 ui.status(_("importing bookmark %s\n") % b)
4620 marks[b] = repo[remotebookmarks[b]].node()
4620 marks[b] = repo[remotebookmarks[b]].node()
4621 marks.write()
4621 marks.write()
4622
4622
4623 return ret
4623 return ret
4624
4624
4625 @command('^push',
4625 @command('^push',
4626 [('f', 'force', None, _('force push')),
4626 [('f', 'force', None, _('force push')),
4627 ('r', 'rev', [],
4627 ('r', 'rev', [],
4628 _('a changeset intended to be included in the destination'),
4628 _('a changeset intended to be included in the destination'),
4629 _('REV')),
4629 _('REV')),
4630 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4630 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4631 ('b', 'branch', [],
4631 ('b', 'branch', [],
4632 _('a specific branch you would like to push'), _('BRANCH')),
4632 _('a specific branch you would like to push'), _('BRANCH')),
4633 ('', 'new-branch', False, _('allow pushing a new branch')),
4633 ('', 'new-branch', False, _('allow pushing a new branch')),
4634 ] + remoteopts,
4634 ] + remoteopts,
4635 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4635 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4636 def push(ui, repo, dest=None, **opts):
4636 def push(ui, repo, dest=None, **opts):
4637 """push changes to the specified destination
4637 """push changes to the specified destination
4638
4638
4639 Push changesets from the local repository to the specified
4639 Push changesets from the local repository to the specified
4640 destination.
4640 destination.
4641
4641
4642 This operation is symmetrical to pull: it is identical to a pull
4642 This operation is symmetrical to pull: it is identical to a pull
4643 in the destination repository from the current one.
4643 in the destination repository from the current one.
4644
4644
4645 By default, push will not allow creation of new heads at the
4645 By default, push will not allow creation of new heads at the
4646 destination, since multiple heads would make it unclear which head
4646 destination, since multiple heads would make it unclear which head
4647 to use. In this situation, it is recommended to pull and merge
4647 to use. In this situation, it is recommended to pull and merge
4648 before pushing.
4648 before pushing.
4649
4649
4650 Use --new-branch if you want to allow push to create a new named
4650 Use --new-branch if you want to allow push to create a new named
4651 branch that is not present at the destination. This allows you to
4651 branch that is not present at the destination. This allows you to
4652 only create a new branch without forcing other changes.
4652 only create a new branch without forcing other changes.
4653
4653
4654 .. note::
4654 .. note::
4655 Extra care should be taken with the -f/--force option,
4655 Extra care should be taken with the -f/--force option,
4656 which will push all new heads on all branches, an action which will
4656 which will push all new heads on all branches, an action which will
4657 almost always cause confusion for collaborators.
4657 almost always cause confusion for collaborators.
4658
4658
4659 If -r/--rev is used, the specified revision and all its ancestors
4659 If -r/--rev is used, the specified revision and all its ancestors
4660 will be pushed to the remote repository.
4660 will be pushed to the remote repository.
4661
4661
4662 If -B/--bookmark is used, the specified bookmarked revision, its
4662 If -B/--bookmark is used, the specified bookmarked revision, its
4663 ancestors, and the bookmark will be pushed to the remote
4663 ancestors, and the bookmark will be pushed to the remote
4664 repository.
4664 repository.
4665
4665
4666 Please see :hg:`help urls` for important details about ``ssh://``
4666 Please see :hg:`help urls` for important details about ``ssh://``
4667 URLs. If DESTINATION is omitted, a default path will be used.
4667 URLs. If DESTINATION is omitted, a default path will be used.
4668
4668
4669 Returns 0 if push was successful, 1 if nothing to push.
4669 Returns 0 if push was successful, 1 if nothing to push.
4670 """
4670 """
4671
4671
4672 if opts.get('bookmark'):
4672 if opts.get('bookmark'):
4673 for b in opts['bookmark']:
4673 for b in opts['bookmark']:
4674 # translate -B options to -r so changesets get pushed
4674 # translate -B options to -r so changesets get pushed
4675 if b in repo._bookmarks:
4675 if b in repo._bookmarks:
4676 opts.setdefault('rev', []).append(b)
4676 opts.setdefault('rev', []).append(b)
4677 else:
4677 else:
4678 # if we try to push a deleted bookmark, translate it to null
4678 # if we try to push a deleted bookmark, translate it to null
4679 # this lets simultaneous -r, -b options continue working
4679 # this lets simultaneous -r, -b options continue working
4680 opts.setdefault('rev', []).append("null")
4680 opts.setdefault('rev', []).append("null")
4681
4681
4682 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4682 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4683 dest, branches = hg.parseurl(dest, opts.get('branch'))
4683 dest, branches = hg.parseurl(dest, opts.get('branch'))
4684 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4684 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4685 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4685 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4686 other = hg.peer(repo, opts, dest)
4686 other = hg.peer(repo, opts, dest)
4687 if revs:
4687 if revs:
4688 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4688 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4689
4689
4690 repo._subtoppath = dest
4690 repo._subtoppath = dest
4691 try:
4691 try:
4692 # push subrepos depth-first for coherent ordering
4692 # push subrepos depth-first for coherent ordering
4693 c = repo['']
4693 c = repo['']
4694 subs = c.substate # only repos that are committed
4694 subs = c.substate # only repos that are committed
4695 for s in sorted(subs):
4695 for s in sorted(subs):
4696 if c.sub(s).push(opts) == 0:
4696 if c.sub(s).push(opts) == 0:
4697 return False
4697 return False
4698 finally:
4698 finally:
4699 del repo._subtoppath
4699 del repo._subtoppath
4700 result = repo.push(other, opts.get('force'), revs=revs,
4700 result = repo.push(other, opts.get('force'), revs=revs,
4701 newbranch=opts.get('new_branch'))
4701 newbranch=opts.get('new_branch'))
4702
4702
4703 result = not result
4703 result = not result
4704
4704
4705 if opts.get('bookmark'):
4705 if opts.get('bookmark'):
4706 rb = other.listkeys('bookmarks')
4706 rb = other.listkeys('bookmarks')
4707 for b in opts['bookmark']:
4707 for b in opts['bookmark']:
4708 # explicit push overrides remote bookmark if any
4708 # explicit push overrides remote bookmark if any
4709 if b in repo._bookmarks:
4709 if b in repo._bookmarks:
4710 ui.status(_("exporting bookmark %s\n") % b)
4710 ui.status(_("exporting bookmark %s\n") % b)
4711 new = repo[b].hex()
4711 new = repo[b].hex()
4712 elif b in rb:
4712 elif b in rb:
4713 ui.status(_("deleting remote bookmark %s\n") % b)
4713 ui.status(_("deleting remote bookmark %s\n") % b)
4714 new = '' # delete
4714 new = '' # delete
4715 else:
4715 else:
4716 ui.warn(_('bookmark %s does not exist on the local '
4716 ui.warn(_('bookmark %s does not exist on the local '
4717 'or remote repository!\n') % b)
4717 'or remote repository!\n') % b)
4718 return 2
4718 return 2
4719 old = rb.get(b, '')
4719 old = rb.get(b, '')
4720 r = other.pushkey('bookmarks', b, old, new)
4720 r = other.pushkey('bookmarks', b, old, new)
4721 if not r:
4721 if not r:
4722 ui.warn(_('updating bookmark %s failed!\n') % b)
4722 ui.warn(_('updating bookmark %s failed!\n') % b)
4723 if not result:
4723 if not result:
4724 result = 2
4724 result = 2
4725
4725
4726 return result
4726 return result
4727
4727
4728 @command('recover', [])
4728 @command('recover', [])
4729 def recover(ui, repo):
4729 def recover(ui, repo):
4730 """roll back an interrupted transaction
4730 """roll back an interrupted transaction
4731
4731
4732 Recover from an interrupted commit or pull.
4732 Recover from an interrupted commit or pull.
4733
4733
4734 This command tries to fix the repository status after an
4734 This command tries to fix the repository status after an
4735 interrupted operation. It should only be necessary when Mercurial
4735 interrupted operation. It should only be necessary when Mercurial
4736 suggests it.
4736 suggests it.
4737
4737
4738 Returns 0 if successful, 1 if nothing to recover or verify fails.
4738 Returns 0 if successful, 1 if nothing to recover or verify fails.
4739 """
4739 """
4740 if repo.recover():
4740 if repo.recover():
4741 return hg.verify(repo)
4741 return hg.verify(repo)
4742 return 1
4742 return 1
4743
4743
4744 @command('^remove|rm',
4744 @command('^remove|rm',
4745 [('A', 'after', None, _('record delete for missing files')),
4745 [('A', 'after', None, _('record delete for missing files')),
4746 ('f', 'force', None,
4746 ('f', 'force', None,
4747 _('remove (and delete) file even if added or modified')),
4747 _('remove (and delete) file even if added or modified')),
4748 ] + walkopts,
4748 ] + walkopts,
4749 _('[OPTION]... FILE...'))
4749 _('[OPTION]... FILE...'))
4750 def remove(ui, repo, *pats, **opts):
4750 def remove(ui, repo, *pats, **opts):
4751 """remove the specified files on the next commit
4751 """remove the specified files on the next commit
4752
4752
4753 Schedule the indicated files for removal from the current branch.
4753 Schedule the indicated files for removal from the current branch.
4754
4754
4755 This command schedules the files to be removed at the next commit.
4755 This command schedules the files to be removed at the next commit.
4756 To undo a remove before that, see :hg:`revert`. To undo added
4756 To undo a remove before that, see :hg:`revert`. To undo added
4757 files, see :hg:`forget`.
4757 files, see :hg:`forget`.
4758
4758
4759 .. container:: verbose
4759 .. container:: verbose
4760
4760
4761 -A/--after can be used to remove only files that have already
4761 -A/--after can be used to remove only files that have already
4762 been deleted, -f/--force can be used to force deletion, and -Af
4762 been deleted, -f/--force can be used to force deletion, and -Af
4763 can be used to remove files from the next revision without
4763 can be used to remove files from the next revision without
4764 deleting them from the working directory.
4764 deleting them from the working directory.
4765
4765
4766 The following table details the behavior of remove for different
4766 The following table details the behavior of remove for different
4767 file states (columns) and option combinations (rows). The file
4767 file states (columns) and option combinations (rows). The file
4768 states are Added [A], Clean [C], Modified [M] and Missing [!]
4768 states are Added [A], Clean [C], Modified [M] and Missing [!]
4769 (as reported by :hg:`status`). The actions are Warn, Remove
4769 (as reported by :hg:`status`). The actions are Warn, Remove
4770 (from branch) and Delete (from disk):
4770 (from branch) and Delete (from disk):
4771
4771
4772 ======= == == == ==
4772 ======= == == == ==
4773 A C M !
4773 A C M !
4774 ======= == == == ==
4774 ======= == == == ==
4775 none W RD W R
4775 none W RD W R
4776 -f R RD RD R
4776 -f R RD RD R
4777 -A W W W R
4777 -A W W W R
4778 -Af R R R R
4778 -Af R R R R
4779 ======= == == == ==
4779 ======= == == == ==
4780
4780
4781 Note that remove never deletes files in Added [A] state from the
4781 Note that remove never deletes files in Added [A] state from the
4782 working directory, not even if option --force is specified.
4782 working directory, not even if option --force is specified.
4783
4783
4784 Returns 0 on success, 1 if any warnings encountered.
4784 Returns 0 on success, 1 if any warnings encountered.
4785 """
4785 """
4786
4786
4787 ret = 0
4787 ret = 0
4788 after, force = opts.get('after'), opts.get('force')
4788 after, force = opts.get('after'), opts.get('force')
4789 if not pats and not after:
4789 if not pats and not after:
4790 raise util.Abort(_('no files specified'))
4790 raise util.Abort(_('no files specified'))
4791
4791
4792 m = scmutil.match(repo[None], pats, opts)
4792 m = scmutil.match(repo[None], pats, opts)
4793 s = repo.status(match=m, clean=True)
4793 s = repo.status(match=m, clean=True)
4794 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4794 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4795
4795
4796 # warn about failure to delete explicit files/dirs
4796 # warn about failure to delete explicit files/dirs
4797 wctx = repo[None]
4797 wctx = repo[None]
4798 for f in m.files():
4798 for f in m.files():
4799 if f in repo.dirstate or f in wctx.dirs():
4799 if f in repo.dirstate or f in wctx.dirs():
4800 continue
4800 continue
4801 if os.path.exists(m.rel(f)):
4801 if os.path.exists(m.rel(f)):
4802 if os.path.isdir(m.rel(f)):
4802 if os.path.isdir(m.rel(f)):
4803 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4803 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4804 else:
4804 else:
4805 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4805 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4806 # missing files will generate a warning elsewhere
4806 # missing files will generate a warning elsewhere
4807 ret = 1
4807 ret = 1
4808
4808
4809 if force:
4809 if force:
4810 list = modified + deleted + clean + added
4810 list = modified + deleted + clean + added
4811 elif after:
4811 elif after:
4812 list = deleted
4812 list = deleted
4813 for f in modified + added + clean:
4813 for f in modified + added + clean:
4814 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4814 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4815 ret = 1
4815 ret = 1
4816 else:
4816 else:
4817 list = deleted + clean
4817 list = deleted + clean
4818 for f in modified:
4818 for f in modified:
4819 ui.warn(_('not removing %s: file is modified (use -f'
4819 ui.warn(_('not removing %s: file is modified (use -f'
4820 ' to force removal)\n') % m.rel(f))
4820 ' to force removal)\n') % m.rel(f))
4821 ret = 1
4821 ret = 1
4822 for f in added:
4822 for f in added:
4823 ui.warn(_('not removing %s: file has been marked for add'
4823 ui.warn(_('not removing %s: file has been marked for add'
4824 ' (use forget to undo)\n') % m.rel(f))
4824 ' (use forget to undo)\n') % m.rel(f))
4825 ret = 1
4825 ret = 1
4826
4826
4827 for f in sorted(list):
4827 for f in sorted(list):
4828 if ui.verbose or not m.exact(f):
4828 if ui.verbose or not m.exact(f):
4829 ui.status(_('removing %s\n') % m.rel(f))
4829 ui.status(_('removing %s\n') % m.rel(f))
4830
4830
4831 wlock = repo.wlock()
4831 wlock = repo.wlock()
4832 try:
4832 try:
4833 if not after:
4833 if not after:
4834 for f in list:
4834 for f in list:
4835 if f in added:
4835 if f in added:
4836 continue # we never unlink added files on remove
4836 continue # we never unlink added files on remove
4837 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4837 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4838 repo[None].forget(list)
4838 repo[None].forget(list)
4839 finally:
4839 finally:
4840 wlock.release()
4840 wlock.release()
4841
4841
4842 return ret
4842 return ret
4843
4843
4844 @command('rename|move|mv',
4844 @command('rename|move|mv',
4845 [('A', 'after', None, _('record a rename that has already occurred')),
4845 [('A', 'after', None, _('record a rename that has already occurred')),
4846 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4846 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4847 ] + walkopts + dryrunopts,
4847 ] + walkopts + dryrunopts,
4848 _('[OPTION]... SOURCE... DEST'))
4848 _('[OPTION]... SOURCE... DEST'))
4849 def rename(ui, repo, *pats, **opts):
4849 def rename(ui, repo, *pats, **opts):
4850 """rename files; equivalent of copy + remove
4850 """rename files; equivalent of copy + remove
4851
4851
4852 Mark dest as copies of sources; mark sources for deletion. If dest
4852 Mark dest as copies of sources; mark sources for deletion. If dest
4853 is a directory, copies are put in that directory. If dest is a
4853 is a directory, copies are put in that directory. If dest is a
4854 file, there can only be one source.
4854 file, there can only be one source.
4855
4855
4856 By default, this command copies the contents of files as they
4856 By default, this command copies the contents of files as they
4857 exist in the working directory. If invoked with -A/--after, the
4857 exist in the working directory. If invoked with -A/--after, the
4858 operation is recorded, but no copying is performed.
4858 operation is recorded, but no copying is performed.
4859
4859
4860 This command takes effect at the next commit. To undo a rename
4860 This command takes effect at the next commit. To undo a rename
4861 before that, see :hg:`revert`.
4861 before that, see :hg:`revert`.
4862
4862
4863 Returns 0 on success, 1 if errors are encountered.
4863 Returns 0 on success, 1 if errors are encountered.
4864 """
4864 """
4865 wlock = repo.wlock(False)
4865 wlock = repo.wlock(False)
4866 try:
4866 try:
4867 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4867 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4868 finally:
4868 finally:
4869 wlock.release()
4869 wlock.release()
4870
4870
4871 @command('resolve',
4871 @command('resolve',
4872 [('a', 'all', None, _('select all unresolved files')),
4872 [('a', 'all', None, _('select all unresolved files')),
4873 ('l', 'list', None, _('list state of files needing merge')),
4873 ('l', 'list', None, _('list state of files needing merge')),
4874 ('m', 'mark', None, _('mark files as resolved')),
4874 ('m', 'mark', None, _('mark files as resolved')),
4875 ('u', 'unmark', None, _('mark files as unresolved')),
4875 ('u', 'unmark', None, _('mark files as unresolved')),
4876 ('n', 'no-status', None, _('hide status prefix'))]
4876 ('n', 'no-status', None, _('hide status prefix'))]
4877 + mergetoolopts + walkopts,
4877 + mergetoolopts + walkopts,
4878 _('[OPTION]... [FILE]...'))
4878 _('[OPTION]... [FILE]...'))
4879 def resolve(ui, repo, *pats, **opts):
4879 def resolve(ui, repo, *pats, **opts):
4880 """redo merges or set/view the merge status of files
4880 """redo merges or set/view the merge status of files
4881
4881
4882 Merges with unresolved conflicts are often the result of
4882 Merges with unresolved conflicts are often the result of
4883 non-interactive merging using the ``internal:merge`` configuration
4883 non-interactive merging using the ``internal:merge`` configuration
4884 setting, or a command-line merge tool like ``diff3``. The resolve
4884 setting, or a command-line merge tool like ``diff3``. The resolve
4885 command is used to manage the files involved in a merge, after
4885 command is used to manage the files involved in a merge, after
4886 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4886 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4887 working directory must have two parents). See :hg:`help
4887 working directory must have two parents). See :hg:`help
4888 merge-tools` for information on configuring merge tools.
4888 merge-tools` for information on configuring merge tools.
4889
4889
4890 The resolve command can be used in the following ways:
4890 The resolve command can be used in the following ways:
4891
4891
4892 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4892 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4893 files, discarding any previous merge attempts. Re-merging is not
4893 files, discarding any previous merge attempts. Re-merging is not
4894 performed for files already marked as resolved. Use ``--all/-a``
4894 performed for files already marked as resolved. Use ``--all/-a``
4895 to select all unresolved files. ``--tool`` can be used to specify
4895 to select all unresolved files. ``--tool`` can be used to specify
4896 the merge tool used for the given files. It overrides the HGMERGE
4896 the merge tool used for the given files. It overrides the HGMERGE
4897 environment variable and your configuration files. Previous file
4897 environment variable and your configuration files. Previous file
4898 contents are saved with a ``.orig`` suffix.
4898 contents are saved with a ``.orig`` suffix.
4899
4899
4900 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4900 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4901 (e.g. after having manually fixed-up the files). The default is
4901 (e.g. after having manually fixed-up the files). The default is
4902 to mark all unresolved files.
4902 to mark all unresolved files.
4903
4903
4904 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4904 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4905 default is to mark all resolved files.
4905 default is to mark all resolved files.
4906
4906
4907 - :hg:`resolve -l`: list files which had or still have conflicts.
4907 - :hg:`resolve -l`: list files which had or still have conflicts.
4908 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4908 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4909
4909
4910 Note that Mercurial will not let you commit files with unresolved
4910 Note that Mercurial will not let you commit files with unresolved
4911 merge conflicts. You must use :hg:`resolve -m ...` before you can
4911 merge conflicts. You must use :hg:`resolve -m ...` before you can
4912 commit after a conflicting merge.
4912 commit after a conflicting merge.
4913
4913
4914 Returns 0 on success, 1 if any files fail a resolve attempt.
4914 Returns 0 on success, 1 if any files fail a resolve attempt.
4915 """
4915 """
4916
4916
4917 all, mark, unmark, show, nostatus = \
4917 all, mark, unmark, show, nostatus = \
4918 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4918 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4919
4919
4920 if (show and (mark or unmark)) or (mark and unmark):
4920 if (show and (mark or unmark)) or (mark and unmark):
4921 raise util.Abort(_("too many options specified"))
4921 raise util.Abort(_("too many options specified"))
4922 if pats and all:
4922 if pats and all:
4923 raise util.Abort(_("can't specify --all and patterns"))
4923 raise util.Abort(_("can't specify --all and patterns"))
4924 if not (all or pats or show or mark or unmark):
4924 if not (all or pats or show or mark or unmark):
4925 raise util.Abort(_('no files or directories specified; '
4925 raise util.Abort(_('no files or directories specified; '
4926 'use --all to remerge all files'))
4926 'use --all to remerge all files'))
4927
4927
4928 ms = mergemod.mergestate(repo)
4928 ms = mergemod.mergestate(repo)
4929 m = scmutil.match(repo[None], pats, opts)
4929 m = scmutil.match(repo[None], pats, opts)
4930 ret = 0
4930 ret = 0
4931
4931
4932 for f in ms:
4932 for f in ms:
4933 if m(f):
4933 if m(f):
4934 if show:
4934 if show:
4935 if nostatus:
4935 if nostatus:
4936 ui.write("%s\n" % f)
4936 ui.write("%s\n" % f)
4937 else:
4937 else:
4938 ui.write("%s %s\n" % (ms[f].upper(), f),
4938 ui.write("%s %s\n" % (ms[f].upper(), f),
4939 label='resolve.' +
4939 label='resolve.' +
4940 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4940 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4941 elif mark:
4941 elif mark:
4942 ms.mark(f, "r")
4942 ms.mark(f, "r")
4943 elif unmark:
4943 elif unmark:
4944 ms.mark(f, "u")
4944 ms.mark(f, "u")
4945 else:
4945 else:
4946 wctx = repo[None]
4946 wctx = repo[None]
4947 mctx = wctx.parents()[-1]
4947 mctx = wctx.parents()[-1]
4948
4948
4949 # backup pre-resolve (merge uses .orig for its own purposes)
4949 # backup pre-resolve (merge uses .orig for its own purposes)
4950 a = repo.wjoin(f)
4950 a = repo.wjoin(f)
4951 util.copyfile(a, a + ".resolve")
4951 util.copyfile(a, a + ".resolve")
4952
4952
4953 try:
4953 try:
4954 # resolve file
4954 # resolve file
4955 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4955 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4956 if ms.resolve(f, wctx, mctx):
4956 if ms.resolve(f, wctx, mctx):
4957 ret = 1
4957 ret = 1
4958 finally:
4958 finally:
4959 ui.setconfig('ui', 'forcemerge', '')
4959 ui.setconfig('ui', 'forcemerge', '')
4960 ms.commit()
4960 ms.commit()
4961
4961
4962 # replace filemerge's .orig file with our resolve file
4962 # replace filemerge's .orig file with our resolve file
4963 util.rename(a + ".resolve", a + ".orig")
4963 util.rename(a + ".resolve", a + ".orig")
4964
4964
4965 ms.commit()
4965 ms.commit()
4966 return ret
4966 return ret
4967
4967
4968 @command('revert',
4968 @command('revert',
4969 [('a', 'all', None, _('revert all changes when no arguments given')),
4969 [('a', 'all', None, _('revert all changes when no arguments given')),
4970 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4970 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4971 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4971 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4972 ('C', 'no-backup', None, _('do not save backup copies of files')),
4972 ('C', 'no-backup', None, _('do not save backup copies of files')),
4973 ] + walkopts + dryrunopts,
4973 ] + walkopts + dryrunopts,
4974 _('[OPTION]... [-r REV] [NAME]...'))
4974 _('[OPTION]... [-r REV] [NAME]...'))
4975 def revert(ui, repo, *pats, **opts):
4975 def revert(ui, repo, *pats, **opts):
4976 """restore files to their checkout state
4976 """restore files to their checkout state
4977
4977
4978 .. note::
4978 .. note::
4979 To check out earlier revisions, you should use :hg:`update REV`.
4979 To check out earlier revisions, you should use :hg:`update REV`.
4980 To cancel an uncommitted merge (and lose your changes),
4980 To cancel an uncommitted merge (and lose your changes),
4981 use :hg:`update --clean .`.
4981 use :hg:`update --clean .`.
4982
4982
4983 With no revision specified, revert the specified files or directories
4983 With no revision specified, revert the specified files or directories
4984 to the contents they had in the parent of the working directory.
4984 to the contents they had in the parent of the working directory.
4985 This restores the contents of files to an unmodified
4985 This restores the contents of files to an unmodified
4986 state and unschedules adds, removes, copies, and renames. If the
4986 state and unschedules adds, removes, copies, and renames. If the
4987 working directory has two parents, you must explicitly specify a
4987 working directory has two parents, you must explicitly specify a
4988 revision.
4988 revision.
4989
4989
4990 Using the -r/--rev or -d/--date options, revert the given files or
4990 Using the -r/--rev or -d/--date options, revert the given files or
4991 directories to their states as of a specific revision. Because
4991 directories to their states as of a specific revision. Because
4992 revert does not change the working directory parents, this will
4992 revert does not change the working directory parents, this will
4993 cause these files to appear modified. This can be helpful to "back
4993 cause these files to appear modified. This can be helpful to "back
4994 out" some or all of an earlier change. See :hg:`backout` for a
4994 out" some or all of an earlier change. See :hg:`backout` for a
4995 related method.
4995 related method.
4996
4996
4997 Modified files are saved with a .orig suffix before reverting.
4997 Modified files are saved with a .orig suffix before reverting.
4998 To disable these backups, use --no-backup.
4998 To disable these backups, use --no-backup.
4999
4999
5000 See :hg:`help dates` for a list of formats valid for -d/--date.
5000 See :hg:`help dates` for a list of formats valid for -d/--date.
5001
5001
5002 Returns 0 on success.
5002 Returns 0 on success.
5003 """
5003 """
5004
5004
5005 if opts.get("date"):
5005 if opts.get("date"):
5006 if opts.get("rev"):
5006 if opts.get("rev"):
5007 raise util.Abort(_("you can't specify a revision and a date"))
5007 raise util.Abort(_("you can't specify a revision and a date"))
5008 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5008 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5009
5009
5010 parent, p2 = repo.dirstate.parents()
5010 parent, p2 = repo.dirstate.parents()
5011 if not opts.get('rev') and p2 != nullid:
5011 if not opts.get('rev') and p2 != nullid:
5012 # revert after merge is a trap for new users (issue2915)
5012 # revert after merge is a trap for new users (issue2915)
5013 raise util.Abort(_('uncommitted merge with no revision specified'),
5013 raise util.Abort(_('uncommitted merge with no revision specified'),
5014 hint=_('use "hg update" or see "hg help revert"'))
5014 hint=_('use "hg update" or see "hg help revert"'))
5015
5015
5016 ctx = scmutil.revsingle(repo, opts.get('rev'))
5016 ctx = scmutil.revsingle(repo, opts.get('rev'))
5017
5017
5018 if not pats and not opts.get('all'):
5018 if not pats and not opts.get('all'):
5019 msg = _("no files or directories specified")
5019 msg = _("no files or directories specified")
5020 if p2 != nullid:
5020 if p2 != nullid:
5021 hint = _("uncommitted merge, use --all to discard all changes,"
5021 hint = _("uncommitted merge, use --all to discard all changes,"
5022 " or 'hg update -C .' to abort the merge")
5022 " or 'hg update -C .' to abort the merge")
5023 raise util.Abort(msg, hint=hint)
5023 raise util.Abort(msg, hint=hint)
5024 dirty = util.any(repo.status())
5024 dirty = util.any(repo.status())
5025 node = ctx.node()
5025 node = ctx.node()
5026 if node != parent:
5026 if node != parent:
5027 if dirty:
5027 if dirty:
5028 hint = _("uncommitted changes, use --all to discard all"
5028 hint = _("uncommitted changes, use --all to discard all"
5029 " changes, or 'hg update %s' to update") % ctx.rev()
5029 " changes, or 'hg update %s' to update") % ctx.rev()
5030 else:
5030 else:
5031 hint = _("use --all to revert all files,"
5031 hint = _("use --all to revert all files,"
5032 " or 'hg update %s' to update") % ctx.rev()
5032 " or 'hg update %s' to update") % ctx.rev()
5033 elif dirty:
5033 elif dirty:
5034 hint = _("uncommitted changes, use --all to discard all changes")
5034 hint = _("uncommitted changes, use --all to discard all changes")
5035 else:
5035 else:
5036 hint = _("use --all to revert all files")
5036 hint = _("use --all to revert all files")
5037 raise util.Abort(msg, hint=hint)
5037 raise util.Abort(msg, hint=hint)
5038
5038
5039 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5039 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5040
5040
5041 @command('rollback', dryrunopts +
5041 @command('rollback', dryrunopts +
5042 [('f', 'force', False, _('ignore safety measures'))])
5042 [('f', 'force', False, _('ignore safety measures'))])
5043 def rollback(ui, repo, **opts):
5043 def rollback(ui, repo, **opts):
5044 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5044 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5045
5045
5046 Please use :hg:`commit --amend` instead of rollback to correct
5046 Please use :hg:`commit --amend` instead of rollback to correct
5047 mistakes in the last commit.
5047 mistakes in the last commit.
5048
5048
5049 This command should be used with care. There is only one level of
5049 This command should be used with care. There is only one level of
5050 rollback, and there is no way to undo a rollback. It will also
5050 rollback, and there is no way to undo a rollback. It will also
5051 restore the dirstate at the time of the last transaction, losing
5051 restore the dirstate at the time of the last transaction, losing
5052 any dirstate changes since that time. This command does not alter
5052 any dirstate changes since that time. This command does not alter
5053 the working directory.
5053 the working directory.
5054
5054
5055 Transactions are used to encapsulate the effects of all commands
5055 Transactions are used to encapsulate the effects of all commands
5056 that create new changesets or propagate existing changesets into a
5056 that create new changesets or propagate existing changesets into a
5057 repository.
5057 repository.
5058
5058
5059 .. container:: verbose
5059 .. container:: verbose
5060
5060
5061 For example, the following commands are transactional, and their
5061 For example, the following commands are transactional, and their
5062 effects can be rolled back:
5062 effects can be rolled back:
5063
5063
5064 - commit
5064 - commit
5065 - import
5065 - import
5066 - pull
5066 - pull
5067 - push (with this repository as the destination)
5067 - push (with this repository as the destination)
5068 - unbundle
5068 - unbundle
5069
5069
5070 To avoid permanent data loss, rollback will refuse to rollback a
5070 To avoid permanent data loss, rollback will refuse to rollback a
5071 commit transaction if it isn't checked out. Use --force to
5071 commit transaction if it isn't checked out. Use --force to
5072 override this protection.
5072 override this protection.
5073
5073
5074 This command is not intended for use on public repositories. Once
5074 This command is not intended for use on public repositories. Once
5075 changes are visible for pull by other users, rolling a transaction
5075 changes are visible for pull by other users, rolling a transaction
5076 back locally is ineffective (someone else may already have pulled
5076 back locally is ineffective (someone else may already have pulled
5077 the changes). Furthermore, a race is possible with readers of the
5077 the changes). Furthermore, a race is possible with readers of the
5078 repository; for example an in-progress pull from the repository
5078 repository; for example an in-progress pull from the repository
5079 may fail if a rollback is performed.
5079 may fail if a rollback is performed.
5080
5080
5081 Returns 0 on success, 1 if no rollback data is available.
5081 Returns 0 on success, 1 if no rollback data is available.
5082 """
5082 """
5083 return repo.rollback(dryrun=opts.get('dry_run'),
5083 return repo.rollback(dryrun=opts.get('dry_run'),
5084 force=opts.get('force'))
5084 force=opts.get('force'))
5085
5085
5086 @command('root', [])
5086 @command('root', [])
5087 def root(ui, repo):
5087 def root(ui, repo):
5088 """print the root (top) of the current working directory
5088 """print the root (top) of the current working directory
5089
5089
5090 Print the root directory of the current repository.
5090 Print the root directory of the current repository.
5091
5091
5092 Returns 0 on success.
5092 Returns 0 on success.
5093 """
5093 """
5094 ui.write(repo.root + "\n")
5094 ui.write(repo.root + "\n")
5095
5095
5096 @command('^serve',
5096 @command('^serve',
5097 [('A', 'accesslog', '', _('name of access log file to write to'),
5097 [('A', 'accesslog', '', _('name of access log file to write to'),
5098 _('FILE')),
5098 _('FILE')),
5099 ('d', 'daemon', None, _('run server in background')),
5099 ('d', 'daemon', None, _('run server in background')),
5100 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5100 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5101 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5101 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5102 # use string type, then we can check if something was passed
5102 # use string type, then we can check if something was passed
5103 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5103 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5104 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5104 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5105 _('ADDR')),
5105 _('ADDR')),
5106 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5106 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5107 _('PREFIX')),
5107 _('PREFIX')),
5108 ('n', 'name', '',
5108 ('n', 'name', '',
5109 _('name to show in web pages (default: working directory)'), _('NAME')),
5109 _('name to show in web pages (default: working directory)'), _('NAME')),
5110 ('', 'web-conf', '',
5110 ('', 'web-conf', '',
5111 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5111 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5112 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5112 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5113 _('FILE')),
5113 _('FILE')),
5114 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5114 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5115 ('', 'stdio', None, _('for remote clients')),
5115 ('', 'stdio', None, _('for remote clients')),
5116 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5116 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5117 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5117 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5118 ('', 'style', '', _('template style to use'), _('STYLE')),
5118 ('', 'style', '', _('template style to use'), _('STYLE')),
5119 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5119 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5120 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5120 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5121 _('[OPTION]...'))
5121 _('[OPTION]...'))
5122 def serve(ui, repo, **opts):
5122 def serve(ui, repo, **opts):
5123 """start stand-alone webserver
5123 """start stand-alone webserver
5124
5124
5125 Start a local HTTP repository browser and pull server. You can use
5125 Start a local HTTP repository browser and pull server. You can use
5126 this for ad-hoc sharing and browsing of repositories. It is
5126 this for ad-hoc sharing and browsing of repositories. It is
5127 recommended to use a real web server to serve a repository for
5127 recommended to use a real web server to serve a repository for
5128 longer periods of time.
5128 longer periods of time.
5129
5129
5130 Please note that the server does not implement access control.
5130 Please note that the server does not implement access control.
5131 This means that, by default, anybody can read from the server and
5131 This means that, by default, anybody can read from the server and
5132 nobody can write to it by default. Set the ``web.allow_push``
5132 nobody can write to it by default. Set the ``web.allow_push``
5133 option to ``*`` to allow everybody to push to the server. You
5133 option to ``*`` to allow everybody to push to the server. You
5134 should use a real web server if you need to authenticate users.
5134 should use a real web server if you need to authenticate users.
5135
5135
5136 By default, the server logs accesses to stdout and errors to
5136 By default, the server logs accesses to stdout and errors to
5137 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5137 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5138 files.
5138 files.
5139
5139
5140 To have the server choose a free port number to listen on, specify
5140 To have the server choose a free port number to listen on, specify
5141 a port number of 0; in this case, the server will print the port
5141 a port number of 0; in this case, the server will print the port
5142 number it uses.
5142 number it uses.
5143
5143
5144 Returns 0 on success.
5144 Returns 0 on success.
5145 """
5145 """
5146
5146
5147 if opts["stdio"] and opts["cmdserver"]:
5147 if opts["stdio"] and opts["cmdserver"]:
5148 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5148 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5149
5149
5150 def checkrepo():
5150 def checkrepo():
5151 if repo is None:
5151 if repo is None:
5152 raise error.RepoError(_("there is no Mercurial repository here"
5152 raise error.RepoError(_("there is no Mercurial repository here"
5153 " (.hg not found)"))
5153 " (.hg not found)"))
5154
5154
5155 if opts["stdio"]:
5155 if opts["stdio"]:
5156 checkrepo()
5156 checkrepo()
5157 s = sshserver.sshserver(ui, repo)
5157 s = sshserver.sshserver(ui, repo)
5158 s.serve_forever()
5158 s.serve_forever()
5159
5159
5160 if opts["cmdserver"]:
5160 if opts["cmdserver"]:
5161 checkrepo()
5161 checkrepo()
5162 s = commandserver.server(ui, repo, opts["cmdserver"])
5162 s = commandserver.server(ui, repo, opts["cmdserver"])
5163 return s.serve()
5163 return s.serve()
5164
5164
5165 # this way we can check if something was given in the command-line
5165 # this way we can check if something was given in the command-line
5166 if opts.get('port'):
5166 if opts.get('port'):
5167 opts['port'] = util.getport(opts.get('port'))
5167 opts['port'] = util.getport(opts.get('port'))
5168
5168
5169 baseui = repo and repo.baseui or ui
5169 baseui = repo and repo.baseui or ui
5170 optlist = ("name templates style address port prefix ipv6"
5170 optlist = ("name templates style address port prefix ipv6"
5171 " accesslog errorlog certificate encoding")
5171 " accesslog errorlog certificate encoding")
5172 for o in optlist.split():
5172 for o in optlist.split():
5173 val = opts.get(o, '')
5173 val = opts.get(o, '')
5174 if val in (None, ''): # should check against default options instead
5174 if val in (None, ''): # should check against default options instead
5175 continue
5175 continue
5176 baseui.setconfig("web", o, val)
5176 baseui.setconfig("web", o, val)
5177 if repo and repo.ui != baseui:
5177 if repo and repo.ui != baseui:
5178 repo.ui.setconfig("web", o, val)
5178 repo.ui.setconfig("web", o, val)
5179
5179
5180 o = opts.get('web_conf') or opts.get('webdir_conf')
5180 o = opts.get('web_conf') or opts.get('webdir_conf')
5181 if not o:
5181 if not o:
5182 if not repo:
5182 if not repo:
5183 raise error.RepoError(_("there is no Mercurial repository"
5183 raise error.RepoError(_("there is no Mercurial repository"
5184 " here (.hg not found)"))
5184 " here (.hg not found)"))
5185 o = repo
5185 o = repo
5186
5186
5187 app = hgweb.hgweb(o, baseui=baseui)
5187 app = hgweb.hgweb(o, baseui=baseui)
5188 service = httpservice(ui, app, opts)
5188 service = httpservice(ui, app, opts)
5189 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5189 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5190
5190
5191 class httpservice(object):
5191 class httpservice(object):
5192 def __init__(self, ui, app, opts):
5192 def __init__(self, ui, app, opts):
5193 self.ui = ui
5193 self.ui = ui
5194 self.app = app
5194 self.app = app
5195 self.opts = opts
5195 self.opts = opts
5196
5196
5197 def init(self):
5197 def init(self):
5198 util.setsignalhandler()
5198 util.setsignalhandler()
5199 self.httpd = hgweb_server.create_server(self.ui, self.app)
5199 self.httpd = hgweb_server.create_server(self.ui, self.app)
5200
5200
5201 if self.opts['port'] and not self.ui.verbose:
5201 if self.opts['port'] and not self.ui.verbose:
5202 return
5202 return
5203
5203
5204 if self.httpd.prefix:
5204 if self.httpd.prefix:
5205 prefix = self.httpd.prefix.strip('/') + '/'
5205 prefix = self.httpd.prefix.strip('/') + '/'
5206 else:
5206 else:
5207 prefix = ''
5207 prefix = ''
5208
5208
5209 port = ':%d' % self.httpd.port
5209 port = ':%d' % self.httpd.port
5210 if port == ':80':
5210 if port == ':80':
5211 port = ''
5211 port = ''
5212
5212
5213 bindaddr = self.httpd.addr
5213 bindaddr = self.httpd.addr
5214 if bindaddr == '0.0.0.0':
5214 if bindaddr == '0.0.0.0':
5215 bindaddr = '*'
5215 bindaddr = '*'
5216 elif ':' in bindaddr: # IPv6
5216 elif ':' in bindaddr: # IPv6
5217 bindaddr = '[%s]' % bindaddr
5217 bindaddr = '[%s]' % bindaddr
5218
5218
5219 fqaddr = self.httpd.fqaddr
5219 fqaddr = self.httpd.fqaddr
5220 if ':' in fqaddr:
5220 if ':' in fqaddr:
5221 fqaddr = '[%s]' % fqaddr
5221 fqaddr = '[%s]' % fqaddr
5222 if self.opts['port']:
5222 if self.opts['port']:
5223 write = self.ui.status
5223 write = self.ui.status
5224 else:
5224 else:
5225 write = self.ui.write
5225 write = self.ui.write
5226 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5226 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5227 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5227 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5228
5228
5229 def run(self):
5229 def run(self):
5230 self.httpd.serve_forever()
5230 self.httpd.serve_forever()
5231
5231
5232
5232
5233 @command('showconfig|debugconfig',
5233 @command('showconfig|debugconfig',
5234 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5234 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5235 _('[-u] [NAME]...'))
5235 _('[-u] [NAME]...'))
5236 def showconfig(ui, repo, *values, **opts):
5236 def showconfig(ui, repo, *values, **opts):
5237 """show combined config settings from all hgrc files
5237 """show combined config settings from all hgrc files
5238
5238
5239 With no arguments, print names and values of all config items.
5239 With no arguments, print names and values of all config items.
5240
5240
5241 With one argument of the form section.name, print just the value
5241 With one argument of the form section.name, print just the value
5242 of that config item.
5242 of that config item.
5243
5243
5244 With multiple arguments, print names and values of all config
5244 With multiple arguments, print names and values of all config
5245 items with matching section names.
5245 items with matching section names.
5246
5246
5247 With --debug, the source (filename and line number) is printed
5247 With --debug, the source (filename and line number) is printed
5248 for each config item.
5248 for each config item.
5249
5249
5250 Returns 0 on success.
5250 Returns 0 on success.
5251 """
5251 """
5252
5252
5253 for f in scmutil.rcpath():
5253 for f in scmutil.rcpath():
5254 ui.debug('read config from: %s\n' % f)
5254 ui.debug('read config from: %s\n' % f)
5255 untrusted = bool(opts.get('untrusted'))
5255 untrusted = bool(opts.get('untrusted'))
5256 if values:
5256 if values:
5257 sections = [v for v in values if '.' not in v]
5257 sections = [v for v in values if '.' not in v]
5258 items = [v for v in values if '.' in v]
5258 items = [v for v in values if '.' in v]
5259 if len(items) > 1 or items and sections:
5259 if len(items) > 1 or items and sections:
5260 raise util.Abort(_('only one config item permitted'))
5260 raise util.Abort(_('only one config item permitted'))
5261 for section, name, value in ui.walkconfig(untrusted=untrusted):
5261 for section, name, value in ui.walkconfig(untrusted=untrusted):
5262 value = str(value).replace('\n', '\\n')
5262 value = str(value).replace('\n', '\\n')
5263 sectname = section + '.' + name
5263 sectname = section + '.' + name
5264 if values:
5264 if values:
5265 for v in values:
5265 for v in values:
5266 if v == section:
5266 if v == section:
5267 ui.debug('%s: ' %
5267 ui.debug('%s: ' %
5268 ui.configsource(section, name, untrusted))
5268 ui.configsource(section, name, untrusted))
5269 ui.write('%s=%s\n' % (sectname, value))
5269 ui.write('%s=%s\n' % (sectname, value))
5270 elif v == sectname:
5270 elif v == sectname:
5271 ui.debug('%s: ' %
5271 ui.debug('%s: ' %
5272 ui.configsource(section, name, untrusted))
5272 ui.configsource(section, name, untrusted))
5273 ui.write(value, '\n')
5273 ui.write(value, '\n')
5274 else:
5274 else:
5275 ui.debug('%s: ' %
5275 ui.debug('%s: ' %
5276 ui.configsource(section, name, untrusted))
5276 ui.configsource(section, name, untrusted))
5277 ui.write('%s=%s\n' % (sectname, value))
5277 ui.write('%s=%s\n' % (sectname, value))
5278
5278
5279 @command('^status|st',
5279 @command('^status|st',
5280 [('A', 'all', None, _('show status of all files')),
5280 [('A', 'all', None, _('show status of all files')),
5281 ('m', 'modified', None, _('show only modified files')),
5281 ('m', 'modified', None, _('show only modified files')),
5282 ('a', 'added', None, _('show only added files')),
5282 ('a', 'added', None, _('show only added files')),
5283 ('r', 'removed', None, _('show only removed files')),
5283 ('r', 'removed', None, _('show only removed files')),
5284 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5284 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5285 ('c', 'clean', None, _('show only files without changes')),
5285 ('c', 'clean', None, _('show only files without changes')),
5286 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5286 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5287 ('i', 'ignored', None, _('show only ignored files')),
5287 ('i', 'ignored', None, _('show only ignored files')),
5288 ('n', 'no-status', None, _('hide status prefix')),
5288 ('n', 'no-status', None, _('hide status prefix')),
5289 ('C', 'copies', None, _('show source of copied files')),
5289 ('C', 'copies', None, _('show source of copied files')),
5290 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5290 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5291 ('', 'rev', [], _('show difference from revision'), _('REV')),
5291 ('', 'rev', [], _('show difference from revision'), _('REV')),
5292 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5292 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5293 ] + walkopts + subrepoopts,
5293 ] + walkopts + subrepoopts,
5294 _('[OPTION]... [FILE]...'))
5294 _('[OPTION]... [FILE]...'))
5295 def status(ui, repo, *pats, **opts):
5295 def status(ui, repo, *pats, **opts):
5296 """show changed files in the working directory
5296 """show changed files in the working directory
5297
5297
5298 Show status of files in the repository. If names are given, only
5298 Show status of files in the repository. If names are given, only
5299 files that match are shown. Files that are clean or ignored or
5299 files that match are shown. Files that are clean or ignored or
5300 the source of a copy/move operation, are not listed unless
5300 the source of a copy/move operation, are not listed unless
5301 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5301 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5302 Unless options described with "show only ..." are given, the
5302 Unless options described with "show only ..." are given, the
5303 options -mardu are used.
5303 options -mardu are used.
5304
5304
5305 Option -q/--quiet hides untracked (unknown and ignored) files
5305 Option -q/--quiet hides untracked (unknown and ignored) files
5306 unless explicitly requested with -u/--unknown or -i/--ignored.
5306 unless explicitly requested with -u/--unknown or -i/--ignored.
5307
5307
5308 .. note::
5308 .. note::
5309 status may appear to disagree with diff if permissions have
5309 status may appear to disagree with diff if permissions have
5310 changed or a merge has occurred. The standard diff format does
5310 changed or a merge has occurred. The standard diff format does
5311 not report permission changes and diff only reports changes
5311 not report permission changes and diff only reports changes
5312 relative to one merge parent.
5312 relative to one merge parent.
5313
5313
5314 If one revision is given, it is used as the base revision.
5314 If one revision is given, it is used as the base revision.
5315 If two revisions are given, the differences between them are
5315 If two revisions are given, the differences between them are
5316 shown. The --change option can also be used as a shortcut to list
5316 shown. The --change option can also be used as a shortcut to list
5317 the changed files of a revision from its first parent.
5317 the changed files of a revision from its first parent.
5318
5318
5319 The codes used to show the status of files are::
5319 The codes used to show the status of files are::
5320
5320
5321 M = modified
5321 M = modified
5322 A = added
5322 A = added
5323 R = removed
5323 R = removed
5324 C = clean
5324 C = clean
5325 ! = missing (deleted by non-hg command, but still tracked)
5325 ! = missing (deleted by non-hg command, but still tracked)
5326 ? = not tracked
5326 ? = not tracked
5327 I = ignored
5327 I = ignored
5328 = origin of the previous file listed as A (added)
5328 = origin of the previous file listed as A (added)
5329
5329
5330 .. container:: verbose
5330 .. container:: verbose
5331
5331
5332 Examples:
5332 Examples:
5333
5333
5334 - show changes in the working directory relative to a
5334 - show changes in the working directory relative to a
5335 changeset::
5335 changeset::
5336
5336
5337 hg status --rev 9353
5337 hg status --rev 9353
5338
5338
5339 - show all changes including copies in an existing changeset::
5339 - show all changes including copies in an existing changeset::
5340
5340
5341 hg status --copies --change 9353
5341 hg status --copies --change 9353
5342
5342
5343 - get a NUL separated list of added files, suitable for xargs::
5343 - get a NUL separated list of added files, suitable for xargs::
5344
5344
5345 hg status -an0
5345 hg status -an0
5346
5346
5347 Returns 0 on success.
5347 Returns 0 on success.
5348 """
5348 """
5349
5349
5350 revs = opts.get('rev')
5350 revs = opts.get('rev')
5351 change = opts.get('change')
5351 change = opts.get('change')
5352
5352
5353 if revs and change:
5353 if revs and change:
5354 msg = _('cannot specify --rev and --change at the same time')
5354 msg = _('cannot specify --rev and --change at the same time')
5355 raise util.Abort(msg)
5355 raise util.Abort(msg)
5356 elif change:
5356 elif change:
5357 node2 = scmutil.revsingle(repo, change, None).node()
5357 node2 = scmutil.revsingle(repo, change, None).node()
5358 node1 = repo[node2].p1().node()
5358 node1 = repo[node2].p1().node()
5359 else:
5359 else:
5360 node1, node2 = scmutil.revpair(repo, revs)
5360 node1, node2 = scmutil.revpair(repo, revs)
5361
5361
5362 cwd = (pats and repo.getcwd()) or ''
5362 cwd = (pats and repo.getcwd()) or ''
5363 end = opts.get('print0') and '\0' or '\n'
5363 end = opts.get('print0') and '\0' or '\n'
5364 copy = {}
5364 copy = {}
5365 states = 'modified added removed deleted unknown ignored clean'.split()
5365 states = 'modified added removed deleted unknown ignored clean'.split()
5366 show = [k for k in states if opts.get(k)]
5366 show = [k for k in states if opts.get(k)]
5367 if opts.get('all'):
5367 if opts.get('all'):
5368 show += ui.quiet and (states[:4] + ['clean']) or states
5368 show += ui.quiet and (states[:4] + ['clean']) or states
5369 if not show:
5369 if not show:
5370 show = ui.quiet and states[:4] or states[:5]
5370 show = ui.quiet and states[:4] or states[:5]
5371
5371
5372 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5372 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5373 'ignored' in show, 'clean' in show, 'unknown' in show,
5373 'ignored' in show, 'clean' in show, 'unknown' in show,
5374 opts.get('subrepos'))
5374 opts.get('subrepos'))
5375 changestates = zip(states, 'MAR!?IC', stat)
5375 changestates = zip(states, 'MAR!?IC', stat)
5376
5376
5377 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5377 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5378 copy = copies.pathcopies(repo[node1], repo[node2])
5378 copy = copies.pathcopies(repo[node1], repo[node2])
5379
5379
5380 fm = ui.formatter('status', opts)
5380 fm = ui.formatter('status', opts)
5381 fmt = '%s' + end
5381 fmt = '%s' + end
5382 showchar = not opts.get('no_status')
5382 showchar = not opts.get('no_status')
5383
5383
5384 for state, char, files in changestates:
5384 for state, char, files in changestates:
5385 if state in show:
5385 if state in show:
5386 label = 'status.' + state
5386 label = 'status.' + state
5387 for f in files:
5387 for f in files:
5388 fm.startitem()
5388 fm.startitem()
5389 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5389 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5390 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5390 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5391 if f in copy:
5391 if f in copy:
5392 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5392 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5393 label='status.copied')
5393 label='status.copied')
5394 fm.end()
5394 fm.end()
5395
5395
5396 @command('^summary|sum',
5396 @command('^summary|sum',
5397 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5397 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5398 def summary(ui, repo, **opts):
5398 def summary(ui, repo, **opts):
5399 """summarize working directory state
5399 """summarize working directory state
5400
5400
5401 This generates a brief summary of the working directory state,
5401 This generates a brief summary of the working directory state,
5402 including parents, branch, commit status, and available updates.
5402 including parents, branch, commit status, and available updates.
5403
5403
5404 With the --remote option, this will check the default paths for
5404 With the --remote option, this will check the default paths for
5405 incoming and outgoing changes. This can be time-consuming.
5405 incoming and outgoing changes. This can be time-consuming.
5406
5406
5407 Returns 0 on success.
5407 Returns 0 on success.
5408 """
5408 """
5409
5409
5410 ctx = repo[None]
5410 ctx = repo[None]
5411 parents = ctx.parents()
5411 parents = ctx.parents()
5412 pnode = parents[0].node()
5412 pnode = parents[0].node()
5413 marks = []
5413 marks = []
5414
5414
5415 for p in parents:
5415 for p in parents:
5416 # label with log.changeset (instead of log.parent) since this
5416 # label with log.changeset (instead of log.parent) since this
5417 # shows a working directory parent *changeset*:
5417 # shows a working directory parent *changeset*:
5418 # i18n: column positioning for "hg summary"
5418 # i18n: column positioning for "hg summary"
5419 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5419 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5420 label='log.changeset changeset.%s' % p.phasestr())
5420 label='log.changeset changeset.%s' % p.phasestr())
5421 ui.write(' '.join(p.tags()), label='log.tag')
5421 ui.write(' '.join(p.tags()), label='log.tag')
5422 if p.bookmarks():
5422 if p.bookmarks():
5423 marks.extend(p.bookmarks())
5423 marks.extend(p.bookmarks())
5424 if p.rev() == -1:
5424 if p.rev() == -1:
5425 if not len(repo):
5425 if not len(repo):
5426 ui.write(_(' (empty repository)'))
5426 ui.write(_(' (empty repository)'))
5427 else:
5427 else:
5428 ui.write(_(' (no revision checked out)'))
5428 ui.write(_(' (no revision checked out)'))
5429 ui.write('\n')
5429 ui.write('\n')
5430 if p.description():
5430 if p.description():
5431 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5431 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5432 label='log.summary')
5432 label='log.summary')
5433
5433
5434 branch = ctx.branch()
5434 branch = ctx.branch()
5435 bheads = repo.branchheads(branch)
5435 bheads = repo.branchheads(branch)
5436 # i18n: column positioning for "hg summary"
5436 # i18n: column positioning for "hg summary"
5437 m = _('branch: %s\n') % branch
5437 m = _('branch: %s\n') % branch
5438 if branch != 'default':
5438 if branch != 'default':
5439 ui.write(m, label='log.branch')
5439 ui.write(m, label='log.branch')
5440 else:
5440 else:
5441 ui.status(m, label='log.branch')
5441 ui.status(m, label='log.branch')
5442
5442
5443 if marks:
5443 if marks:
5444 current = repo._bookmarkcurrent
5444 current = repo._bookmarkcurrent
5445 # i18n: column positioning for "hg summary"
5445 # i18n: column positioning for "hg summary"
5446 ui.write(_('bookmarks:'), label='log.bookmark')
5446 ui.write(_('bookmarks:'), label='log.bookmark')
5447 if current is not None:
5447 if current is not None:
5448 if current in marks:
5448 if current in marks:
5449 ui.write(' *' + current, label='bookmarks.current')
5449 ui.write(' *' + current, label='bookmarks.current')
5450 marks.remove(current)
5450 marks.remove(current)
5451 else:
5451 else:
5452 ui.write(' [%s]' % current, label='bookmarks.current')
5452 ui.write(' [%s]' % current, label='bookmarks.current')
5453 for m in marks:
5453 for m in marks:
5454 ui.write(' ' + m, label='log.bookmark')
5454 ui.write(' ' + m, label='log.bookmark')
5455 ui.write('\n', label='log.bookmark')
5455 ui.write('\n', label='log.bookmark')
5456
5456
5457 st = list(repo.status(unknown=True))[:6]
5457 st = list(repo.status(unknown=True))[:6]
5458
5458
5459 c = repo.dirstate.copies()
5459 c = repo.dirstate.copies()
5460 copied, renamed = [], []
5460 copied, renamed = [], []
5461 for d, s in c.iteritems():
5461 for d, s in c.iteritems():
5462 if s in st[2]:
5462 if s in st[2]:
5463 st[2].remove(s)
5463 st[2].remove(s)
5464 renamed.append(d)
5464 renamed.append(d)
5465 else:
5465 else:
5466 copied.append(d)
5466 copied.append(d)
5467 if d in st[1]:
5467 if d in st[1]:
5468 st[1].remove(d)
5468 st[1].remove(d)
5469 st.insert(3, renamed)
5469 st.insert(3, renamed)
5470 st.insert(4, copied)
5470 st.insert(4, copied)
5471
5471
5472 ms = mergemod.mergestate(repo)
5472 ms = mergemod.mergestate(repo)
5473 st.append([f for f in ms if ms[f] == 'u'])
5473 st.append([f for f in ms if ms[f] == 'u'])
5474
5474
5475 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5475 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5476 st.append(subs)
5476 st.append(subs)
5477
5477
5478 labels = [ui.label(_('%d modified'), 'status.modified'),
5478 labels = [ui.label(_('%d modified'), 'status.modified'),
5479 ui.label(_('%d added'), 'status.added'),
5479 ui.label(_('%d added'), 'status.added'),
5480 ui.label(_('%d removed'), 'status.removed'),
5480 ui.label(_('%d removed'), 'status.removed'),
5481 ui.label(_('%d renamed'), 'status.copied'),
5481 ui.label(_('%d renamed'), 'status.copied'),
5482 ui.label(_('%d copied'), 'status.copied'),
5482 ui.label(_('%d copied'), 'status.copied'),
5483 ui.label(_('%d deleted'), 'status.deleted'),
5483 ui.label(_('%d deleted'), 'status.deleted'),
5484 ui.label(_('%d unknown'), 'status.unknown'),
5484 ui.label(_('%d unknown'), 'status.unknown'),
5485 ui.label(_('%d ignored'), 'status.ignored'),
5485 ui.label(_('%d ignored'), 'status.ignored'),
5486 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5486 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5487 ui.label(_('%d subrepos'), 'status.modified')]
5487 ui.label(_('%d subrepos'), 'status.modified')]
5488 t = []
5488 t = []
5489 for s, l in zip(st, labels):
5489 for s, l in zip(st, labels):
5490 if s:
5490 if s:
5491 t.append(l % len(s))
5491 t.append(l % len(s))
5492
5492
5493 t = ', '.join(t)
5493 t = ', '.join(t)
5494 cleanworkdir = False
5494 cleanworkdir = False
5495
5495
5496 if repo.vfs.exists('updatestate'):
5496 if repo.vfs.exists('updatestate'):
5497 t += _(' (interrupted update)')
5497 t += _(' (interrupted update)')
5498 elif len(parents) > 1:
5498 elif len(parents) > 1:
5499 t += _(' (merge)')
5499 t += _(' (merge)')
5500 elif branch != parents[0].branch():
5500 elif branch != parents[0].branch():
5501 t += _(' (new branch)')
5501 t += _(' (new branch)')
5502 elif (parents[0].closesbranch() and
5502 elif (parents[0].closesbranch() and
5503 pnode in repo.branchheads(branch, closed=True)):
5503 pnode in repo.branchheads(branch, closed=True)):
5504 t += _(' (head closed)')
5504 t += _(' (head closed)')
5505 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5505 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5506 t += _(' (clean)')
5506 t += _(' (clean)')
5507 cleanworkdir = True
5507 cleanworkdir = True
5508 elif pnode not in bheads:
5508 elif pnode not in bheads:
5509 t += _(' (new branch head)')
5509 t += _(' (new branch head)')
5510
5510
5511 if cleanworkdir:
5511 if cleanworkdir:
5512 # i18n: column positioning for "hg summary"
5512 # i18n: column positioning for "hg summary"
5513 ui.status(_('commit: %s\n') % t.strip())
5513 ui.status(_('commit: %s\n') % t.strip())
5514 else:
5514 else:
5515 # i18n: column positioning for "hg summary"
5515 # i18n: column positioning for "hg summary"
5516 ui.write(_('commit: %s\n') % t.strip())
5516 ui.write(_('commit: %s\n') % t.strip())
5517
5517
5518 # all ancestors of branch heads - all ancestors of parent = new csets
5518 # all ancestors of branch heads - all ancestors of parent = new csets
5519 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5519 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5520 bheads))
5520 bheads))
5521
5521
5522 if new == 0:
5522 if new == 0:
5523 # i18n: column positioning for "hg summary"
5523 # i18n: column positioning for "hg summary"
5524 ui.status(_('update: (current)\n'))
5524 ui.status(_('update: (current)\n'))
5525 elif pnode not in bheads:
5525 elif pnode not in bheads:
5526 # i18n: column positioning for "hg summary"
5526 # i18n: column positioning for "hg summary"
5527 ui.write(_('update: %d new changesets (update)\n') % new)
5527 ui.write(_('update: %d new changesets (update)\n') % new)
5528 else:
5528 else:
5529 # i18n: column positioning for "hg summary"
5529 # i18n: column positioning for "hg summary"
5530 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5530 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5531 (new, len(bheads)))
5531 (new, len(bheads)))
5532
5532
5533 cmdutil.summaryhooks(ui, repo)
5533 cmdutil.summaryhooks(ui, repo)
5534
5534
5535 if opts.get('remote'):
5535 if opts.get('remote'):
5536 t = []
5536 t = []
5537 source, branches = hg.parseurl(ui.expandpath('default'))
5537 source, branches = hg.parseurl(ui.expandpath('default'))
5538 sbranch = branches[0]
5538 sbranch = branches[0]
5539 other = hg.peer(repo, {}, source)
5539 other = hg.peer(repo, {}, source)
5540 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5540 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5541 if revs:
5541 if revs:
5542 revs = [other.lookup(rev) for rev in revs]
5542 revs = [other.lookup(rev) for rev in revs]
5543 ui.debug('comparing with %s\n' % util.hidepassword(source))
5543 ui.debug('comparing with %s\n' % util.hidepassword(source))
5544 repo.ui.pushbuffer()
5544 repo.ui.pushbuffer()
5545 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5545 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5546 _common, incoming, _rheads = commoninc
5546 _common, incoming, _rheads = commoninc
5547 repo.ui.popbuffer()
5547 repo.ui.popbuffer()
5548 if incoming:
5548 if incoming:
5549 t.append(_('1 or more incoming'))
5549 t.append(_('1 or more incoming'))
5550
5550
5551 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5551 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5552 dbranch = branches[0]
5552 dbranch = branches[0]
5553 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5553 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5554 if source != dest:
5554 if source != dest:
5555 other = hg.peer(repo, {}, dest)
5555 other = hg.peer(repo, {}, dest)
5556 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5556 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5557 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5557 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5558 commoninc = None
5558 commoninc = None
5559 if revs:
5559 if revs:
5560 revs = [repo.lookup(rev) for rev in revs]
5560 revs = [repo.lookup(rev) for rev in revs]
5561 repo.ui.pushbuffer()
5561 repo.ui.pushbuffer()
5562 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5562 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5563 commoninc=commoninc)
5563 commoninc=commoninc)
5564 repo.ui.popbuffer()
5564 repo.ui.popbuffer()
5565 o = outgoing.missing
5565 o = outgoing.missing
5566 if o:
5566 if o:
5567 t.append(_('%d outgoing') % len(o))
5567 t.append(_('%d outgoing') % len(o))
5568 if 'bookmarks' in other.listkeys('namespaces'):
5568 if 'bookmarks' in other.listkeys('namespaces'):
5569 lmarks = repo.listkeys('bookmarks')
5569 lmarks = repo.listkeys('bookmarks')
5570 rmarks = other.listkeys('bookmarks')
5570 rmarks = other.listkeys('bookmarks')
5571 diff = set(rmarks) - set(lmarks)
5571 diff = set(rmarks) - set(lmarks)
5572 if len(diff) > 0:
5572 if len(diff) > 0:
5573 t.append(_('%d incoming bookmarks') % len(diff))
5573 t.append(_('%d incoming bookmarks') % len(diff))
5574 diff = set(lmarks) - set(rmarks)
5574 diff = set(lmarks) - set(rmarks)
5575 if len(diff) > 0:
5575 if len(diff) > 0:
5576 t.append(_('%d outgoing bookmarks') % len(diff))
5576 t.append(_('%d outgoing bookmarks') % len(diff))
5577
5577
5578 if t:
5578 if t:
5579 # i18n: column positioning for "hg summary"
5579 # i18n: column positioning for "hg summary"
5580 ui.write(_('remote: %s\n') % (', '.join(t)))
5580 ui.write(_('remote: %s\n') % (', '.join(t)))
5581 else:
5581 else:
5582 # i18n: column positioning for "hg summary"
5582 # i18n: column positioning for "hg summary"
5583 ui.status(_('remote: (synced)\n'))
5583 ui.status(_('remote: (synced)\n'))
5584
5584
5585 @command('tag',
5585 @command('tag',
5586 [('f', 'force', None, _('force tag')),
5586 [('f', 'force', None, _('force tag')),
5587 ('l', 'local', None, _('make the tag local')),
5587 ('l', 'local', None, _('make the tag local')),
5588 ('r', 'rev', '', _('revision to tag'), _('REV')),
5588 ('r', 'rev', '', _('revision to tag'), _('REV')),
5589 ('', 'remove', None, _('remove a tag')),
5589 ('', 'remove', None, _('remove a tag')),
5590 # -l/--local is already there, commitopts cannot be used
5590 # -l/--local is already there, commitopts cannot be used
5591 ('e', 'edit', None, _('edit commit message')),
5591 ('e', 'edit', None, _('edit commit message')),
5592 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5592 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5593 ] + commitopts2,
5593 ] + commitopts2,
5594 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5594 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5595 def tag(ui, repo, name1, *names, **opts):
5595 def tag(ui, repo, name1, *names, **opts):
5596 """add one or more tags for the current or given revision
5596 """add one or more tags for the current or given revision
5597
5597
5598 Name a particular revision using <name>.
5598 Name a particular revision using <name>.
5599
5599
5600 Tags are used to name particular revisions of the repository and are
5600 Tags are used to name particular revisions of the repository and are
5601 very useful to compare different revisions, to go back to significant
5601 very useful to compare different revisions, to go back to significant
5602 earlier versions or to mark branch points as releases, etc. Changing
5602 earlier versions or to mark branch points as releases, etc. Changing
5603 an existing tag is normally disallowed; use -f/--force to override.
5603 an existing tag is normally disallowed; use -f/--force to override.
5604
5604
5605 If no revision is given, the parent of the working directory is
5605 If no revision is given, the parent of the working directory is
5606 used.
5606 used.
5607
5607
5608 To facilitate version control, distribution, and merging of tags,
5608 To facilitate version control, distribution, and merging of tags,
5609 they are stored as a file named ".hgtags" which is managed similarly
5609 they are stored as a file named ".hgtags" which is managed similarly
5610 to other project files and can be hand-edited if necessary. This
5610 to other project files and can be hand-edited if necessary. This
5611 also means that tagging creates a new commit. The file
5611 also means that tagging creates a new commit. The file
5612 ".hg/localtags" is used for local tags (not shared among
5612 ".hg/localtags" is used for local tags (not shared among
5613 repositories).
5613 repositories).
5614
5614
5615 Tag commits are usually made at the head of a branch. If the parent
5615 Tag commits are usually made at the head of a branch. If the parent
5616 of the working directory is not a branch head, :hg:`tag` aborts; use
5616 of the working directory is not a branch head, :hg:`tag` aborts; use
5617 -f/--force to force the tag commit to be based on a non-head
5617 -f/--force to force the tag commit to be based on a non-head
5618 changeset.
5618 changeset.
5619
5619
5620 See :hg:`help dates` for a list of formats valid for -d/--date.
5620 See :hg:`help dates` for a list of formats valid for -d/--date.
5621
5621
5622 Since tag names have priority over branch names during revision
5622 Since tag names have priority over branch names during revision
5623 lookup, using an existing branch name as a tag name is discouraged.
5623 lookup, using an existing branch name as a tag name is discouraged.
5624
5624
5625 Returns 0 on success.
5625 Returns 0 on success.
5626 """
5626 """
5627 wlock = lock = None
5627 wlock = lock = None
5628 try:
5628 try:
5629 wlock = repo.wlock()
5629 wlock = repo.wlock()
5630 lock = repo.lock()
5630 lock = repo.lock()
5631 rev_ = "."
5631 rev_ = "."
5632 names = [t.strip() for t in (name1,) + names]
5632 names = [t.strip() for t in (name1,) + names]
5633 if len(names) != len(set(names)):
5633 if len(names) != len(set(names)):
5634 raise util.Abort(_('tag names must be unique'))
5634 raise util.Abort(_('tag names must be unique'))
5635 for n in names:
5635 for n in names:
5636 scmutil.checknewlabel(repo, n, 'tag')
5636 scmutil.checknewlabel(repo, n, 'tag')
5637 if not n:
5637 if not n:
5638 raise util.Abort(_('tag names cannot consist entirely of '
5638 raise util.Abort(_('tag names cannot consist entirely of '
5639 'whitespace'))
5639 'whitespace'))
5640 if opts.get('rev') and opts.get('remove'):
5640 if opts.get('rev') and opts.get('remove'):
5641 raise util.Abort(_("--rev and --remove are incompatible"))
5641 raise util.Abort(_("--rev and --remove are incompatible"))
5642 if opts.get('rev'):
5642 if opts.get('rev'):
5643 rev_ = opts['rev']
5643 rev_ = opts['rev']
5644 message = opts.get('message')
5644 message = opts.get('message')
5645 if opts.get('remove'):
5645 if opts.get('remove'):
5646 expectedtype = opts.get('local') and 'local' or 'global'
5646 expectedtype = opts.get('local') and 'local' or 'global'
5647 for n in names:
5647 for n in names:
5648 if not repo.tagtype(n):
5648 if not repo.tagtype(n):
5649 raise util.Abort(_("tag '%s' does not exist") % n)
5649 raise util.Abort(_("tag '%s' does not exist") % n)
5650 if repo.tagtype(n) != expectedtype:
5650 if repo.tagtype(n) != expectedtype:
5651 if expectedtype == 'global':
5651 if expectedtype == 'global':
5652 raise util.Abort(_("tag '%s' is not a global tag") % n)
5652 raise util.Abort(_("tag '%s' is not a global tag") % n)
5653 else:
5653 else:
5654 raise util.Abort(_("tag '%s' is not a local tag") % n)
5654 raise util.Abort(_("tag '%s' is not a local tag") % n)
5655 rev_ = nullid
5655 rev_ = nullid
5656 if not message:
5656 if not message:
5657 # we don't translate commit messages
5657 # we don't translate commit messages
5658 message = 'Removed tag %s' % ', '.join(names)
5658 message = 'Removed tag %s' % ', '.join(names)
5659 elif not opts.get('force'):
5659 elif not opts.get('force'):
5660 for n in names:
5660 for n in names:
5661 if n in repo.tags():
5661 if n in repo.tags():
5662 raise util.Abort(_("tag '%s' already exists "
5662 raise util.Abort(_("tag '%s' already exists "
5663 "(use -f to force)") % n)
5663 "(use -f to force)") % n)
5664 if not opts.get('local'):
5664 if not opts.get('local'):
5665 p1, p2 = repo.dirstate.parents()
5665 p1, p2 = repo.dirstate.parents()
5666 if p2 != nullid:
5666 if p2 != nullid:
5667 raise util.Abort(_('uncommitted merge'))
5667 raise util.Abort(_('uncommitted merge'))
5668 bheads = repo.branchheads()
5668 bheads = repo.branchheads()
5669 if not opts.get('force') and bheads and p1 not in bheads:
5669 if not opts.get('force') and bheads and p1 not in bheads:
5670 raise util.Abort(_('not at a branch head (use -f to force)'))
5670 raise util.Abort(_('not at a branch head (use -f to force)'))
5671 r = scmutil.revsingle(repo, rev_).node()
5671 r = scmutil.revsingle(repo, rev_).node()
5672
5672
5673 if not message:
5673 if not message:
5674 # we don't translate commit messages
5674 # we don't translate commit messages
5675 message = ('Added tag %s for changeset %s' %
5675 message = ('Added tag %s for changeset %s' %
5676 (', '.join(names), short(r)))
5676 (', '.join(names), short(r)))
5677
5677
5678 date = opts.get('date')
5678 date = opts.get('date')
5679 if date:
5679 if date:
5680 date = util.parsedate(date)
5680 date = util.parsedate(date)
5681
5681
5682 if opts.get('edit'):
5682 if opts.get('edit'):
5683 message = ui.edit(message, ui.username())
5683 message = ui.edit(message, ui.username())
5684
5684
5685 # don't allow tagging the null rev
5685 # don't allow tagging the null rev
5686 if (not opts.get('remove') and
5686 if (not opts.get('remove') and
5687 scmutil.revsingle(repo, rev_).rev() == nullrev):
5687 scmutil.revsingle(repo, rev_).rev() == nullrev):
5688 raise util.Abort(_("cannot tag null revision"))
5688 raise util.Abort(_("cannot tag null revision"))
5689
5689
5690 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5690 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5691 finally:
5691 finally:
5692 release(lock, wlock)
5692 release(lock, wlock)
5693
5693
5694 @command('tags', [], '')
5694 @command('tags', [], '')
5695 def tags(ui, repo, **opts):
5695 def tags(ui, repo, **opts):
5696 """list repository tags
5696 """list repository tags
5697
5697
5698 This lists both regular and local tags. When the -v/--verbose
5698 This lists both regular and local tags. When the -v/--verbose
5699 switch is used, a third column "local" is printed for local tags.
5699 switch is used, a third column "local" is printed for local tags.
5700
5700
5701 Returns 0 on success.
5701 Returns 0 on success.
5702 """
5702 """
5703
5703
5704 fm = ui.formatter('tags', opts)
5704 fm = ui.formatter('tags', opts)
5705 hexfunc = ui.debugflag and hex or short
5705 hexfunc = ui.debugflag and hex or short
5706 tagtype = ""
5706 tagtype = ""
5707
5707
5708 for t, n in reversed(repo.tagslist()):
5708 for t, n in reversed(repo.tagslist()):
5709 hn = hexfunc(n)
5709 hn = hexfunc(n)
5710 label = 'tags.normal'
5710 label = 'tags.normal'
5711 tagtype = ''
5711 tagtype = ''
5712 if repo.tagtype(t) == 'local':
5712 if repo.tagtype(t) == 'local':
5713 label = 'tags.local'
5713 label = 'tags.local'
5714 tagtype = 'local'
5714 tagtype = 'local'
5715
5715
5716 fm.startitem()
5716 fm.startitem()
5717 fm.write('tag', '%s', t, label=label)
5717 fm.write('tag', '%s', t, label=label)
5718 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5718 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5719 fm.condwrite(not ui.quiet, 'rev id', fmt,
5719 fm.condwrite(not ui.quiet, 'rev id', fmt,
5720 repo.changelog.rev(n), hn, label=label)
5720 repo.changelog.rev(n), hn, label=label)
5721 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5721 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5722 tagtype, label=label)
5722 tagtype, label=label)
5723 fm.plain('\n')
5723 fm.plain('\n')
5724 fm.end()
5724 fm.end()
5725
5725
5726 @command('tip',
5726 @command('tip',
5727 [('p', 'patch', None, _('show patch')),
5727 [('p', 'patch', None, _('show patch')),
5728 ('g', 'git', None, _('use git extended diff format')),
5728 ('g', 'git', None, _('use git extended diff format')),
5729 ] + templateopts,
5729 ] + templateopts,
5730 _('[-p] [-g]'))
5730 _('[-p] [-g]'))
5731 def tip(ui, repo, **opts):
5731 def tip(ui, repo, **opts):
5732 """show the tip revision (DEPRECATED)
5732 """show the tip revision (DEPRECATED)
5733
5733
5734 The tip revision (usually just called the tip) is the changeset
5734 The tip revision (usually just called the tip) is the changeset
5735 most recently added to the repository (and therefore the most
5735 most recently added to the repository (and therefore the most
5736 recently changed head).
5736 recently changed head).
5737
5737
5738 If you have just made a commit, that commit will be the tip. If
5738 If you have just made a commit, that commit will be the tip. If
5739 you have just pulled changes from another repository, the tip of
5739 you have just pulled changes from another repository, the tip of
5740 that repository becomes the current tip. The "tip" tag is special
5740 that repository becomes the current tip. The "tip" tag is special
5741 and cannot be renamed or assigned to a different changeset.
5741 and cannot be renamed or assigned to a different changeset.
5742
5742
5743 This command is deprecated, please use :hg:`heads` instead.
5743 This command is deprecated, please use :hg:`heads` instead.
5744
5744
5745 Returns 0 on success.
5745 Returns 0 on success.
5746 """
5746 """
5747 displayer = cmdutil.show_changeset(ui, repo, opts)
5747 displayer = cmdutil.show_changeset(ui, repo, opts)
5748 displayer.show(repo['tip'])
5748 displayer.show(repo['tip'])
5749 displayer.close()
5749 displayer.close()
5750
5750
5751 @command('unbundle',
5751 @command('unbundle',
5752 [('u', 'update', None,
5752 [('u', 'update', None,
5753 _('update to new branch head if changesets were unbundled'))],
5753 _('update to new branch head if changesets were unbundled'))],
5754 _('[-u] FILE...'))
5754 _('[-u] FILE...'))
5755 def unbundle(ui, repo, fname1, *fnames, **opts):
5755 def unbundle(ui, repo, fname1, *fnames, **opts):
5756 """apply one or more changegroup files
5756 """apply one or more changegroup files
5757
5757
5758 Apply one or more compressed changegroup files generated by the
5758 Apply one or more compressed changegroup files generated by the
5759 bundle command.
5759 bundle command.
5760
5760
5761 Returns 0 on success, 1 if an update has unresolved files.
5761 Returns 0 on success, 1 if an update has unresolved files.
5762 """
5762 """
5763 fnames = (fname1,) + fnames
5763 fnames = (fname1,) + fnames
5764
5764
5765 lock = repo.lock()
5765 lock = repo.lock()
5766 wc = repo['.']
5766 wc = repo['.']
5767 try:
5767 try:
5768 for fname in fnames:
5768 for fname in fnames:
5769 f = hg.openpath(ui, fname)
5769 f = hg.openpath(ui, fname)
5770 gen = changegroup.readbundle(f, fname)
5770 gen = changegroup.readbundle(f, fname)
5771 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5771 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5772 finally:
5772 finally:
5773 lock.release()
5773 lock.release()
5774 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5774 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5775 return postincoming(ui, repo, modheads, opts.get('update'), None)
5775 return postincoming(ui, repo, modheads, opts.get('update'), None)
5776
5776
5777 @command('^update|up|checkout|co',
5777 @command('^update|up|checkout|co',
5778 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5778 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5779 ('c', 'check', None,
5779 ('c', 'check', None,
5780 _('update across branches if no uncommitted changes')),
5780 _('update across branches if no uncommitted changes')),
5781 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5781 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5782 ('r', 'rev', '', _('revision'), _('REV'))],
5782 ('r', 'rev', '', _('revision'), _('REV'))],
5783 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5783 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5784 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5784 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5785 """update working directory (or switch revisions)
5785 """update working directory (or switch revisions)
5786
5786
5787 Update the repository's working directory to the specified
5787 Update the repository's working directory to the specified
5788 changeset. If no changeset is specified, update to the tip of the
5788 changeset. If no changeset is specified, update to the tip of the
5789 current named branch and move the current bookmark (see :hg:`help
5789 current named branch and move the current bookmark (see :hg:`help
5790 bookmarks`).
5790 bookmarks`).
5791
5791
5792 Update sets the working directory's parent revision to the specified
5792 Update sets the working directory's parent revision to the specified
5793 changeset (see :hg:`help parents`).
5793 changeset (see :hg:`help parents`).
5794
5794
5795 If the changeset is not a descendant or ancestor of the working
5795 If the changeset is not a descendant or ancestor of the working
5796 directory's parent, the update is aborted. With the -c/--check
5796 directory's parent, the update is aborted. With the -c/--check
5797 option, the working directory is checked for uncommitted changes; if
5797 option, the working directory is checked for uncommitted changes; if
5798 none are found, the working directory is updated to the specified
5798 none are found, the working directory is updated to the specified
5799 changeset.
5799 changeset.
5800
5800
5801 .. container:: verbose
5801 .. container:: verbose
5802
5802
5803 The following rules apply when the working directory contains
5803 The following rules apply when the working directory contains
5804 uncommitted changes:
5804 uncommitted changes:
5805
5805
5806 1. If neither -c/--check nor -C/--clean is specified, and if
5806 1. If neither -c/--check nor -C/--clean is specified, and if
5807 the requested changeset is an ancestor or descendant of
5807 the requested changeset is an ancestor or descendant of
5808 the working directory's parent, the uncommitted changes
5808 the working directory's parent, the uncommitted changes
5809 are merged into the requested changeset and the merged
5809 are merged into the requested changeset and the merged
5810 result is left uncommitted. If the requested changeset is
5810 result is left uncommitted. If the requested changeset is
5811 not an ancestor or descendant (that is, it is on another
5811 not an ancestor or descendant (that is, it is on another
5812 branch), the update is aborted and the uncommitted changes
5812 branch), the update is aborted and the uncommitted changes
5813 are preserved.
5813 are preserved.
5814
5814
5815 2. With the -c/--check option, the update is aborted and the
5815 2. With the -c/--check option, the update is aborted and the
5816 uncommitted changes are preserved.
5816 uncommitted changes are preserved.
5817
5817
5818 3. With the -C/--clean option, uncommitted changes are discarded and
5818 3. With the -C/--clean option, uncommitted changes are discarded and
5819 the working directory is updated to the requested changeset.
5819 the working directory is updated to the requested changeset.
5820
5820
5821 To cancel an uncommitted merge (and lose your changes), use
5821 To cancel an uncommitted merge (and lose your changes), use
5822 :hg:`update --clean .`.
5822 :hg:`update --clean .`.
5823
5823
5824 Use null as the changeset to remove the working directory (like
5824 Use null as the changeset to remove the working directory (like
5825 :hg:`clone -U`).
5825 :hg:`clone -U`).
5826
5826
5827 If you want to revert just one file to an older revision, use
5827 If you want to revert just one file to an older revision, use
5828 :hg:`revert [-r REV] NAME`.
5828 :hg:`revert [-r REV] NAME`.
5829
5829
5830 See :hg:`help dates` for a list of formats valid for -d/--date.
5830 See :hg:`help dates` for a list of formats valid for -d/--date.
5831
5831
5832 Returns 0 on success, 1 if there are unresolved files.
5832 Returns 0 on success, 1 if there are unresolved files.
5833 """
5833 """
5834 if rev and node:
5834 if rev and node:
5835 raise util.Abort(_("please specify just one revision"))
5835 raise util.Abort(_("please specify just one revision"))
5836
5836
5837 if rev is None or rev == '':
5837 if rev is None or rev == '':
5838 rev = node
5838 rev = node
5839
5839
5840 cmdutil.clearunfinished(repo)
5840 cmdutil.clearunfinished(repo)
5841
5841
5842 # with no argument, we also move the current bookmark, if any
5842 # with no argument, we also move the current bookmark, if any
5843 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5843 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
5844
5844
5845 # if we defined a bookmark, we have to remember the original bookmark name
5845 # if we defined a bookmark, we have to remember the original bookmark name
5846 brev = rev
5846 brev = rev
5847 rev = scmutil.revsingle(repo, rev, rev).rev()
5847 rev = scmutil.revsingle(repo, rev, rev).rev()
5848
5848
5849 if check and clean:
5849 if check and clean:
5850 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5850 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5851
5851
5852 if date:
5852 if date:
5853 if rev is not None:
5853 if rev is not None:
5854 raise util.Abort(_("you can't specify a revision and a date"))
5854 raise util.Abort(_("you can't specify a revision and a date"))
5855 rev = cmdutil.finddate(ui, repo, date)
5855 rev = cmdutil.finddate(ui, repo, date)
5856
5856
5857 if check:
5857 if check:
5858 c = repo[None]
5858 c = repo[None]
5859 if c.dirty(merge=False, branch=False, missing=True):
5859 if c.dirty(merge=False, branch=False, missing=True):
5860 raise util.Abort(_("uncommitted changes"))
5860 raise util.Abort(_("uncommitted changes"))
5861 if rev is None:
5861 if rev is None:
5862 rev = repo[repo[None].branch()].rev()
5862 rev = repo[repo[None].branch()].rev()
5863 mergemod._checkunknown(repo, repo[None], repo[rev])
5863 mergemod._checkunknown(repo, repo[None], repo[rev])
5864
5864
5865 if clean:
5865 if clean:
5866 ret = hg.clean(repo, rev)
5866 ret = hg.clean(repo, rev)
5867 else:
5867 else:
5868 ret = hg.update(repo, rev)
5868 ret = hg.update(repo, rev)
5869
5869
5870 if not ret and movemarkfrom:
5870 if not ret and movemarkfrom:
5871 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5871 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5872 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5872 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5873 elif brev in repo._bookmarks:
5873 elif brev in repo._bookmarks:
5874 bookmarks.setcurrent(repo, brev)
5874 bookmarks.setcurrent(repo, brev)
5875 elif brev:
5875 elif brev:
5876 bookmarks.unsetcurrent(repo)
5876 bookmarks.unsetcurrent(repo)
5877
5877
5878 return ret
5878 return ret
5879
5879
5880 @command('verify', [])
5880 @command('verify', [])
5881 def verify(ui, repo):
5881 def verify(ui, repo):
5882 """verify the integrity of the repository
5882 """verify the integrity of the repository
5883
5883
5884 Verify the integrity of the current repository.
5884 Verify the integrity of the current repository.
5885
5885
5886 This will perform an extensive check of the repository's
5886 This will perform an extensive check of the repository's
5887 integrity, validating the hashes and checksums of each entry in
5887 integrity, validating the hashes and checksums of each entry in
5888 the changelog, manifest, and tracked files, as well as the
5888 the changelog, manifest, and tracked files, as well as the
5889 integrity of their crosslinks and indices.
5889 integrity of their crosslinks and indices.
5890
5890
5891 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5891 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5892 for more information about recovery from corruption of the
5892 for more information about recovery from corruption of the
5893 repository.
5893 repository.
5894
5894
5895 Returns 0 on success, 1 if errors are encountered.
5895 Returns 0 on success, 1 if errors are encountered.
5896 """
5896 """
5897 return hg.verify(repo)
5897 return hg.verify(repo)
5898
5898
5899 @command('version', [])
5899 @command('version', [])
5900 def version_(ui):
5900 def version_(ui):
5901 """output version and copyright information"""
5901 """output version and copyright information"""
5902 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5902 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5903 % util.version())
5903 % util.version())
5904 ui.status(_(
5904 ui.status(_(
5905 "(see http://mercurial.selenic.com for more information)\n"
5905 "(see http://mercurial.selenic.com for more information)\n"
5906 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5906 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5907 "This is free software; see the source for copying conditions. "
5907 "This is free software; see the source for copying conditions. "
5908 "There is NO\nwarranty; "
5908 "There is NO\nwarranty; "
5909 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5909 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5910 ))
5910 ))
5911
5911
5912 norepo = ("clone init version help debugcommands debugcomplete"
5912 norepo = ("clone init version help debugcommands debugcomplete"
5913 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5913 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5914 " debugknown debuggetbundle debugbundle")
5914 " debugknown debuggetbundle debugbundle")
5915 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5915 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5916 " debugdata debugindex debugindexdot debugrevlog")
5916 " debugdata debugindex debugindexdot debugrevlog")
5917 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5917 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5918 " remove resolve status debugwalk")
5918 " remove resolve status debugwalk")
@@ -1,84 +1,84 b''
1 What are phases?
1 What are phases?
2 ================
2 ================
3
3
4 Phases are a system for tracking which changesets have been or should
4 Phases are a system for tracking which changesets have been or should
5 be shared. This helps prevent common mistakes when modifying history
5 be shared. This helps prevent common mistakes when modifying history
6 (for instance, with the mq or rebase extensions).
6 (for instance, with the mq or rebase extensions).
7
7
8 Each changeset in a repository is in one of the following phases:
8 Each changeset in a repository is in one of the following phases:
9
9
10 - public : changeset is visible on a public server
10 - public : changeset is visible on a public server
11 - draft : changeset is not yet published
11 - draft : changeset is not yet published
12 - secret : changeset should not be pushed, pulled, or cloned
12 - secret : changeset should not be pushed, pulled, or cloned
13
13
14 These phases are ordered (public < draft < secret) and no changeset
14 These phases are ordered (public < draft < secret) and no changeset
15 can be in a lower phase than its ancestors. For instance, if a
15 can be in a lower phase than its ancestors. For instance, if a
16 changeset is public, all its ancestors are also public. Lastly,
16 changeset is public, all its ancestors are also public. Lastly,
17 changeset phases should only be changed towards the public phase.
17 changeset phases should only be changed towards the public phase.
18
18
19 How are phases managed?
19 How are phases managed?
20 =======================
20 =======================
21
21
22 For the most part, phases should work transparently. By default, a
22 For the most part, phases should work transparently. By default, a
23 changeset is created in the draft phase and is moved into the public
23 changeset is created in the draft phase and is moved into the public
24 phase when it is pushed to another repository.
24 phase when it is pushed to another repository.
25
25
26 Once changesets become public, extensions like mq and rebase will
26 Once changesets become public, extensions like mq and rebase will
27 refuse to operate on them to prevent creating duplicate changesets.
27 refuse to operate on them to prevent creating duplicate changesets.
28 Phases can also be manually manipulated with the :hg:`phase` command
28 Phases can also be manually manipulated with the :hg:`phase` command
29 if needed. See :hg:`help -v phase` for examples.
29 if needed. See :hg:`help -v phase` for examples.
30
30
31 Phases and servers
31 Phases and servers
32 ==================
32 ==================
33
33
34 Normally, all servers are ``publishing`` by default. This means::
34 Normally, all servers are ``publishing`` by default. This means::
35
35
36 - all draft changesets that are pulled or cloned appear in phase
36 - all draft changesets that are pulled or cloned appear in phase
37 public on the client
37 public on the client
38
38
39 - all draft changesets that are pushed appear as public on both
39 - all draft changesets that are pushed appear as public on both
40 client and server
40 client and server
41
41
42 - secret changesets are neither pushed, pulled, or cloned
42 - secret changesets are neither pushed, pulled, or cloned
43
43
44 .. note::
44 .. note::
45 Pulling a draft changeset from a publishing server does not mark it
45 Pulling a draft changeset from a publishing server does not mark it
46 as public on the server side due to the read-only nature of pull.
46 as public on the server side due to the read-only nature of pull.
47
47
48 Sometimes it may be desirable to push and pull changesets in the draft
48 Sometimes it may be desirable to push and pull changesets in the draft
49 phase to share unfinished work. This can be done by setting a
49 phase to share unfinished work. This can be done by setting a
50 repository to disable publishing in its configuration file::
50 repository to disable publishing in its configuration file::
51
51
52 [phases]
52 [phases]
53 publish = False
53 publish = False
54
54
55 See :hg:`help config` for more information on configuration files.
55 See :hg:`help config` for more information on configuration files.
56
56
57 .. note::
57 .. note::
58 Servers running older versions of Mercurial are treated as
58 Servers running older versions of Mercurial are treated as
59 publishing.
59 publishing.
60
60
61 Examples
61 Examples
62 ========
62 ========
63
63
64 - list changesets in draft or secret phase::
64 - list changesets in draft or secret phase::
65
65
66 hg log -r "not public()"
66 hg log -r "not public()"
67
67
68 - change all secret changesets to draft::
68 - change all secret changesets to draft::
69
69
70 hg phase --draft "secret()"
70 hg phase --draft "secret()"
71
71
72 - forcibly move the current changeset and descendants from public to draft::
72 - forcibly move the current changeset and descendants from public to draft::
73
73
74 hg phase --force --draft .
74 hg phase --force --draft .
75
75
76 - show a list of changeset revision and phase::
76 - show a list of changeset revision and phase::
77
77
78 hg log --template "{rev} {phase}\n"
78 hg log --template "{rev} {phase}\n"
79
79
80 - resynchronize draft changesets relative to a remote repository::
80 - resynchronize draft changesets relative to a remote repository::
81
81
82 hg phase -fd 'outgoing(URL)'
82 hg phase -fd "outgoing(URL)"
83
83
84 See :hg:`help phase` for more information on manually manipulating phases.
84 See :hg:`help phase` for more information on manually manipulating phases.
General Comments 0
You need to be logged in to leave comments. Login now