##// END OF EJS Templates
merge with stable
Matt Mackall -
r19234:7bbad79b merge default
parent child Browse files
Show More
@@ -1,157 +1,158 b''
1 # blackbox.py - log repository events to a file for post-mortem debugging
1 # blackbox.py - log repository events to a file for post-mortem debugging
2 #
2 #
3 # Copyright 2010 Nicolas Dumazet
3 # Copyright 2010 Nicolas Dumazet
4 # Copyright 2013 Facebook, Inc.
4 # Copyright 2013 Facebook, Inc.
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 """log repository events to a blackbox for debugging
9 """log repository events to a blackbox for debugging
10
10
11 Logs event information to .hg/blackbox.log to help debug and diagnose problems.
11 Logs event information to .hg/blackbox.log to help debug and diagnose problems.
12 The events that get logged can be configured via the blackbox.track config key.
12 The events that get logged can be configured via the blackbox.track config key.
13 Examples::
13 Examples::
14
14
15 [blackbox]
15 [blackbox]
16 track = *
16 track = *
17
17
18 [blackbox]
18 [blackbox]
19 track = command, commandfinish, commandexception, exthook, pythonhook
19 track = command, commandfinish, commandexception, exthook, pythonhook
20
20
21 [blackbox]
21 [blackbox]
22 track = incoming
22 track = incoming
23
23
24 [blackbox]
24 [blackbox]
25 # limit the size of a log file
25 # limit the size of a log file
26 maxsize = 1.5 MB
26 maxsize = 1.5 MB
27 # rotate up to N log files when the current one gets too big
27 # rotate up to N log files when the current one gets too big
28 maxfiles = 3
28 maxfiles = 3
29
29
30 """
30 """
31
31
32 from mercurial import util, cmdutil
32 from mercurial import util, cmdutil
33 from mercurial.i18n import _
33 from mercurial.i18n import _
34 import errno, os, re
34 import errno, os, re
35
35
36 cmdtable = {}
36 cmdtable = {}
37 command = cmdutil.command(cmdtable)
37 command = cmdutil.command(cmdtable)
38 testedwith = 'internal'
38 testedwith = 'internal'
39 lastblackbox = None
39 lastblackbox = None
40
40
41 def wrapui(ui):
41 def wrapui(ui):
42 class blackboxui(ui.__class__):
42 class blackboxui(ui.__class__):
43 @util.propertycache
43 @util.propertycache
44 def track(self):
44 def track(self):
45 return self.configlist('blackbox', 'track', ['*'])
45 return self.configlist('blackbox', 'track', ['*'])
46
46
47 def _openlogfile(self):
47 def _openlogfile(self):
48 def rotate(oldpath, newpath):
48 def rotate(oldpath, newpath):
49 try:
49 try:
50 os.unlink(newpath)
50 os.unlink(newpath)
51 except OSError, err:
51 except OSError, err:
52 if err.errno != errno.ENOENT:
52 if err.errno != errno.ENOENT:
53 self.debug("warning: cannot remove '%s': %s\n" %
53 self.debug("warning: cannot remove '%s': %s\n" %
54 (newpath, err.strerror))
54 (newpath, err.strerror))
55 try:
55 try:
56 if newpath:
56 if newpath:
57 os.rename(oldpath, newpath)
57 os.rename(oldpath, newpath)
58 except OSError, err:
58 except OSError, err:
59 if err.errno != errno.ENOENT:
59 if err.errno != errno.ENOENT:
60 self.debug("warning: cannot rename '%s' to '%s': %s\n" %
60 self.debug("warning: cannot rename '%s' to '%s': %s\n" %
61 (newpath, oldpath, err.strerror))
61 (newpath, oldpath, err.strerror))
62
62
63 fp = self._bbopener('blackbox.log', 'a')
63 fp = self._bbopener('blackbox.log', 'a')
64 maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
64 maxsize = self.configbytes('blackbox', 'maxsize', 1048576)
65 if maxsize > 0:
65 if maxsize > 0:
66 st = os.fstat(fp.fileno())
66 st = os.fstat(fp.fileno())
67 if st.st_size >= maxsize:
67 if st.st_size >= maxsize:
68 path = fp.name
68 path = fp.name
69 fp.close()
69 fp.close()
70 maxfiles = self.configint('blackbox', 'maxfiles', 7)
70 maxfiles = self.configint('blackbox', 'maxfiles', 7)
71 for i in xrange(maxfiles - 1, 1, -1):
71 for i in xrange(maxfiles - 1, 1, -1):
72 rotate(oldpath='%s.%d' % (path, i - 1),
72 rotate(oldpath='%s.%d' % (path, i - 1),
73 newpath='%s.%d' % (path, i))
73 newpath='%s.%d' % (path, i))
74 rotate(oldpath=path,
74 rotate(oldpath=path,
75 newpath=maxfiles > 0 and path + '.1')
75 newpath=maxfiles > 0 and path + '.1')
76 fp = self._bbopener('blackbox.log', 'a')
76 fp = self._bbopener('blackbox.log', 'a')
77 return fp
77 return fp
78
78
79 def log(self, event, *msg, **opts):
79 def log(self, event, *msg, **opts):
80 global lastblackbox
80 global lastblackbox
81 super(blackboxui, self).log(event, *msg, **opts)
81 super(blackboxui, self).log(event, *msg, **opts)
82
82
83 if not '*' in self.track and not event in self.track:
83 if not '*' in self.track and not event in self.track:
84 return
84 return
85
85
86 if util.safehasattr(self, '_blackbox'):
86 if util.safehasattr(self, '_blackbox'):
87 blackbox = self._blackbox
87 blackbox = self._blackbox
88 elif util.safehasattr(self, '_bbopener'):
88 elif util.safehasattr(self, '_bbopener'):
89 try:
89 try:
90 self._blackbox = self._openlogfile()
90 self._blackbox = self._openlogfile()
91 except (IOError, OSError), err:
91 except (IOError, OSError), err:
92 self.debug('warning: cannot write to blackbox.log: %s\n' %
92 self.debug('warning: cannot write to blackbox.log: %s\n' %
93 err.strerror)
93 err.strerror)
94 del self._bbopener
94 del self._bbopener
95 self._blackbox = None
95 self._blackbox = None
96 blackbox = self._blackbox
96 blackbox = self._blackbox
97 else:
97 else:
98 # certain ui instances exist outside the context of
98 # certain ui instances exist outside the context of
99 # a repo, so just default to the last blackbox that
99 # a repo, so just default to the last blackbox that
100 # was seen.
100 # was seen.
101 blackbox = lastblackbox
101 blackbox = lastblackbox
102
102
103 if blackbox:
103 if blackbox:
104 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
104 date = util.datestr(None, '%Y/%m/%d %H:%M:%S')
105 user = util.getuser()
105 user = util.getuser()
106 formattedmsg = msg[0] % msg[1:]
106 formattedmsg = msg[0] % msg[1:]
107 try:
107 try:
108 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
108 blackbox.write('%s %s> %s' % (date, user, formattedmsg))
109 except IOError, err:
109 except IOError, err:
110 self.debug('warning: cannot write to blackbox.log: %s\n' %
110 self.debug('warning: cannot write to blackbox.log: %s\n' %
111 err.strerror)
111 err.strerror)
112 lastblackbox = blackbox
112 lastblackbox = blackbox
113
113
114 def setrepo(self, repo):
114 def setrepo(self, repo):
115 self._bbopener = repo.opener
115 self._bbopener = repo.opener
116
116
117 ui.__class__ = blackboxui
117 ui.__class__ = blackboxui
118
118
119 def uisetup(ui):
119 def uisetup(ui):
120 wrapui(ui)
120 wrapui(ui)
121
121
122 def reposetup(ui, repo):
122 def reposetup(ui, repo):
123 # During 'hg pull' a httppeer repo is created to represent the remote repo.
123 # During 'hg pull' a httppeer repo is created to represent the remote repo.
124 # It doesn't have a .hg directory to put a blackbox in, so we don't do
124 # It doesn't have a .hg directory to put a blackbox in, so we don't do
125 # the blackbox setup for it.
125 # the blackbox setup for it.
126 if not repo.local():
126 if not repo.local():
127 return
127 return
128
128
129 ui.setrepo(repo)
129 if util.safehasattr(ui, 'setrepo'):
130 ui.setrepo(repo)
130
131
131 @command('^blackbox',
132 @command('^blackbox',
132 [('l', 'limit', 10, _('the number of events to show')),
133 [('l', 'limit', 10, _('the number of events to show')),
133 ],
134 ],
134 _('hg blackbox [OPTION]...'))
135 _('hg blackbox [OPTION]...'))
135 def blackbox(ui, repo, *revs, **opts):
136 def blackbox(ui, repo, *revs, **opts):
136 '''view the recent repository events
137 '''view the recent repository events
137 '''
138 '''
138
139
139 if not os.path.exists(repo.join('blackbox.log')):
140 if not os.path.exists(repo.join('blackbox.log')):
140 return
141 return
141
142
142 limit = opts.get('limit')
143 limit = opts.get('limit')
143 blackbox = repo.opener('blackbox.log', 'r')
144 blackbox = repo.opener('blackbox.log', 'r')
144 lines = blackbox.read().split('\n')
145 lines = blackbox.read().split('\n')
145
146
146 count = 0
147 count = 0
147 output = []
148 output = []
148 for line in reversed(lines):
149 for line in reversed(lines):
149 if count >= limit:
150 if count >= limit:
150 break
151 break
151
152
152 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
153 # count the commands by matching lines like: 2013/01/23 19:13:36 root>
153 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
154 if re.match('^\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} .*> .*', line):
154 count += 1
155 count += 1
155 output.append(line)
156 output.append(line)
156
157
157 ui.status('\n'.join(reversed(output)))
158 ui.status('\n'.join(reversed(output)))
@@ -1,5881 +1,5883 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, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 bheads = repo.branchheads(branch)
459 bheads = repo.branchheads(branch)
460 hg.clean(repo, node, show_stats=False)
460 hg.clean(repo, node, show_stats=False)
461 repo.dirstate.setbranch(branch)
461 repo.dirstate.setbranch(branch)
462 rctx = scmutil.revsingle(repo, hex(parent))
462 rctx = scmutil.revsingle(repo, hex(parent))
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
464 if not opts.get('merge') and op1 != node:
464 if not opts.get('merge') and op1 != node:
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.update(repo, op1)
467 return hg.update(repo, op1)
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470
470
471 e = cmdutil.commiteditor
471 e = cmdutil.commiteditor
472 if not opts['message'] and not opts['logfile']:
472 if not opts['message'] and not opts['logfile']:
473 # we don't translate commit messages
473 # we don't translate commit messages
474 opts['message'] = "Backed out changeset %s" % short(node)
474 opts['message'] = "Backed out changeset %s" % short(node)
475 e = cmdutil.commitforceeditor
475 e = cmdutil.commitforceeditor
476
476
477 def commitfunc(ui, repo, message, match, opts):
477 def commitfunc(ui, repo, message, match, opts):
478 return repo.commit(message, opts.get('user'), opts.get('date'),
478 return repo.commit(message, opts.get('user'), opts.get('date'),
479 match, editor=e)
479 match, editor=e)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
482
482
483 def nice(node):
483 def nice(node):
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
485 ui.status(_('changeset %s backs out changeset %s\n') %
485 ui.status(_('changeset %s backs out changeset %s\n') %
486 (nice(repo.changelog.tip()), nice(node)))
486 (nice(repo.changelog.tip()), nice(node)))
487 if opts.get('merge') and op1 != node:
487 if opts.get('merge') and op1 != node:
488 hg.clean(repo, op1, show_stats=False)
488 hg.clean(repo, op1, show_stats=False)
489 ui.status(_('merging with changeset %s\n')
489 ui.status(_('merging with changeset %s\n')
490 % nice(repo.changelog.tip()))
490 % nice(repo.changelog.tip()))
491 try:
491 try:
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
493 return hg.merge(repo, hex(repo.changelog.tip()))
493 return hg.merge(repo, hex(repo.changelog.tip()))
494 finally:
494 finally:
495 ui.setconfig('ui', 'forcemerge', '')
495 ui.setconfig('ui', 'forcemerge', '')
496 finally:
496 finally:
497 wlock.release()
497 wlock.release()
498 return 0
498 return 0
499
499
500 @command('bisect',
500 @command('bisect',
501 [('r', 'reset', False, _('reset bisect state')),
501 [('r', 'reset', False, _('reset bisect state')),
502 ('g', 'good', False, _('mark changeset good')),
502 ('g', 'good', False, _('mark changeset good')),
503 ('b', 'bad', False, _('mark changeset bad')),
503 ('b', 'bad', False, _('mark changeset bad')),
504 ('s', 'skip', False, _('skip testing changeset')),
504 ('s', 'skip', False, _('skip testing changeset')),
505 ('e', 'extend', False, _('extend the bisect range')),
505 ('e', 'extend', False, _('extend the bisect range')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
507 ('U', 'noupdate', False, _('do not update to target'))],
507 ('U', 'noupdate', False, _('do not update to target'))],
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
509 def bisect(ui, repo, rev=None, extra=None, command=None,
509 def bisect(ui, repo, rev=None, extra=None, command=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
511 noupdate=None):
511 noupdate=None):
512 """subdivision search of changesets
512 """subdivision search of changesets
513
513
514 This command helps to find changesets which introduce problems. To
514 This command helps to find changesets which introduce problems. To
515 use, mark the earliest changeset you know exhibits the problem as
515 use, mark the earliest changeset you know exhibits the problem as
516 bad, then mark the latest changeset which is free from the problem
516 bad, then mark the latest changeset which is free from the problem
517 as good. Bisect will update your working directory to a revision
517 as good. Bisect will update your working directory to a revision
518 for testing (unless the -U/--noupdate option is specified). Once
518 for testing (unless the -U/--noupdate option is specified). Once
519 you have performed tests, mark the working directory as good or
519 you have performed tests, mark the working directory as good or
520 bad, and bisect will either update to another candidate changeset
520 bad, and bisect will either update to another candidate changeset
521 or announce that it has found the bad revision.
521 or announce that it has found the bad revision.
522
522
523 As a shortcut, you can also use the revision argument to mark a
523 As a shortcut, you can also use the revision argument to mark a
524 revision as good or bad without checking it out first.
524 revision as good or bad without checking it out first.
525
525
526 If you supply a command, it will be used for automatic bisection.
526 If you supply a command, it will be used for automatic bisection.
527 The environment variable HG_NODE will contain the ID of the
527 The environment variable HG_NODE will contain the ID of the
528 changeset being tested. The exit status of the command will be
528 changeset being tested. The exit status of the command will be
529 used to mark revisions as good or bad: status 0 means good, 125
529 used to mark revisions as good or bad: status 0 means good, 125
530 means to skip the revision, 127 (command not found) will abort the
530 means to skip the revision, 127 (command not found) will abort the
531 bisection, and any other non-zero exit status means the revision
531 bisection, and any other non-zero exit status means the revision
532 is bad.
532 is bad.
533
533
534 .. container:: verbose
534 .. container:: verbose
535
535
536 Some examples:
536 Some examples:
537
537
538 - start a bisection with known bad revision 12, and good revision 34::
538 - start a bisection with known bad revision 12, and good revision 34::
539
539
540 hg bisect --bad 34
540 hg bisect --bad 34
541 hg bisect --good 12
541 hg bisect --good 12
542
542
543 - advance the current bisection by marking current revision as good or
543 - advance the current bisection by marking current revision as good or
544 bad::
544 bad::
545
545
546 hg bisect --good
546 hg bisect --good
547 hg bisect --bad
547 hg bisect --bad
548
548
549 - mark the current revision, or a known revision, to be skipped (e.g. if
549 - mark the current revision, or a known revision, to be skipped (e.g. if
550 that revision is not usable because of another issue)::
550 that revision is not usable because of another issue)::
551
551
552 hg bisect --skip
552 hg bisect --skip
553 hg bisect --skip 23
553 hg bisect --skip 23
554
554
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
556
556
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
558
558
559 - forget the current bisection::
559 - forget the current bisection::
560
560
561 hg bisect --reset
561 hg bisect --reset
562
562
563 - use 'make && make tests' to automatically find the first broken
563 - use 'make && make tests' to automatically find the first broken
564 revision::
564 revision::
565
565
566 hg bisect --reset
566 hg bisect --reset
567 hg bisect --bad 34
567 hg bisect --bad 34
568 hg bisect --good 12
568 hg bisect --good 12
569 hg bisect --command 'make && make tests'
569 hg bisect --command 'make && make tests'
570
570
571 - see all changesets whose states are already known in the current
571 - see all changesets whose states are already known in the current
572 bisection::
572 bisection::
573
573
574 hg log -r "bisect(pruned)"
574 hg log -r "bisect(pruned)"
575
575
576 - see the changeset currently being bisected (especially useful
576 - see the changeset currently being bisected (especially useful
577 if running with -U/--noupdate)::
577 if running with -U/--noupdate)::
578
578
579 hg log -r "bisect(current)"
579 hg log -r "bisect(current)"
580
580
581 - see all changesets that took part in the current bisection::
581 - see all changesets that took part in the current bisection::
582
582
583 hg log -r "bisect(range)"
583 hg log -r "bisect(range)"
584
584
585 - with the graphlog extension, you can even get a nice graph::
585 - with the graphlog extension, you can even get a nice graph::
586
586
587 hg log --graph -r "bisect(range)"
587 hg log --graph -r "bisect(range)"
588
588
589 See :hg:`help revsets` for more about the `bisect()` keyword.
589 See :hg:`help revsets` for more about the `bisect()` keyword.
590
590
591 Returns 0 on success.
591 Returns 0 on success.
592 """
592 """
593 def extendbisectrange(nodes, good):
593 def extendbisectrange(nodes, good):
594 # bisect is incomplete when it ends on a merge node and
594 # bisect is incomplete when it ends on a merge node and
595 # one of the parent was not checked.
595 # one of the parent was not checked.
596 parents = repo[nodes[0]].parents()
596 parents = repo[nodes[0]].parents()
597 if len(parents) > 1:
597 if len(parents) > 1:
598 side = good and state['bad'] or state['good']
598 side = good and state['bad'] or state['good']
599 num = len(set(i.node() for i in parents) & set(side))
599 num = len(set(i.node() for i in parents) & set(side))
600 if num == 1:
600 if num == 1:
601 return parents[0].ancestor(parents[1])
601 return parents[0].ancestor(parents[1])
602 return None
602 return None
603
603
604 def print_result(nodes, good):
604 def print_result(nodes, good):
605 displayer = cmdutil.show_changeset(ui, repo, {})
605 displayer = cmdutil.show_changeset(ui, repo, {})
606 if len(nodes) == 1:
606 if len(nodes) == 1:
607 # narrowed it down to a single revision
607 # narrowed it down to a single revision
608 if good:
608 if good:
609 ui.write(_("The first good revision is:\n"))
609 ui.write(_("The first good revision is:\n"))
610 else:
610 else:
611 ui.write(_("The first bad revision is:\n"))
611 ui.write(_("The first bad revision is:\n"))
612 displayer.show(repo[nodes[0]])
612 displayer.show(repo[nodes[0]])
613 extendnode = extendbisectrange(nodes, good)
613 extendnode = extendbisectrange(nodes, good)
614 if extendnode is not None:
614 if extendnode is not None:
615 ui.write(_('Not all ancestors of this changeset have been'
615 ui.write(_('Not all ancestors of this changeset have been'
616 ' checked.\nUse bisect --extend to continue the '
616 ' checked.\nUse bisect --extend to continue the '
617 'bisection from\nthe common ancestor, %s.\n')
617 'bisection from\nthe common ancestor, %s.\n')
618 % extendnode)
618 % extendnode)
619 else:
619 else:
620 # multiple possible revisions
620 # multiple possible revisions
621 if good:
621 if good:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "good revision could be any of:\n"))
623 "good revision could be any of:\n"))
624 else:
624 else:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "bad revision could be any of:\n"))
626 "bad revision could be any of:\n"))
627 for n in nodes:
627 for n in nodes:
628 displayer.show(repo[n])
628 displayer.show(repo[n])
629 displayer.close()
629 displayer.close()
630
630
631 def check_state(state, interactive=True):
631 def check_state(state, interactive=True):
632 if not state['good'] or not state['bad']:
632 if not state['good'] or not state['bad']:
633 if (good or bad or skip or reset) and interactive:
633 if (good or bad or skip or reset) and interactive:
634 return
634 return
635 if not state['good']:
635 if not state['good']:
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
637 else:
637 else:
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
639 return True
639 return True
640
640
641 # backward compatibility
641 # backward compatibility
642 if rev in "good bad reset init".split():
642 if rev in "good bad reset init".split():
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
644 cmd, rev, extra = rev, extra, None
644 cmd, rev, extra = rev, extra, None
645 if cmd == "good":
645 if cmd == "good":
646 good = True
646 good = True
647 elif cmd == "bad":
647 elif cmd == "bad":
648 bad = True
648 bad = True
649 else:
649 else:
650 reset = True
650 reset = True
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
652 raise util.Abort(_('incompatible arguments'))
652 raise util.Abort(_('incompatible arguments'))
653
653
654 if reset:
654 if reset:
655 p = repo.join("bisect.state")
655 p = repo.join("bisect.state")
656 if os.path.exists(p):
656 if os.path.exists(p):
657 os.unlink(p)
657 os.unlink(p)
658 return
658 return
659
659
660 state = hbisect.load_state(repo)
660 state = hbisect.load_state(repo)
661
661
662 if command:
662 if command:
663 changesets = 1
663 changesets = 1
664 try:
664 try:
665 node = state['current'][0]
665 node = state['current'][0]
666 except LookupError:
666 except LookupError:
667 if noupdate:
667 if noupdate:
668 raise util.Abort(_('current bisect revision is unknown - '
668 raise util.Abort(_('current bisect revision is unknown - '
669 'start a new bisect to fix'))
669 'start a new bisect to fix'))
670 node, p2 = repo.dirstate.parents()
670 node, p2 = repo.dirstate.parents()
671 if p2 != nullid:
671 if p2 != nullid:
672 raise util.Abort(_('current bisect revision is a merge'))
672 raise util.Abort(_('current bisect revision is a merge'))
673 try:
673 try:
674 while changesets:
674 while changesets:
675 # update state
675 # update state
676 state['current'] = [node]
676 state['current'] = [node]
677 hbisect.save_state(repo, state)
677 hbisect.save_state(repo, state)
678 status = util.system(command,
678 status = util.system(command,
679 environ={'HG_NODE': hex(node)},
679 environ={'HG_NODE': hex(node)},
680 out=ui.fout)
680 out=ui.fout)
681 if status == 125:
681 if status == 125:
682 transition = "skip"
682 transition = "skip"
683 elif status == 0:
683 elif status == 0:
684 transition = "good"
684 transition = "good"
685 # status < 0 means process was killed
685 # status < 0 means process was killed
686 elif status == 127:
686 elif status == 127:
687 raise util.Abort(_("failed to execute %s") % command)
687 raise util.Abort(_("failed to execute %s") % command)
688 elif status < 0:
688 elif status < 0:
689 raise util.Abort(_("%s killed") % command)
689 raise util.Abort(_("%s killed") % command)
690 else:
690 else:
691 transition = "bad"
691 transition = "bad"
692 ctx = scmutil.revsingle(repo, rev, node)
692 ctx = scmutil.revsingle(repo, rev, node)
693 rev = None # clear for future iterations
693 rev = None # clear for future iterations
694 state[transition].append(ctx.node())
694 state[transition].append(ctx.node())
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
696 check_state(state, interactive=False)
696 check_state(state, interactive=False)
697 # bisect
697 # bisect
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
699 # update to next check
699 # update to next check
700 node = nodes[0]
700 node = nodes[0]
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 finally:
704 finally:
705 state['current'] = [node]
705 state['current'] = [node]
706 hbisect.save_state(repo, state)
706 hbisect.save_state(repo, state)
707 print_result(nodes, good)
707 print_result(nodes, good)
708 return
708 return
709
709
710 # update state
710 # update state
711
711
712 if rev:
712 if rev:
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
714 else:
714 else:
715 nodes = [repo.lookup('.')]
715 nodes = [repo.lookup('.')]
716
716
717 if good or bad or skip:
717 if good or bad or skip:
718 if good:
718 if good:
719 state['good'] += nodes
719 state['good'] += nodes
720 elif bad:
720 elif bad:
721 state['bad'] += nodes
721 state['bad'] += nodes
722 elif skip:
722 elif skip:
723 state['skip'] += nodes
723 state['skip'] += nodes
724 hbisect.save_state(repo, state)
724 hbisect.save_state(repo, state)
725
725
726 if not check_state(state):
726 if not check_state(state):
727 return
727 return
728
728
729 # actually bisect
729 # actually bisect
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
731 if extend:
731 if extend:
732 if not changesets:
732 if not changesets:
733 extendnode = extendbisectrange(nodes, good)
733 extendnode = extendbisectrange(nodes, good)
734 if extendnode is not None:
734 if extendnode is not None:
735 ui.write(_("Extending search to changeset %d:%s\n"
735 ui.write(_("Extending search to changeset %d:%s\n"
736 % (extendnode.rev(), extendnode)))
736 % (extendnode.rev(), extendnode)))
737 state['current'] = [extendnode.node()]
737 state['current'] = [extendnode.node()]
738 hbisect.save_state(repo, state)
738 hbisect.save_state(repo, state)
739 if noupdate:
739 if noupdate:
740 return
740 return
741 cmdutil.bailifchanged(repo)
741 cmdutil.bailifchanged(repo)
742 return hg.clean(repo, extendnode.node())
742 return hg.clean(repo, extendnode.node())
743 raise util.Abort(_("nothing to extend"))
743 raise util.Abort(_("nothing to extend"))
744
744
745 if changesets == 0:
745 if changesets == 0:
746 print_result(nodes, good)
746 print_result(nodes, good)
747 else:
747 else:
748 assert len(nodes) == 1 # only a single node can be tested next
748 assert len(nodes) == 1 # only a single node can be tested next
749 node = nodes[0]
749 node = nodes[0]
750 # compute the approximate number of remaining tests
750 # compute the approximate number of remaining tests
751 tests, size = 0, 2
751 tests, size = 0, 2
752 while size <= changesets:
752 while size <= changesets:
753 tests, size = tests + 1, size * 2
753 tests, size = tests + 1, size * 2
754 rev = repo.changelog.rev(node)
754 rev = repo.changelog.rev(node)
755 ui.write(_("Testing changeset %d:%s "
755 ui.write(_("Testing changeset %d:%s "
756 "(%d changesets remaining, ~%d tests)\n")
756 "(%d changesets remaining, ~%d tests)\n")
757 % (rev, short(node), changesets, tests))
757 % (rev, short(node), changesets, tests))
758 state['current'] = [node]
758 state['current'] = [node]
759 hbisect.save_state(repo, state)
759 hbisect.save_state(repo, state)
760 if not noupdate:
760 if not noupdate:
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, node)
762 return hg.clean(repo, node)
763
763
764 @command('bookmarks|bookmark',
764 @command('bookmarks|bookmark',
765 [('f', 'force', False, _('force')),
765 [('f', 'force', False, _('force')),
766 ('r', 'rev', '', _('revision'), _('REV')),
766 ('r', 'rev', '', _('revision'), _('REV')),
767 ('d', 'delete', False, _('delete a given bookmark')),
767 ('d', 'delete', False, _('delete a given bookmark')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
770 _('hg bookmarks [OPTIONS]... [NAME]...'))
770 _('hg bookmarks [OPTIONS]... [NAME]...'))
771 def bookmark(ui, repo, *names, **opts):
771 def bookmark(ui, repo, *names, **opts):
772 '''track a line of development with movable markers
772 '''track a line of development with movable markers
773
773
774 Bookmarks are pointers to certain commits that move when committing.
774 Bookmarks are pointers to certain commits that move when committing.
775 Bookmarks are local. They can be renamed, copied and deleted. It is
775 Bookmarks are local. They can be renamed, copied and deleted. It is
776 possible to use :hg:`merge NAME` to merge from a given bookmark, and
776 possible to use :hg:`merge NAME` to merge from a given bookmark, and
777 :hg:`update NAME` to update to a given bookmark.
777 :hg:`update NAME` to update to a given bookmark.
778
778
779 You can use :hg:`bookmark NAME` to set a bookmark on the working
779 You can use :hg:`bookmark NAME` to set a bookmark on the working
780 directory's parent revision with the given name. If you specify
780 directory's parent revision with the given name. If you specify
781 a revision using -r REV (where REV may be an existing bookmark),
781 a revision using -r REV (where REV may be an existing bookmark),
782 the bookmark is assigned to that revision.
782 the bookmark is assigned to that revision.
783
783
784 Bookmarks can be pushed and pulled between repositories (see :hg:`help
784 Bookmarks can be pushed and pulled between repositories (see :hg:`help
785 push` and :hg:`help pull`). This requires both the local and remote
785 push` and :hg:`help pull`). This requires both the local and remote
786 repositories to support bookmarks. For versions prior to 1.8, this means
786 repositories to support bookmarks. For versions prior to 1.8, this means
787 the bookmarks extension must be enabled.
787 the bookmarks extension must be enabled.
788
788
789 If you set a bookmark called '@', new clones of the repository will
789 If you set a bookmark called '@', new clones of the repository will
790 have that revision checked out (and the bookmark made active) by
790 have that revision checked out (and the bookmark made active) by
791 default.
791 default.
792
792
793 With -i/--inactive, the new bookmark will not be made the active
793 With -i/--inactive, the new bookmark will not be made the active
794 bookmark. If -r/--rev is given, the new bookmark will not be made
794 bookmark. If -r/--rev is given, the new bookmark will not be made
795 active even if -i/--inactive is not given. If no NAME is given, the
795 active even if -i/--inactive is not given. If no NAME is given, the
796 current active bookmark will be marked inactive.
796 current active bookmark will be marked inactive.
797 '''
797 '''
798 force = opts.get('force')
798 force = opts.get('force')
799 rev = opts.get('rev')
799 rev = opts.get('rev')
800 delete = opts.get('delete')
800 delete = opts.get('delete')
801 rename = opts.get('rename')
801 rename = opts.get('rename')
802 inactive = opts.get('inactive')
802 inactive = opts.get('inactive')
803
803
804 hexfn = ui.debugflag and hex or short
804 hexfn = ui.debugflag and hex or short
805 marks = repo._bookmarks
805 marks = repo._bookmarks
806 cur = repo.changectx('.').node()
806 cur = repo.changectx('.').node()
807
807
808 def checkformat(mark):
808 def checkformat(mark):
809 mark = mark.strip()
809 mark = mark.strip()
810 if not mark:
810 if not mark:
811 raise util.Abort(_("bookmark names cannot consist entirely of "
811 raise util.Abort(_("bookmark names cannot consist entirely of "
812 "whitespace"))
812 "whitespace"))
813 scmutil.checknewlabel(repo, mark, 'bookmark')
813 scmutil.checknewlabel(repo, mark, 'bookmark')
814 return mark
814 return mark
815
815
816 def checkconflict(repo, mark, force=False, target=None):
816 def checkconflict(repo, mark, force=False, target=None):
817 if mark in marks and not force:
817 if mark in marks and not force:
818 if target:
818 if target:
819 if marks[mark] == target and target == cur:
819 if marks[mark] == target and target == cur:
820 # re-activating a bookmark
820 # re-activating a bookmark
821 return
821 return
822 anc = repo.changelog.ancestors([repo[target].rev()])
822 anc = repo.changelog.ancestors([repo[target].rev()])
823 bmctx = repo[marks[mark]]
823 bmctx = repo[marks[mark]]
824 divs = [repo[b].node() for b in marks
824 divs = [repo[b].node() for b in marks
825 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
825 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
826
826
827 # allow resolving a single divergent bookmark even if moving
827 # allow resolving a single divergent bookmark even if moving
828 # the bookmark across branches when a revision is specified
828 # the bookmark across branches when a revision is specified
829 # that contains a divergent bookmark
829 # that contains a divergent bookmark
830 if bmctx.rev() not in anc and target in divs:
830 if bmctx.rev() not in anc and target in divs:
831 bookmarks.deletedivergent(repo, [target], mark)
831 bookmarks.deletedivergent(repo, [target], mark)
832 return
832 return
833
833
834 deletefrom = [b for b in divs
834 deletefrom = [b for b in divs
835 if repo[b].rev() in anc or b == target]
835 if repo[b].rev() in anc or b == target]
836 bookmarks.deletedivergent(repo, deletefrom, mark)
836 bookmarks.deletedivergent(repo, deletefrom, mark)
837 if bmctx.rev() in anc:
837 if bmctx.rev() in anc:
838 ui.status(_("moving bookmark '%s' forward from %s\n") %
838 ui.status(_("moving bookmark '%s' forward from %s\n") %
839 (mark, short(bmctx.node())))
839 (mark, short(bmctx.node())))
840 return
840 return
841 raise util.Abort(_("bookmark '%s' already exists "
841 raise util.Abort(_("bookmark '%s' already exists "
842 "(use -f to force)") % mark)
842 "(use -f to force)") % mark)
843 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
843 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
844 and not force):
844 and not force):
845 raise util.Abort(
845 raise util.Abort(
846 _("a bookmark cannot have the name of an existing branch"))
846 _("a bookmark cannot have the name of an existing branch"))
847
847
848 if delete and rename:
848 if delete and rename:
849 raise util.Abort(_("--delete and --rename are incompatible"))
849 raise util.Abort(_("--delete and --rename are incompatible"))
850 if delete and rev:
850 if delete and rev:
851 raise util.Abort(_("--rev is incompatible with --delete"))
851 raise util.Abort(_("--rev is incompatible with --delete"))
852 if rename and rev:
852 if rename and rev:
853 raise util.Abort(_("--rev is incompatible with --rename"))
853 raise util.Abort(_("--rev is incompatible with --rename"))
854 if not names and (delete or rev):
854 if not names and (delete or rev):
855 raise util.Abort(_("bookmark name required"))
855 raise util.Abort(_("bookmark name required"))
856
856
857 if delete:
857 if delete:
858 for mark in names:
858 for mark in names:
859 if mark not in marks:
859 if mark not in marks:
860 raise util.Abort(_("bookmark '%s' does not exist") % mark)
860 raise util.Abort(_("bookmark '%s' does not exist") % mark)
861 if mark == repo._bookmarkcurrent:
861 if mark == repo._bookmarkcurrent:
862 bookmarks.setcurrent(repo, None)
862 bookmarks.setcurrent(repo, None)
863 del marks[mark]
863 del marks[mark]
864 marks.write()
864 marks.write()
865
865
866 elif rename:
866 elif rename:
867 if not names:
867 if not names:
868 raise util.Abort(_("new bookmark name required"))
868 raise util.Abort(_("new bookmark name required"))
869 elif len(names) > 1:
869 elif len(names) > 1:
870 raise util.Abort(_("only one new bookmark name allowed"))
870 raise util.Abort(_("only one new bookmark name allowed"))
871 mark = checkformat(names[0])
871 mark = checkformat(names[0])
872 if rename not in marks:
872 if rename not in marks:
873 raise util.Abort(_("bookmark '%s' does not exist") % rename)
873 raise util.Abort(_("bookmark '%s' does not exist") % rename)
874 checkconflict(repo, mark, force)
874 checkconflict(repo, mark, force)
875 marks[mark] = marks[rename]
875 marks[mark] = marks[rename]
876 if repo._bookmarkcurrent == rename and not inactive:
876 if repo._bookmarkcurrent == rename and not inactive:
877 bookmarks.setcurrent(repo, mark)
877 bookmarks.setcurrent(repo, mark)
878 del marks[rename]
878 del marks[rename]
879 marks.write()
879 marks.write()
880
880
881 elif names:
881 elif names:
882 newact = None
882 newact = None
883 for mark in names:
883 for mark in names:
884 mark = checkformat(mark)
884 mark = checkformat(mark)
885 if newact is None:
885 if newact is None:
886 newact = mark
886 newact = mark
887 if inactive and mark == repo._bookmarkcurrent:
887 if inactive and mark == repo._bookmarkcurrent:
888 bookmarks.setcurrent(repo, None)
888 bookmarks.setcurrent(repo, None)
889 return
889 return
890 tgt = cur
890 tgt = cur
891 if rev:
891 if rev:
892 tgt = scmutil.revsingle(repo, rev).node()
892 tgt = scmutil.revsingle(repo, rev).node()
893 checkconflict(repo, mark, force, tgt)
893 checkconflict(repo, mark, force, tgt)
894 marks[mark] = tgt
894 marks[mark] = tgt
895 if not inactive and cur == marks[newact] and not rev:
895 if not inactive and cur == marks[newact] and not rev:
896 bookmarks.setcurrent(repo, newact)
896 bookmarks.setcurrent(repo, newact)
897 elif cur != tgt and newact == repo._bookmarkcurrent:
897 elif cur != tgt and newact == repo._bookmarkcurrent:
898 bookmarks.setcurrent(repo, None)
898 bookmarks.setcurrent(repo, None)
899 marks.write()
899 marks.write()
900
900
901 # Same message whether trying to deactivate the current bookmark (-i
901 # Same message whether trying to deactivate the current bookmark (-i
902 # with no NAME) or listing bookmarks
902 # with no NAME) or listing bookmarks
903 elif len(marks) == 0:
903 elif len(marks) == 0:
904 ui.status(_("no bookmarks set\n"))
904 ui.status(_("no bookmarks set\n"))
905
905
906 elif inactive:
906 elif inactive:
907 if not repo._bookmarkcurrent:
907 if not repo._bookmarkcurrent:
908 ui.status(_("no active bookmark\n"))
908 ui.status(_("no active bookmark\n"))
909 else:
909 else:
910 bookmarks.setcurrent(repo, None)
910 bookmarks.setcurrent(repo, None)
911
911
912 else: # show bookmarks
912 else: # show bookmarks
913 for bmark, n in sorted(marks.iteritems()):
913 for bmark, n in sorted(marks.iteritems()):
914 current = repo._bookmarkcurrent
914 current = repo._bookmarkcurrent
915 if bmark == current:
915 if bmark == current:
916 prefix, label = '*', 'bookmarks.current'
916 prefix, label = '*', 'bookmarks.current'
917 else:
917 else:
918 prefix, label = ' ', ''
918 prefix, label = ' ', ''
919
919
920 if ui.quiet:
920 if ui.quiet:
921 ui.write("%s\n" % bmark, label=label)
921 ui.write("%s\n" % bmark, label=label)
922 else:
922 else:
923 ui.write(" %s %-25s %d:%s\n" % (
923 ui.write(" %s %-25s %d:%s\n" % (
924 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
924 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
925 label=label)
925 label=label)
926
926
927 @command('branch',
927 @command('branch',
928 [('f', 'force', None,
928 [('f', 'force', None,
929 _('set branch name even if it shadows an existing branch')),
929 _('set branch name even if it shadows an existing branch')),
930 ('C', 'clean', None, _('reset branch name to parent branch name'))],
930 ('C', 'clean', None, _('reset branch name to parent branch name'))],
931 _('[-fC] [NAME]'))
931 _('[-fC] [NAME]'))
932 def branch(ui, repo, label=None, **opts):
932 def branch(ui, repo, label=None, **opts):
933 """set or show the current branch name
933 """set or show the current branch name
934
934
935 .. note::
935 .. note::
936 Branch names are permanent and global. Use :hg:`bookmark` to create a
936 Branch names are permanent and global. Use :hg:`bookmark` to create a
937 light-weight bookmark instead. See :hg:`help glossary` for more
937 light-weight bookmark instead. See :hg:`help glossary` for more
938 information about named branches and bookmarks.
938 information about named branches and bookmarks.
939
939
940 With no argument, show the current branch name. With one argument,
940 With no argument, show the current branch name. With one argument,
941 set the working directory branch name (the branch will not exist
941 set the working directory branch name (the branch will not exist
942 in the repository until the next commit). Standard practice
942 in the repository until the next commit). Standard practice
943 recommends that primary development take place on the 'default'
943 recommends that primary development take place on the 'default'
944 branch.
944 branch.
945
945
946 Unless -f/--force is specified, branch will not let you set a
946 Unless -f/--force is specified, branch will not let you set a
947 branch name that already exists, even if it's inactive.
947 branch name that already exists, even if it's inactive.
948
948
949 Use -C/--clean to reset the working directory branch to that of
949 Use -C/--clean to reset the working directory branch to that of
950 the parent of the working directory, negating a previous branch
950 the parent of the working directory, negating a previous branch
951 change.
951 change.
952
952
953 Use the command :hg:`update` to switch to an existing branch. Use
953 Use the command :hg:`update` to switch to an existing branch. Use
954 :hg:`commit --close-branch` to mark this branch as closed.
954 :hg:`commit --close-branch` to mark this branch as closed.
955
955
956 Returns 0 on success.
956 Returns 0 on success.
957 """
957 """
958 if label:
958 if label:
959 label = label.strip()
959 label = label.strip()
960
960
961 if not opts.get('clean') and not label:
961 if not opts.get('clean') and not label:
962 ui.write("%s\n" % repo.dirstate.branch())
962 ui.write("%s\n" % repo.dirstate.branch())
963 return
963 return
964
964
965 wlock = repo.wlock()
965 wlock = repo.wlock()
966 try:
966 try:
967 if opts.get('clean'):
967 if opts.get('clean'):
968 label = repo[None].p1().branch()
968 label = repo[None].p1().branch()
969 repo.dirstate.setbranch(label)
969 repo.dirstate.setbranch(label)
970 ui.status(_('reset working directory to branch %s\n') % label)
970 ui.status(_('reset working directory to branch %s\n') % label)
971 elif label:
971 elif label:
972 if not opts.get('force') and label in repo.branchmap():
972 if not opts.get('force') and label in repo.branchmap():
973 if label not in [p.branch() for p in repo.parents()]:
973 if label not in [p.branch() for p in repo.parents()]:
974 raise util.Abort(_('a branch of the same name already'
974 raise util.Abort(_('a branch of the same name already'
975 ' exists'),
975 ' exists'),
976 # i18n: "it" refers to an existing branch
976 # i18n: "it" refers to an existing branch
977 hint=_("use 'hg update' to switch to it"))
977 hint=_("use 'hg update' to switch to it"))
978 scmutil.checknewlabel(repo, label, 'branch')
978 scmutil.checknewlabel(repo, label, 'branch')
979 repo.dirstate.setbranch(label)
979 repo.dirstate.setbranch(label)
980 ui.status(_('marked working directory as branch %s\n') % label)
980 ui.status(_('marked working directory as branch %s\n') % label)
981 ui.status(_('(branches are permanent and global, '
981 ui.status(_('(branches are permanent and global, '
982 'did you want a bookmark?)\n'))
982 'did you want a bookmark?)\n'))
983 finally:
983 finally:
984 wlock.release()
984 wlock.release()
985
985
986 @command('branches',
986 @command('branches',
987 [('a', 'active', False, _('show only branches that have unmerged heads')),
987 [('a', 'active', False, _('show only branches that have unmerged heads')),
988 ('c', 'closed', False, _('show normal and closed branches'))],
988 ('c', 'closed', False, _('show normal and closed branches'))],
989 _('[-ac]'))
989 _('[-ac]'))
990 def branches(ui, repo, active=False, closed=False):
990 def branches(ui, repo, active=False, closed=False):
991 """list repository named branches
991 """list repository named branches
992
992
993 List the repository's named branches, indicating which ones are
993 List the repository's named branches, indicating which ones are
994 inactive. If -c/--closed is specified, also list branches which have
994 inactive. If -c/--closed is specified, also list branches which have
995 been marked closed (see :hg:`commit --close-branch`).
995 been marked closed (see :hg:`commit --close-branch`).
996
996
997 If -a/--active is specified, only show active branches. A branch
997 If -a/--active is specified, only show active branches. A branch
998 is considered active if it contains repository heads.
998 is considered active if it contains repository heads.
999
999
1000 Use the command :hg:`update` to switch to an existing branch.
1000 Use the command :hg:`update` to switch to an existing branch.
1001
1001
1002 Returns 0.
1002 Returns 0.
1003 """
1003 """
1004
1004
1005 hexfunc = ui.debugflag and hex or short
1005 hexfunc = ui.debugflag and hex or short
1006
1006
1007 activebranches = set([repo[n].branch() for n in repo.heads()])
1007 activebranches = set([repo[n].branch() for n in repo.heads()])
1008 branches = []
1008 branches = []
1009 for tag, heads in repo.branchmap().iteritems():
1009 for tag, heads in repo.branchmap().iteritems():
1010 for h in reversed(heads):
1010 for h in reversed(heads):
1011 ctx = repo[h]
1011 ctx = repo[h]
1012 isopen = not ctx.closesbranch()
1012 isopen = not ctx.closesbranch()
1013 if isopen:
1013 if isopen:
1014 tip = ctx
1014 tip = ctx
1015 break
1015 break
1016 else:
1016 else:
1017 tip = repo[heads[-1]]
1017 tip = repo[heads[-1]]
1018 isactive = tag in activebranches and isopen
1018 isactive = tag in activebranches and isopen
1019 branches.append((tip, isactive, isopen))
1019 branches.append((tip, isactive, isopen))
1020 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1020 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1021 reverse=True)
1021 reverse=True)
1022
1022
1023 for ctx, isactive, isopen in branches:
1023 for ctx, isactive, isopen in branches:
1024 if (not active) or isactive:
1024 if (not active) or isactive:
1025 if isactive:
1025 if isactive:
1026 label = 'branches.active'
1026 label = 'branches.active'
1027 notice = ''
1027 notice = ''
1028 elif not isopen:
1028 elif not isopen:
1029 if not closed:
1029 if not closed:
1030 continue
1030 continue
1031 label = 'branches.closed'
1031 label = 'branches.closed'
1032 notice = _(' (closed)')
1032 notice = _(' (closed)')
1033 else:
1033 else:
1034 label = 'branches.inactive'
1034 label = 'branches.inactive'
1035 notice = _(' (inactive)')
1035 notice = _(' (inactive)')
1036 if ctx.branch() == repo.dirstate.branch():
1036 if ctx.branch() == repo.dirstate.branch():
1037 label = 'branches.current'
1037 label = 'branches.current'
1038 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1038 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1039 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1039 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1040 'log.changeset changeset.%s' % ctx.phasestr())
1040 'log.changeset changeset.%s' % ctx.phasestr())
1041 tag = ui.label(ctx.branch(), label)
1041 tag = ui.label(ctx.branch(), label)
1042 if ui.quiet:
1042 if ui.quiet:
1043 ui.write("%s\n" % tag)
1043 ui.write("%s\n" % tag)
1044 else:
1044 else:
1045 ui.write("%s %s%s\n" % (tag, rev, notice))
1045 ui.write("%s %s%s\n" % (tag, rev, notice))
1046
1046
1047 @command('bundle',
1047 @command('bundle',
1048 [('f', 'force', None, _('run even when the destination is unrelated')),
1048 [('f', 'force', None, _('run even when the destination is unrelated')),
1049 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1049 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1050 _('REV')),
1050 _('REV')),
1051 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1051 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1052 _('BRANCH')),
1052 _('BRANCH')),
1053 ('', 'base', [],
1053 ('', 'base', [],
1054 _('a base changeset assumed to be available at the destination'),
1054 _('a base changeset assumed to be available at the destination'),
1055 _('REV')),
1055 _('REV')),
1056 ('a', 'all', None, _('bundle all changesets in the repository')),
1056 ('a', 'all', None, _('bundle all changesets in the repository')),
1057 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1057 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1058 ] + remoteopts,
1058 ] + remoteopts,
1059 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1059 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1060 def bundle(ui, repo, fname, dest=None, **opts):
1060 def bundle(ui, repo, fname, dest=None, **opts):
1061 """create a changegroup file
1061 """create a changegroup file
1062
1062
1063 Generate a compressed changegroup file collecting changesets not
1063 Generate a compressed changegroup file collecting changesets not
1064 known to be in another repository.
1064 known to be in another repository.
1065
1065
1066 If you omit the destination repository, then hg assumes the
1066 If you omit the destination repository, then hg assumes the
1067 destination will have all the nodes you specify with --base
1067 destination will have all the nodes you specify with --base
1068 parameters. To create a bundle containing all changesets, use
1068 parameters. To create a bundle containing all changesets, use
1069 -a/--all (or --base null).
1069 -a/--all (or --base null).
1070
1070
1071 You can change compression method with the -t/--type option.
1071 You can change compression method with the -t/--type option.
1072 The available compression methods are: none, bzip2, and
1072 The available compression methods are: none, bzip2, and
1073 gzip (by default, bundles are compressed using bzip2).
1073 gzip (by default, bundles are compressed using bzip2).
1074
1074
1075 The bundle file can then be transferred using conventional means
1075 The bundle file can then be transferred using conventional means
1076 and applied to another repository with the unbundle or pull
1076 and applied to another repository with the unbundle or pull
1077 command. This is useful when direct push and pull are not
1077 command. This is useful when direct push and pull are not
1078 available or when exporting an entire repository is undesirable.
1078 available or when exporting an entire repository is undesirable.
1079
1079
1080 Applying bundles preserves all changeset contents including
1080 Applying bundles preserves all changeset contents including
1081 permissions, copy/rename information, and revision history.
1081 permissions, copy/rename information, and revision history.
1082
1082
1083 Returns 0 on success, 1 if no changes found.
1083 Returns 0 on success, 1 if no changes found.
1084 """
1084 """
1085 revs = None
1085 revs = None
1086 if 'rev' in opts:
1086 if 'rev' in opts:
1087 revs = scmutil.revrange(repo, opts['rev'])
1087 revs = scmutil.revrange(repo, opts['rev'])
1088
1088
1089 bundletype = opts.get('type', 'bzip2').lower()
1089 bundletype = opts.get('type', 'bzip2').lower()
1090 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1090 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1091 bundletype = btypes.get(bundletype)
1091 bundletype = btypes.get(bundletype)
1092 if bundletype not in changegroup.bundletypes:
1092 if bundletype not in changegroup.bundletypes:
1093 raise util.Abort(_('unknown bundle type specified with --type'))
1093 raise util.Abort(_('unknown bundle type specified with --type'))
1094
1094
1095 if opts.get('all'):
1095 if opts.get('all'):
1096 base = ['null']
1096 base = ['null']
1097 else:
1097 else:
1098 base = scmutil.revrange(repo, opts.get('base'))
1098 base = scmutil.revrange(repo, opts.get('base'))
1099 # TODO: get desired bundlecaps from command line.
1099 # TODO: get desired bundlecaps from command line.
1100 bundlecaps = None
1100 bundlecaps = None
1101 if base:
1101 if base:
1102 if dest:
1102 if dest:
1103 raise util.Abort(_("--base is incompatible with specifying "
1103 raise util.Abort(_("--base is incompatible with specifying "
1104 "a destination"))
1104 "a destination"))
1105 common = [repo.lookup(rev) for rev in base]
1105 common = [repo.lookup(rev) for rev in base]
1106 heads = revs and map(repo.lookup, revs) or revs
1106 heads = revs and map(repo.lookup, revs) or revs
1107 cg = repo.getbundle('bundle', heads=heads, common=common,
1107 cg = repo.getbundle('bundle', heads=heads, common=common,
1108 bundlecaps=bundlecaps)
1108 bundlecaps=bundlecaps)
1109 outgoing = None
1109 outgoing = None
1110 else:
1110 else:
1111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1112 dest, branches = hg.parseurl(dest, opts.get('branch'))
1112 dest, branches = hg.parseurl(dest, opts.get('branch'))
1113 other = hg.peer(repo, opts, dest)
1113 other = hg.peer(repo, opts, dest)
1114 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1114 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1115 heads = revs and map(repo.lookup, revs) or revs
1115 heads = revs and map(repo.lookup, revs) or revs
1116 outgoing = discovery.findcommonoutgoing(repo, other,
1116 outgoing = discovery.findcommonoutgoing(repo, other,
1117 onlyheads=heads,
1117 onlyheads=heads,
1118 force=opts.get('force'),
1118 force=opts.get('force'),
1119 portable=True)
1119 portable=True)
1120 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1120 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1121 if not cg:
1121 if not cg:
1122 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1122 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1123 return 1
1123 return 1
1124
1124
1125 changegroup.writebundle(cg, fname, bundletype)
1125 changegroup.writebundle(cg, fname, bundletype)
1126
1126
1127 @command('cat',
1127 @command('cat',
1128 [('o', 'output', '',
1128 [('o', 'output', '',
1129 _('print output to file with formatted name'), _('FORMAT')),
1129 _('print output to file with formatted name'), _('FORMAT')),
1130 ('r', 'rev', '', _('print the given revision'), _('REV')),
1130 ('r', 'rev', '', _('print the given revision'), _('REV')),
1131 ('', 'decode', None, _('apply any matching decode filter')),
1131 ('', 'decode', None, _('apply any matching decode filter')),
1132 ] + walkopts,
1132 ] + walkopts,
1133 _('[OPTION]... FILE...'))
1133 _('[OPTION]... FILE...'))
1134 def cat(ui, repo, file1, *pats, **opts):
1134 def cat(ui, repo, file1, *pats, **opts):
1135 """output the current or given revision of files
1135 """output the current or given revision of files
1136
1136
1137 Print the specified files as they were at the given revision. If
1137 Print the specified files as they were at the given revision. If
1138 no revision is given, the parent of the working directory is used,
1138 no revision is given, the parent of the working directory is used,
1139 or tip if no revision is checked out.
1139 or tip if no revision is checked out.
1140
1140
1141 Output may be to a file, in which case the name of the file is
1141 Output may be to a file, in which case the name of the file is
1142 given using a format string. The formatting rules are the same as
1142 given using a format string. The formatting rules are the same as
1143 for the export command, with the following additions:
1143 for the export command, with the following additions:
1144
1144
1145 :``%s``: basename of file being printed
1145 :``%s``: basename of file being printed
1146 :``%d``: dirname of file being printed, or '.' if in repository root
1146 :``%d``: dirname of file being printed, or '.' if in repository root
1147 :``%p``: root-relative path name of file being printed
1147 :``%p``: root-relative path name of file being printed
1148
1148
1149 Returns 0 on success.
1149 Returns 0 on success.
1150 """
1150 """
1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1152 err = 1
1152 err = 1
1153 m = scmutil.match(ctx, (file1,) + pats, opts)
1153 m = scmutil.match(ctx, (file1,) + pats, opts)
1154 for abs in ctx.walk(m):
1154 for abs in ctx.walk(m):
1155 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1155 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1156 pathname=abs)
1156 pathname=abs)
1157 data = ctx[abs].data()
1157 data = ctx[abs].data()
1158 if opts.get('decode'):
1158 if opts.get('decode'):
1159 data = repo.wwritedata(abs, data)
1159 data = repo.wwritedata(abs, data)
1160 fp.write(data)
1160 fp.write(data)
1161 fp.close()
1161 fp.close()
1162 err = 0
1162 err = 0
1163 return err
1163 return err
1164
1164
1165 @command('^clone',
1165 @command('^clone',
1166 [('U', 'noupdate', None,
1166 [('U', 'noupdate', None,
1167 _('the clone will include an empty working copy (only a repository)')),
1167 _('the clone will include an empty working copy (only a repository)')),
1168 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1168 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1169 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1169 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1170 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1170 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1171 ('', 'pull', None, _('use pull protocol to copy metadata')),
1171 ('', 'pull', None, _('use pull protocol to copy metadata')),
1172 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1172 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1173 ] + remoteopts,
1173 ] + remoteopts,
1174 _('[OPTION]... SOURCE [DEST]'))
1174 _('[OPTION]... SOURCE [DEST]'))
1175 def clone(ui, source, dest=None, **opts):
1175 def clone(ui, source, dest=None, **opts):
1176 """make a copy of an existing repository
1176 """make a copy of an existing repository
1177
1177
1178 Create a copy of an existing repository in a new directory.
1178 Create a copy of an existing repository in a new directory.
1179
1179
1180 If no destination directory name is specified, it defaults to the
1180 If no destination directory name is specified, it defaults to the
1181 basename of the source.
1181 basename of the source.
1182
1182
1183 The location of the source is added to the new repository's
1183 The location of the source is added to the new repository's
1184 ``.hg/hgrc`` file, as the default to be used for future pulls.
1184 ``.hg/hgrc`` file, as the default to be used for future pulls.
1185
1185
1186 Only local paths and ``ssh://`` URLs are supported as
1186 Only local paths and ``ssh://`` URLs are supported as
1187 destinations. For ``ssh://`` destinations, no working directory or
1187 destinations. For ``ssh://`` destinations, no working directory or
1188 ``.hg/hgrc`` will be created on the remote side.
1188 ``.hg/hgrc`` will be created on the remote side.
1189
1189
1190 To pull only a subset of changesets, specify one or more revisions
1190 To pull only a subset of changesets, specify one or more revisions
1191 identifiers with -r/--rev or branches with -b/--branch. The
1191 identifiers with -r/--rev or branches with -b/--branch. The
1192 resulting clone will contain only the specified changesets and
1192 resulting clone will contain only the specified changesets and
1193 their ancestors. These options (or 'clone src#rev dest') imply
1193 their ancestors. These options (or 'clone src#rev dest') imply
1194 --pull, even for local source repositories. Note that specifying a
1194 --pull, even for local source repositories. Note that specifying a
1195 tag will include the tagged changeset but not the changeset
1195 tag will include the tagged changeset but not the changeset
1196 containing the tag.
1196 containing the tag.
1197
1197
1198 If the source repository has a bookmark called '@' set, that
1198 If the source repository has a bookmark called '@' set, that
1199 revision will be checked out in the new repository by default.
1199 revision will be checked out in the new repository by default.
1200
1200
1201 To check out a particular version, use -u/--update, or
1201 To check out a particular version, use -u/--update, or
1202 -U/--noupdate to create a clone with no working directory.
1202 -U/--noupdate to create a clone with no working directory.
1203
1203
1204 .. container:: verbose
1204 .. container:: verbose
1205
1205
1206 For efficiency, hardlinks are used for cloning whenever the
1206 For efficiency, hardlinks are used for cloning whenever the
1207 source and destination are on the same filesystem (note this
1207 source and destination are on the same filesystem (note this
1208 applies only to the repository data, not to the working
1208 applies only to the repository data, not to the working
1209 directory). Some filesystems, such as AFS, implement hardlinking
1209 directory). Some filesystems, such as AFS, implement hardlinking
1210 incorrectly, but do not report errors. In these cases, use the
1210 incorrectly, but do not report errors. In these cases, use the
1211 --pull option to avoid hardlinking.
1211 --pull option to avoid hardlinking.
1212
1212
1213 In some cases, you can clone repositories and the working
1213 In some cases, you can clone repositories and the working
1214 directory using full hardlinks with ::
1214 directory using full hardlinks with ::
1215
1215
1216 $ cp -al REPO REPOCLONE
1216 $ cp -al REPO REPOCLONE
1217
1217
1218 This is the fastest way to clone, but it is not always safe. The
1218 This is the fastest way to clone, but it is not always safe. The
1219 operation is not atomic (making sure REPO is not modified during
1219 operation is not atomic (making sure REPO is not modified during
1220 the operation is up to you) and you have to make sure your
1220 the operation is up to you) and you have to make sure your
1221 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1221 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1222 so). Also, this is not compatible with certain extensions that
1222 so). Also, this is not compatible with certain extensions that
1223 place their metadata under the .hg directory, such as mq.
1223 place their metadata under the .hg directory, such as mq.
1224
1224
1225 Mercurial will update the working directory to the first applicable
1225 Mercurial will update the working directory to the first applicable
1226 revision from this list:
1226 revision from this list:
1227
1227
1228 a) null if -U or the source repository has no changesets
1228 a) null if -U or the source repository has no changesets
1229 b) if -u . and the source repository is local, the first parent of
1229 b) if -u . and the source repository is local, the first parent of
1230 the source repository's working directory
1230 the source repository's working directory
1231 c) the changeset specified with -u (if a branch name, this means the
1231 c) the changeset specified with -u (if a branch name, this means the
1232 latest head of that branch)
1232 latest head of that branch)
1233 d) the changeset specified with -r
1233 d) the changeset specified with -r
1234 e) the tipmost head specified with -b
1234 e) the tipmost head specified with -b
1235 f) the tipmost head specified with the url#branch source syntax
1235 f) the tipmost head specified with the url#branch source syntax
1236 g) the revision marked with the '@' bookmark, if present
1236 g) the revision marked with the '@' bookmark, if present
1237 h) the tipmost head of the default branch
1237 h) the tipmost head of the default branch
1238 i) tip
1238 i) tip
1239
1239
1240 Examples:
1240 Examples:
1241
1241
1242 - clone a remote repository to a new directory named hg/::
1242 - clone a remote repository to a new directory named hg/::
1243
1243
1244 hg clone http://selenic.com/hg
1244 hg clone http://selenic.com/hg
1245
1245
1246 - create a lightweight local clone::
1246 - create a lightweight local clone::
1247
1247
1248 hg clone project/ project-feature/
1248 hg clone project/ project-feature/
1249
1249
1250 - clone from an absolute path on an ssh server (note double-slash)::
1250 - clone from an absolute path on an ssh server (note double-slash)::
1251
1251
1252 hg clone ssh://user@server//home/projects/alpha/
1252 hg clone ssh://user@server//home/projects/alpha/
1253
1253
1254 - do a high-speed clone over a LAN while checking out a
1254 - do a high-speed clone over a LAN while checking out a
1255 specified version::
1255 specified version::
1256
1256
1257 hg clone --uncompressed http://server/repo -u 1.5
1257 hg clone --uncompressed http://server/repo -u 1.5
1258
1258
1259 - create a repository without changesets after a particular revision::
1259 - create a repository without changesets after a particular revision::
1260
1260
1261 hg clone -r 04e544 experimental/ good/
1261 hg clone -r 04e544 experimental/ good/
1262
1262
1263 - clone (and track) a particular named branch::
1263 - clone (and track) a particular named branch::
1264
1264
1265 hg clone http://selenic.com/hg#stable
1265 hg clone http://selenic.com/hg#stable
1266
1266
1267 See :hg:`help urls` for details on specifying URLs.
1267 See :hg:`help urls` for details on specifying URLs.
1268
1268
1269 Returns 0 on success.
1269 Returns 0 on success.
1270 """
1270 """
1271 if opts.get('noupdate') and opts.get('updaterev'):
1271 if opts.get('noupdate') and opts.get('updaterev'):
1272 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1272 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1273
1273
1274 r = hg.clone(ui, opts, source, dest,
1274 r = hg.clone(ui, opts, source, dest,
1275 pull=opts.get('pull'),
1275 pull=opts.get('pull'),
1276 stream=opts.get('uncompressed'),
1276 stream=opts.get('uncompressed'),
1277 rev=opts.get('rev'),
1277 rev=opts.get('rev'),
1278 update=opts.get('updaterev') or not opts.get('noupdate'),
1278 update=opts.get('updaterev') or not opts.get('noupdate'),
1279 branch=opts.get('branch'))
1279 branch=opts.get('branch'))
1280
1280
1281 return r is None
1281 return r is None
1282
1282
1283 @command('^commit|ci',
1283 @command('^commit|ci',
1284 [('A', 'addremove', None,
1284 [('A', 'addremove', None,
1285 _('mark new/missing files as added/removed before committing')),
1285 _('mark new/missing files as added/removed before committing')),
1286 ('', 'close-branch', None,
1286 ('', 'close-branch', None,
1287 _('mark a branch as closed, hiding it from the branch list')),
1287 _('mark a branch as closed, hiding it from the branch list')),
1288 ('', 'amend', None, _('amend the parent of the working dir')),
1288 ('', 'amend', None, _('amend the parent of the working dir')),
1289 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1289 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1290 _('[OPTION]... [FILE]...'))
1290 _('[OPTION]... [FILE]...'))
1291 def commit(ui, repo, *pats, **opts):
1291 def commit(ui, repo, *pats, **opts):
1292 """commit the specified files or all outstanding changes
1292 """commit the specified files or all outstanding changes
1293
1293
1294 Commit changes to the given files into the repository. Unlike a
1294 Commit changes to the given files into the repository. Unlike a
1295 centralized SCM, this operation is a local operation. See
1295 centralized SCM, this operation is a local operation. See
1296 :hg:`push` for a way to actively distribute your changes.
1296 :hg:`push` for a way to actively distribute your changes.
1297
1297
1298 If a list of files is omitted, all changes reported by :hg:`status`
1298 If a list of files is omitted, all changes reported by :hg:`status`
1299 will be committed.
1299 will be committed.
1300
1300
1301 If you are committing the result of a merge, do not provide any
1301 If you are committing the result of a merge, do not provide any
1302 filenames or -I/-X filters.
1302 filenames or -I/-X filters.
1303
1303
1304 If no commit message is specified, Mercurial starts your
1304 If no commit message is specified, Mercurial starts your
1305 configured editor where you can enter a message. In case your
1305 configured editor where you can enter a message. In case your
1306 commit fails, you will find a backup of your message in
1306 commit fails, you will find a backup of your message in
1307 ``.hg/last-message.txt``.
1307 ``.hg/last-message.txt``.
1308
1308
1309 The --amend flag can be used to amend the parent of the
1309 The --amend flag can be used to amend the parent of the
1310 working directory with a new commit that contains the changes
1310 working directory with a new commit that contains the changes
1311 in the parent in addition to those currently reported by :hg:`status`,
1311 in the parent in addition to those currently reported by :hg:`status`,
1312 if there are any. The old commit is stored in a backup bundle in
1312 if there are any. The old commit is stored in a backup bundle in
1313 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1313 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1314 on how to restore it).
1314 on how to restore it).
1315
1315
1316 Message, user and date are taken from the amended commit unless
1316 Message, user and date are taken from the amended commit unless
1317 specified. When a message isn't specified on the command line,
1317 specified. When a message isn't specified on the command line,
1318 the editor will open with the message of the amended commit.
1318 the editor will open with the message of the amended commit.
1319
1319
1320 It is not possible to amend public changesets (see :hg:`help phases`)
1320 It is not possible to amend public changesets (see :hg:`help phases`)
1321 or changesets that have children.
1321 or changesets that have children.
1322
1322
1323 See :hg:`help dates` for a list of formats valid for -d/--date.
1323 See :hg:`help dates` for a list of formats valid for -d/--date.
1324
1324
1325 Returns 0 on success, 1 if nothing changed.
1325 Returns 0 on success, 1 if nothing changed.
1326 """
1326 """
1327 if opts.get('subrepos'):
1327 if opts.get('subrepos'):
1328 if opts.get('amend'):
1329 raise util.Abort(_('cannot amend with --subrepos'))
1328 # Let --subrepos on the command line override config setting.
1330 # Let --subrepos on the command line override config setting.
1329 ui.setconfig('ui', 'commitsubrepos', True)
1331 ui.setconfig('ui', 'commitsubrepos', True)
1330
1332
1331 extra = {}
1333 extra = {}
1332 if opts.get('close_branch'):
1334 if opts.get('close_branch'):
1333 extra['close'] = 1
1335 extra['close'] = 1
1334
1336
1335 branch = repo[None].branch()
1337 branch = repo[None].branch()
1336 bheads = repo.branchheads(branch)
1338 bheads = repo.branchheads(branch)
1337
1339
1338 if opts.get('amend'):
1340 if opts.get('amend'):
1339 if ui.configbool('ui', 'commitsubrepos'):
1341 if ui.configbool('ui', 'commitsubrepos'):
1340 raise util.Abort(_('cannot amend recursively'))
1342 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1341
1343
1342 old = repo['.']
1344 old = repo['.']
1343 if old.phase() == phases.public:
1345 if old.phase() == phases.public:
1344 raise util.Abort(_('cannot amend public changesets'))
1346 raise util.Abort(_('cannot amend public changesets'))
1345 if len(repo[None].parents()) > 1:
1347 if len(repo[None].parents()) > 1:
1346 raise util.Abort(_('cannot amend while merging'))
1348 raise util.Abort(_('cannot amend while merging'))
1347 if (not obsolete._enabled) and old.children():
1349 if (not obsolete._enabled) and old.children():
1348 raise util.Abort(_('cannot amend changeset with children'))
1350 raise util.Abort(_('cannot amend changeset with children'))
1349
1351
1350 e = cmdutil.commiteditor
1352 e = cmdutil.commiteditor
1351 if opts.get('force_editor'):
1353 if opts.get('force_editor'):
1352 e = cmdutil.commitforceeditor
1354 e = cmdutil.commitforceeditor
1353
1355
1354 def commitfunc(ui, repo, message, match, opts):
1356 def commitfunc(ui, repo, message, match, opts):
1355 editor = e
1357 editor = e
1356 # message contains text from -m or -l, if it's empty,
1358 # message contains text from -m or -l, if it's empty,
1357 # open the editor with the old message
1359 # open the editor with the old message
1358 if not message:
1360 if not message:
1359 message = old.description()
1361 message = old.description()
1360 editor = cmdutil.commitforceeditor
1362 editor = cmdutil.commitforceeditor
1361 return repo.commit(message,
1363 return repo.commit(message,
1362 opts.get('user') or old.user(),
1364 opts.get('user') or old.user(),
1363 opts.get('date') or old.date(),
1365 opts.get('date') or old.date(),
1364 match,
1366 match,
1365 editor=editor,
1367 editor=editor,
1366 extra=extra)
1368 extra=extra)
1367
1369
1368 current = repo._bookmarkcurrent
1370 current = repo._bookmarkcurrent
1369 marks = old.bookmarks()
1371 marks = old.bookmarks()
1370 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1372 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1371 if node == old.node():
1373 if node == old.node():
1372 ui.status(_("nothing changed\n"))
1374 ui.status(_("nothing changed\n"))
1373 return 1
1375 return 1
1374 elif marks:
1376 elif marks:
1375 ui.debug('moving bookmarks %r from %s to %s\n' %
1377 ui.debug('moving bookmarks %r from %s to %s\n' %
1376 (marks, old.hex(), hex(node)))
1378 (marks, old.hex(), hex(node)))
1377 newmarks = repo._bookmarks
1379 newmarks = repo._bookmarks
1378 for bm in marks:
1380 for bm in marks:
1379 newmarks[bm] = node
1381 newmarks[bm] = node
1380 if bm == current:
1382 if bm == current:
1381 bookmarks.setcurrent(repo, bm)
1383 bookmarks.setcurrent(repo, bm)
1382 newmarks.write()
1384 newmarks.write()
1383 else:
1385 else:
1384 e = cmdutil.commiteditor
1386 e = cmdutil.commiteditor
1385 if opts.get('force_editor'):
1387 if opts.get('force_editor'):
1386 e = cmdutil.commitforceeditor
1388 e = cmdutil.commitforceeditor
1387
1389
1388 def commitfunc(ui, repo, message, match, opts):
1390 def commitfunc(ui, repo, message, match, opts):
1389 return repo.commit(message, opts.get('user'), opts.get('date'),
1391 return repo.commit(message, opts.get('user'), opts.get('date'),
1390 match, editor=e, extra=extra)
1392 match, editor=e, extra=extra)
1391
1393
1392 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1394 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1393
1395
1394 if not node:
1396 if not node:
1395 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1397 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1396 if stat[3]:
1398 if stat[3]:
1397 ui.status(_("nothing changed (%d missing files, see "
1399 ui.status(_("nothing changed (%d missing files, see "
1398 "'hg status')\n") % len(stat[3]))
1400 "'hg status')\n") % len(stat[3]))
1399 else:
1401 else:
1400 ui.status(_("nothing changed\n"))
1402 ui.status(_("nothing changed\n"))
1401 return 1
1403 return 1
1402
1404
1403 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1405 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1404
1406
1405 @command('copy|cp',
1407 @command('copy|cp',
1406 [('A', 'after', None, _('record a copy that has already occurred')),
1408 [('A', 'after', None, _('record a copy that has already occurred')),
1407 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1409 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1408 ] + walkopts + dryrunopts,
1410 ] + walkopts + dryrunopts,
1409 _('[OPTION]... [SOURCE]... DEST'))
1411 _('[OPTION]... [SOURCE]... DEST'))
1410 def copy(ui, repo, *pats, **opts):
1412 def copy(ui, repo, *pats, **opts):
1411 """mark files as copied for the next commit
1413 """mark files as copied for the next commit
1412
1414
1413 Mark dest as having copies of source files. If dest is a
1415 Mark dest as having copies of source files. If dest is a
1414 directory, copies are put in that directory. If dest is a file,
1416 directory, copies are put in that directory. If dest is a file,
1415 the source must be a single file.
1417 the source must be a single file.
1416
1418
1417 By default, this command copies the contents of files as they
1419 By default, this command copies the contents of files as they
1418 exist in the working directory. If invoked with -A/--after, the
1420 exist in the working directory. If invoked with -A/--after, the
1419 operation is recorded, but no copying is performed.
1421 operation is recorded, but no copying is performed.
1420
1422
1421 This command takes effect with the next commit. To undo a copy
1423 This command takes effect with the next commit. To undo a copy
1422 before that, see :hg:`revert`.
1424 before that, see :hg:`revert`.
1423
1425
1424 Returns 0 on success, 1 if errors are encountered.
1426 Returns 0 on success, 1 if errors are encountered.
1425 """
1427 """
1426 wlock = repo.wlock(False)
1428 wlock = repo.wlock(False)
1427 try:
1429 try:
1428 return cmdutil.copy(ui, repo, pats, opts)
1430 return cmdutil.copy(ui, repo, pats, opts)
1429 finally:
1431 finally:
1430 wlock.release()
1432 wlock.release()
1431
1433
1432 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1434 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1433 def debugancestor(ui, repo, *args):
1435 def debugancestor(ui, repo, *args):
1434 """find the ancestor revision of two revisions in a given index"""
1436 """find the ancestor revision of two revisions in a given index"""
1435 if len(args) == 3:
1437 if len(args) == 3:
1436 index, rev1, rev2 = args
1438 index, rev1, rev2 = args
1437 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1439 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1438 lookup = r.lookup
1440 lookup = r.lookup
1439 elif len(args) == 2:
1441 elif len(args) == 2:
1440 if not repo:
1442 if not repo:
1441 raise util.Abort(_("there is no Mercurial repository here "
1443 raise util.Abort(_("there is no Mercurial repository here "
1442 "(.hg not found)"))
1444 "(.hg not found)"))
1443 rev1, rev2 = args
1445 rev1, rev2 = args
1444 r = repo.changelog
1446 r = repo.changelog
1445 lookup = repo.lookup
1447 lookup = repo.lookup
1446 else:
1448 else:
1447 raise util.Abort(_('either two or three arguments required'))
1449 raise util.Abort(_('either two or three arguments required'))
1448 a = r.ancestor(lookup(rev1), lookup(rev2))
1450 a = r.ancestor(lookup(rev1), lookup(rev2))
1449 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1451 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1450
1452
1451 @command('debugbuilddag',
1453 @command('debugbuilddag',
1452 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1454 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1453 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1455 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1454 ('n', 'new-file', None, _('add new file at each rev'))],
1456 ('n', 'new-file', None, _('add new file at each rev'))],
1455 _('[OPTION]... [TEXT]'))
1457 _('[OPTION]... [TEXT]'))
1456 def debugbuilddag(ui, repo, text=None,
1458 def debugbuilddag(ui, repo, text=None,
1457 mergeable_file=False,
1459 mergeable_file=False,
1458 overwritten_file=False,
1460 overwritten_file=False,
1459 new_file=False):
1461 new_file=False):
1460 """builds a repo with a given DAG from scratch in the current empty repo
1462 """builds a repo with a given DAG from scratch in the current empty repo
1461
1463
1462 The description of the DAG is read from stdin if not given on the
1464 The description of the DAG is read from stdin if not given on the
1463 command line.
1465 command line.
1464
1466
1465 Elements:
1467 Elements:
1466
1468
1467 - "+n" is a linear run of n nodes based on the current default parent
1469 - "+n" is a linear run of n nodes based on the current default parent
1468 - "." is a single node based on the current default parent
1470 - "." is a single node based on the current default parent
1469 - "$" resets the default parent to null (implied at the start);
1471 - "$" resets the default parent to null (implied at the start);
1470 otherwise the default parent is always the last node created
1472 otherwise the default parent is always the last node created
1471 - "<p" sets the default parent to the backref p
1473 - "<p" sets the default parent to the backref p
1472 - "*p" is a fork at parent p, which is a backref
1474 - "*p" is a fork at parent p, which is a backref
1473 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1475 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1474 - "/p2" is a merge of the preceding node and p2
1476 - "/p2" is a merge of the preceding node and p2
1475 - ":tag" defines a local tag for the preceding node
1477 - ":tag" defines a local tag for the preceding node
1476 - "@branch" sets the named branch for subsequent nodes
1478 - "@branch" sets the named branch for subsequent nodes
1477 - "#...\\n" is a comment up to the end of the line
1479 - "#...\\n" is a comment up to the end of the line
1478
1480
1479 Whitespace between the above elements is ignored.
1481 Whitespace between the above elements is ignored.
1480
1482
1481 A backref is either
1483 A backref is either
1482
1484
1483 - a number n, which references the node curr-n, where curr is the current
1485 - a number n, which references the node curr-n, where curr is the current
1484 node, or
1486 node, or
1485 - the name of a local tag you placed earlier using ":tag", or
1487 - the name of a local tag you placed earlier using ":tag", or
1486 - empty to denote the default parent.
1488 - empty to denote the default parent.
1487
1489
1488 All string valued-elements are either strictly alphanumeric, or must
1490 All string valued-elements are either strictly alphanumeric, or must
1489 be enclosed in double quotes ("..."), with "\\" as escape character.
1491 be enclosed in double quotes ("..."), with "\\" as escape character.
1490 """
1492 """
1491
1493
1492 if text is None:
1494 if text is None:
1493 ui.status(_("reading DAG from stdin\n"))
1495 ui.status(_("reading DAG from stdin\n"))
1494 text = ui.fin.read()
1496 text = ui.fin.read()
1495
1497
1496 cl = repo.changelog
1498 cl = repo.changelog
1497 if len(cl) > 0:
1499 if len(cl) > 0:
1498 raise util.Abort(_('repository is not empty'))
1500 raise util.Abort(_('repository is not empty'))
1499
1501
1500 # determine number of revs in DAG
1502 # determine number of revs in DAG
1501 total = 0
1503 total = 0
1502 for type, data in dagparser.parsedag(text):
1504 for type, data in dagparser.parsedag(text):
1503 if type == 'n':
1505 if type == 'n':
1504 total += 1
1506 total += 1
1505
1507
1506 if mergeable_file:
1508 if mergeable_file:
1507 linesperrev = 2
1509 linesperrev = 2
1508 # make a file with k lines per rev
1510 # make a file with k lines per rev
1509 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1511 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1510 initialmergedlines.append("")
1512 initialmergedlines.append("")
1511
1513
1512 tags = []
1514 tags = []
1513
1515
1514 lock = tr = None
1516 lock = tr = None
1515 try:
1517 try:
1516 lock = repo.lock()
1518 lock = repo.lock()
1517 tr = repo.transaction("builddag")
1519 tr = repo.transaction("builddag")
1518
1520
1519 at = -1
1521 at = -1
1520 atbranch = 'default'
1522 atbranch = 'default'
1521 nodeids = []
1523 nodeids = []
1522 id = 0
1524 id = 0
1523 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1525 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1524 for type, data in dagparser.parsedag(text):
1526 for type, data in dagparser.parsedag(text):
1525 if type == 'n':
1527 if type == 'n':
1526 ui.note(('node %s\n' % str(data)))
1528 ui.note(('node %s\n' % str(data)))
1527 id, ps = data
1529 id, ps = data
1528
1530
1529 files = []
1531 files = []
1530 fctxs = {}
1532 fctxs = {}
1531
1533
1532 p2 = None
1534 p2 = None
1533 if mergeable_file:
1535 if mergeable_file:
1534 fn = "mf"
1536 fn = "mf"
1535 p1 = repo[ps[0]]
1537 p1 = repo[ps[0]]
1536 if len(ps) > 1:
1538 if len(ps) > 1:
1537 p2 = repo[ps[1]]
1539 p2 = repo[ps[1]]
1538 pa = p1.ancestor(p2)
1540 pa = p1.ancestor(p2)
1539 base, local, other = [x[fn].data() for x in (pa, p1,
1541 base, local, other = [x[fn].data() for x in (pa, p1,
1540 p2)]
1542 p2)]
1541 m3 = simplemerge.Merge3Text(base, local, other)
1543 m3 = simplemerge.Merge3Text(base, local, other)
1542 ml = [l.strip() for l in m3.merge_lines()]
1544 ml = [l.strip() for l in m3.merge_lines()]
1543 ml.append("")
1545 ml.append("")
1544 elif at > 0:
1546 elif at > 0:
1545 ml = p1[fn].data().split("\n")
1547 ml = p1[fn].data().split("\n")
1546 else:
1548 else:
1547 ml = initialmergedlines
1549 ml = initialmergedlines
1548 ml[id * linesperrev] += " r%i" % id
1550 ml[id * linesperrev] += " r%i" % id
1549 mergedtext = "\n".join(ml)
1551 mergedtext = "\n".join(ml)
1550 files.append(fn)
1552 files.append(fn)
1551 fctxs[fn] = context.memfilectx(fn, mergedtext)
1553 fctxs[fn] = context.memfilectx(fn, mergedtext)
1552
1554
1553 if overwritten_file:
1555 if overwritten_file:
1554 fn = "of"
1556 fn = "of"
1555 files.append(fn)
1557 files.append(fn)
1556 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1558 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1557
1559
1558 if new_file:
1560 if new_file:
1559 fn = "nf%i" % id
1561 fn = "nf%i" % id
1560 files.append(fn)
1562 files.append(fn)
1561 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1563 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1562 if len(ps) > 1:
1564 if len(ps) > 1:
1563 if not p2:
1565 if not p2:
1564 p2 = repo[ps[1]]
1566 p2 = repo[ps[1]]
1565 for fn in p2:
1567 for fn in p2:
1566 if fn.startswith("nf"):
1568 if fn.startswith("nf"):
1567 files.append(fn)
1569 files.append(fn)
1568 fctxs[fn] = p2[fn]
1570 fctxs[fn] = p2[fn]
1569
1571
1570 def fctxfn(repo, cx, path):
1572 def fctxfn(repo, cx, path):
1571 return fctxs.get(path)
1573 return fctxs.get(path)
1572
1574
1573 if len(ps) == 0 or ps[0] < 0:
1575 if len(ps) == 0 or ps[0] < 0:
1574 pars = [None, None]
1576 pars = [None, None]
1575 elif len(ps) == 1:
1577 elif len(ps) == 1:
1576 pars = [nodeids[ps[0]], None]
1578 pars = [nodeids[ps[0]], None]
1577 else:
1579 else:
1578 pars = [nodeids[p] for p in ps]
1580 pars = [nodeids[p] for p in ps]
1579 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1581 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1580 date=(id, 0),
1582 date=(id, 0),
1581 user="debugbuilddag",
1583 user="debugbuilddag",
1582 extra={'branch': atbranch})
1584 extra={'branch': atbranch})
1583 nodeid = repo.commitctx(cx)
1585 nodeid = repo.commitctx(cx)
1584 nodeids.append(nodeid)
1586 nodeids.append(nodeid)
1585 at = id
1587 at = id
1586 elif type == 'l':
1588 elif type == 'l':
1587 id, name = data
1589 id, name = data
1588 ui.note(('tag %s\n' % name))
1590 ui.note(('tag %s\n' % name))
1589 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1591 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1590 elif type == 'a':
1592 elif type == 'a':
1591 ui.note(('branch %s\n' % data))
1593 ui.note(('branch %s\n' % data))
1592 atbranch = data
1594 atbranch = data
1593 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1595 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1594 tr.close()
1596 tr.close()
1595
1597
1596 if tags:
1598 if tags:
1597 repo.opener.write("localtags", "".join(tags))
1599 repo.opener.write("localtags", "".join(tags))
1598 finally:
1600 finally:
1599 ui.progress(_('building'), None)
1601 ui.progress(_('building'), None)
1600 release(tr, lock)
1602 release(tr, lock)
1601
1603
1602 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1604 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1603 def debugbundle(ui, bundlepath, all=None, **opts):
1605 def debugbundle(ui, bundlepath, all=None, **opts):
1604 """lists the contents of a bundle"""
1606 """lists the contents of a bundle"""
1605 f = hg.openpath(ui, bundlepath)
1607 f = hg.openpath(ui, bundlepath)
1606 try:
1608 try:
1607 gen = changegroup.readbundle(f, bundlepath)
1609 gen = changegroup.readbundle(f, bundlepath)
1608 if all:
1610 if all:
1609 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1611 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1610
1612
1611 def showchunks(named):
1613 def showchunks(named):
1612 ui.write("\n%s\n" % named)
1614 ui.write("\n%s\n" % named)
1613 chain = None
1615 chain = None
1614 while True:
1616 while True:
1615 chunkdata = gen.deltachunk(chain)
1617 chunkdata = gen.deltachunk(chain)
1616 if not chunkdata:
1618 if not chunkdata:
1617 break
1619 break
1618 node = chunkdata['node']
1620 node = chunkdata['node']
1619 p1 = chunkdata['p1']
1621 p1 = chunkdata['p1']
1620 p2 = chunkdata['p2']
1622 p2 = chunkdata['p2']
1621 cs = chunkdata['cs']
1623 cs = chunkdata['cs']
1622 deltabase = chunkdata['deltabase']
1624 deltabase = chunkdata['deltabase']
1623 delta = chunkdata['delta']
1625 delta = chunkdata['delta']
1624 ui.write("%s %s %s %s %s %s\n" %
1626 ui.write("%s %s %s %s %s %s\n" %
1625 (hex(node), hex(p1), hex(p2),
1627 (hex(node), hex(p1), hex(p2),
1626 hex(cs), hex(deltabase), len(delta)))
1628 hex(cs), hex(deltabase), len(delta)))
1627 chain = node
1629 chain = node
1628
1630
1629 chunkdata = gen.changelogheader()
1631 chunkdata = gen.changelogheader()
1630 showchunks("changelog")
1632 showchunks("changelog")
1631 chunkdata = gen.manifestheader()
1633 chunkdata = gen.manifestheader()
1632 showchunks("manifest")
1634 showchunks("manifest")
1633 while True:
1635 while True:
1634 chunkdata = gen.filelogheader()
1636 chunkdata = gen.filelogheader()
1635 if not chunkdata:
1637 if not chunkdata:
1636 break
1638 break
1637 fname = chunkdata['filename']
1639 fname = chunkdata['filename']
1638 showchunks(fname)
1640 showchunks(fname)
1639 else:
1641 else:
1640 chunkdata = gen.changelogheader()
1642 chunkdata = gen.changelogheader()
1641 chain = None
1643 chain = None
1642 while True:
1644 while True:
1643 chunkdata = gen.deltachunk(chain)
1645 chunkdata = gen.deltachunk(chain)
1644 if not chunkdata:
1646 if not chunkdata:
1645 break
1647 break
1646 node = chunkdata['node']
1648 node = chunkdata['node']
1647 ui.write("%s\n" % hex(node))
1649 ui.write("%s\n" % hex(node))
1648 chain = node
1650 chain = node
1649 finally:
1651 finally:
1650 f.close()
1652 f.close()
1651
1653
1652 @command('debugcheckstate', [], '')
1654 @command('debugcheckstate', [], '')
1653 def debugcheckstate(ui, repo):
1655 def debugcheckstate(ui, repo):
1654 """validate the correctness of the current dirstate"""
1656 """validate the correctness of the current dirstate"""
1655 parent1, parent2 = repo.dirstate.parents()
1657 parent1, parent2 = repo.dirstate.parents()
1656 m1 = repo[parent1].manifest()
1658 m1 = repo[parent1].manifest()
1657 m2 = repo[parent2].manifest()
1659 m2 = repo[parent2].manifest()
1658 errors = 0
1660 errors = 0
1659 for f in repo.dirstate:
1661 for f in repo.dirstate:
1660 state = repo.dirstate[f]
1662 state = repo.dirstate[f]
1661 if state in "nr" and f not in m1:
1663 if state in "nr" and f not in m1:
1662 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1664 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1663 errors += 1
1665 errors += 1
1664 if state in "a" and f in m1:
1666 if state in "a" and f in m1:
1665 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1667 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1666 errors += 1
1668 errors += 1
1667 if state in "m" and f not in m1 and f not in m2:
1669 if state in "m" and f not in m1 and f not in m2:
1668 ui.warn(_("%s in state %s, but not in either manifest\n") %
1670 ui.warn(_("%s in state %s, but not in either manifest\n") %
1669 (f, state))
1671 (f, state))
1670 errors += 1
1672 errors += 1
1671 for f in m1:
1673 for f in m1:
1672 state = repo.dirstate[f]
1674 state = repo.dirstate[f]
1673 if state not in "nrm":
1675 if state not in "nrm":
1674 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1676 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1675 errors += 1
1677 errors += 1
1676 if errors:
1678 if errors:
1677 error = _(".hg/dirstate inconsistent with current parent's manifest")
1679 error = _(".hg/dirstate inconsistent with current parent's manifest")
1678 raise util.Abort(error)
1680 raise util.Abort(error)
1679
1681
1680 @command('debugcommands', [], _('[COMMAND]'))
1682 @command('debugcommands', [], _('[COMMAND]'))
1681 def debugcommands(ui, cmd='', *args):
1683 def debugcommands(ui, cmd='', *args):
1682 """list all available commands and options"""
1684 """list all available commands and options"""
1683 for cmd, vals in sorted(table.iteritems()):
1685 for cmd, vals in sorted(table.iteritems()):
1684 cmd = cmd.split('|')[0].strip('^')
1686 cmd = cmd.split('|')[0].strip('^')
1685 opts = ', '.join([i[1] for i in vals[1]])
1687 opts = ', '.join([i[1] for i in vals[1]])
1686 ui.write('%s: %s\n' % (cmd, opts))
1688 ui.write('%s: %s\n' % (cmd, opts))
1687
1689
1688 @command('debugcomplete',
1690 @command('debugcomplete',
1689 [('o', 'options', None, _('show the command options'))],
1691 [('o', 'options', None, _('show the command options'))],
1690 _('[-o] CMD'))
1692 _('[-o] CMD'))
1691 def debugcomplete(ui, cmd='', **opts):
1693 def debugcomplete(ui, cmd='', **opts):
1692 """returns the completion list associated with the given command"""
1694 """returns the completion list associated with the given command"""
1693
1695
1694 if opts.get('options'):
1696 if opts.get('options'):
1695 options = []
1697 options = []
1696 otables = [globalopts]
1698 otables = [globalopts]
1697 if cmd:
1699 if cmd:
1698 aliases, entry = cmdutil.findcmd(cmd, table, False)
1700 aliases, entry = cmdutil.findcmd(cmd, table, False)
1699 otables.append(entry[1])
1701 otables.append(entry[1])
1700 for t in otables:
1702 for t in otables:
1701 for o in t:
1703 for o in t:
1702 if "(DEPRECATED)" in o[3]:
1704 if "(DEPRECATED)" in o[3]:
1703 continue
1705 continue
1704 if o[0]:
1706 if o[0]:
1705 options.append('-%s' % o[0])
1707 options.append('-%s' % o[0])
1706 options.append('--%s' % o[1])
1708 options.append('--%s' % o[1])
1707 ui.write("%s\n" % "\n".join(options))
1709 ui.write("%s\n" % "\n".join(options))
1708 return
1710 return
1709
1711
1710 cmdlist = cmdutil.findpossible(cmd, table)
1712 cmdlist = cmdutil.findpossible(cmd, table)
1711 if ui.verbose:
1713 if ui.verbose:
1712 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1714 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1713 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1715 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1714
1716
1715 @command('debugdag',
1717 @command('debugdag',
1716 [('t', 'tags', None, _('use tags as labels')),
1718 [('t', 'tags', None, _('use tags as labels')),
1717 ('b', 'branches', None, _('annotate with branch names')),
1719 ('b', 'branches', None, _('annotate with branch names')),
1718 ('', 'dots', None, _('use dots for runs')),
1720 ('', 'dots', None, _('use dots for runs')),
1719 ('s', 'spaces', None, _('separate elements by spaces'))],
1721 ('s', 'spaces', None, _('separate elements by spaces'))],
1720 _('[OPTION]... [FILE [REV]...]'))
1722 _('[OPTION]... [FILE [REV]...]'))
1721 def debugdag(ui, repo, file_=None, *revs, **opts):
1723 def debugdag(ui, repo, file_=None, *revs, **opts):
1722 """format the changelog or an index DAG as a concise textual description
1724 """format the changelog or an index DAG as a concise textual description
1723
1725
1724 If you pass a revlog index, the revlog's DAG is emitted. If you list
1726 If you pass a revlog index, the revlog's DAG is emitted. If you list
1725 revision numbers, they get labeled in the output as rN.
1727 revision numbers, they get labeled in the output as rN.
1726
1728
1727 Otherwise, the changelog DAG of the current repo is emitted.
1729 Otherwise, the changelog DAG of the current repo is emitted.
1728 """
1730 """
1729 spaces = opts.get('spaces')
1731 spaces = opts.get('spaces')
1730 dots = opts.get('dots')
1732 dots = opts.get('dots')
1731 if file_:
1733 if file_:
1732 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1734 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1733 revs = set((int(r) for r in revs))
1735 revs = set((int(r) for r in revs))
1734 def events():
1736 def events():
1735 for r in rlog:
1737 for r in rlog:
1736 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1738 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1737 if p != -1)))
1739 if p != -1)))
1738 if r in revs:
1740 if r in revs:
1739 yield 'l', (r, "r%i" % r)
1741 yield 'l', (r, "r%i" % r)
1740 elif repo:
1742 elif repo:
1741 cl = repo.changelog
1743 cl = repo.changelog
1742 tags = opts.get('tags')
1744 tags = opts.get('tags')
1743 branches = opts.get('branches')
1745 branches = opts.get('branches')
1744 if tags:
1746 if tags:
1745 labels = {}
1747 labels = {}
1746 for l, n in repo.tags().items():
1748 for l, n in repo.tags().items():
1747 labels.setdefault(cl.rev(n), []).append(l)
1749 labels.setdefault(cl.rev(n), []).append(l)
1748 def events():
1750 def events():
1749 b = "default"
1751 b = "default"
1750 for r in cl:
1752 for r in cl:
1751 if branches:
1753 if branches:
1752 newb = cl.read(cl.node(r))[5]['branch']
1754 newb = cl.read(cl.node(r))[5]['branch']
1753 if newb != b:
1755 if newb != b:
1754 yield 'a', newb
1756 yield 'a', newb
1755 b = newb
1757 b = newb
1756 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1758 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1757 if p != -1)))
1759 if p != -1)))
1758 if tags:
1760 if tags:
1759 ls = labels.get(r)
1761 ls = labels.get(r)
1760 if ls:
1762 if ls:
1761 for l in ls:
1763 for l in ls:
1762 yield 'l', (r, l)
1764 yield 'l', (r, l)
1763 else:
1765 else:
1764 raise util.Abort(_('need repo for changelog dag'))
1766 raise util.Abort(_('need repo for changelog dag'))
1765
1767
1766 for line in dagparser.dagtextlines(events(),
1768 for line in dagparser.dagtextlines(events(),
1767 addspaces=spaces,
1769 addspaces=spaces,
1768 wraplabels=True,
1770 wraplabels=True,
1769 wrapannotations=True,
1771 wrapannotations=True,
1770 wrapnonlinear=dots,
1772 wrapnonlinear=dots,
1771 usedots=dots,
1773 usedots=dots,
1772 maxlinewidth=70):
1774 maxlinewidth=70):
1773 ui.write(line)
1775 ui.write(line)
1774 ui.write("\n")
1776 ui.write("\n")
1775
1777
1776 @command('debugdata',
1778 @command('debugdata',
1777 [('c', 'changelog', False, _('open changelog')),
1779 [('c', 'changelog', False, _('open changelog')),
1778 ('m', 'manifest', False, _('open manifest'))],
1780 ('m', 'manifest', False, _('open manifest'))],
1779 _('-c|-m|FILE REV'))
1781 _('-c|-m|FILE REV'))
1780 def debugdata(ui, repo, file_, rev = None, **opts):
1782 def debugdata(ui, repo, file_, rev = None, **opts):
1781 """dump the contents of a data file revision"""
1783 """dump the contents of a data file revision"""
1782 if opts.get('changelog') or opts.get('manifest'):
1784 if opts.get('changelog') or opts.get('manifest'):
1783 file_, rev = None, file_
1785 file_, rev = None, file_
1784 elif rev is None:
1786 elif rev is None:
1785 raise error.CommandError('debugdata', _('invalid arguments'))
1787 raise error.CommandError('debugdata', _('invalid arguments'))
1786 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1788 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1787 try:
1789 try:
1788 ui.write(r.revision(r.lookup(rev)))
1790 ui.write(r.revision(r.lookup(rev)))
1789 except KeyError:
1791 except KeyError:
1790 raise util.Abort(_('invalid revision identifier %s') % rev)
1792 raise util.Abort(_('invalid revision identifier %s') % rev)
1791
1793
1792 @command('debugdate',
1794 @command('debugdate',
1793 [('e', 'extended', None, _('try extended date formats'))],
1795 [('e', 'extended', None, _('try extended date formats'))],
1794 _('[-e] DATE [RANGE]'))
1796 _('[-e] DATE [RANGE]'))
1795 def debugdate(ui, date, range=None, **opts):
1797 def debugdate(ui, date, range=None, **opts):
1796 """parse and display a date"""
1798 """parse and display a date"""
1797 if opts["extended"]:
1799 if opts["extended"]:
1798 d = util.parsedate(date, util.extendeddateformats)
1800 d = util.parsedate(date, util.extendeddateformats)
1799 else:
1801 else:
1800 d = util.parsedate(date)
1802 d = util.parsedate(date)
1801 ui.write(("internal: %s %s\n") % d)
1803 ui.write(("internal: %s %s\n") % d)
1802 ui.write(("standard: %s\n") % util.datestr(d))
1804 ui.write(("standard: %s\n") % util.datestr(d))
1803 if range:
1805 if range:
1804 m = util.matchdate(range)
1806 m = util.matchdate(range)
1805 ui.write(("match: %s\n") % m(d[0]))
1807 ui.write(("match: %s\n") % m(d[0]))
1806
1808
1807 @command('debugdiscovery',
1809 @command('debugdiscovery',
1808 [('', 'old', None, _('use old-style discovery')),
1810 [('', 'old', None, _('use old-style discovery')),
1809 ('', 'nonheads', None,
1811 ('', 'nonheads', None,
1810 _('use old-style discovery with non-heads included')),
1812 _('use old-style discovery with non-heads included')),
1811 ] + remoteopts,
1813 ] + remoteopts,
1812 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1814 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1813 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1815 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1814 """runs the changeset discovery protocol in isolation"""
1816 """runs the changeset discovery protocol in isolation"""
1815 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1817 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1816 opts.get('branch'))
1818 opts.get('branch'))
1817 remote = hg.peer(repo, opts, remoteurl)
1819 remote = hg.peer(repo, opts, remoteurl)
1818 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1820 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1819
1821
1820 # make sure tests are repeatable
1822 # make sure tests are repeatable
1821 random.seed(12323)
1823 random.seed(12323)
1822
1824
1823 def doit(localheads, remoteheads, remote=remote):
1825 def doit(localheads, remoteheads, remote=remote):
1824 if opts.get('old'):
1826 if opts.get('old'):
1825 if localheads:
1827 if localheads:
1826 raise util.Abort('cannot use localheads with old style '
1828 raise util.Abort('cannot use localheads with old style '
1827 'discovery')
1829 'discovery')
1828 if not util.safehasattr(remote, 'branches'):
1830 if not util.safehasattr(remote, 'branches'):
1829 # enable in-client legacy support
1831 # enable in-client legacy support
1830 remote = localrepo.locallegacypeer(remote.local())
1832 remote = localrepo.locallegacypeer(remote.local())
1831 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1833 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1832 force=True)
1834 force=True)
1833 common = set(common)
1835 common = set(common)
1834 if not opts.get('nonheads'):
1836 if not opts.get('nonheads'):
1835 ui.write(("unpruned common: %s\n") %
1837 ui.write(("unpruned common: %s\n") %
1836 " ".join(sorted(short(n) for n in common)))
1838 " ".join(sorted(short(n) for n in common)))
1837 dag = dagutil.revlogdag(repo.changelog)
1839 dag = dagutil.revlogdag(repo.changelog)
1838 all = dag.ancestorset(dag.internalizeall(common))
1840 all = dag.ancestorset(dag.internalizeall(common))
1839 common = dag.externalizeall(dag.headsetofconnecteds(all))
1841 common = dag.externalizeall(dag.headsetofconnecteds(all))
1840 else:
1842 else:
1841 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1843 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1842 common = set(common)
1844 common = set(common)
1843 rheads = set(hds)
1845 rheads = set(hds)
1844 lheads = set(repo.heads())
1846 lheads = set(repo.heads())
1845 ui.write(("common heads: %s\n") %
1847 ui.write(("common heads: %s\n") %
1846 " ".join(sorted(short(n) for n in common)))
1848 " ".join(sorted(short(n) for n in common)))
1847 if lheads <= common:
1849 if lheads <= common:
1848 ui.write(("local is subset\n"))
1850 ui.write(("local is subset\n"))
1849 elif rheads <= common:
1851 elif rheads <= common:
1850 ui.write(("remote is subset\n"))
1852 ui.write(("remote is subset\n"))
1851
1853
1852 serverlogs = opts.get('serverlog')
1854 serverlogs = opts.get('serverlog')
1853 if serverlogs:
1855 if serverlogs:
1854 for filename in serverlogs:
1856 for filename in serverlogs:
1855 logfile = open(filename, 'r')
1857 logfile = open(filename, 'r')
1856 try:
1858 try:
1857 line = logfile.readline()
1859 line = logfile.readline()
1858 while line:
1860 while line:
1859 parts = line.strip().split(';')
1861 parts = line.strip().split(';')
1860 op = parts[1]
1862 op = parts[1]
1861 if op == 'cg':
1863 if op == 'cg':
1862 pass
1864 pass
1863 elif op == 'cgss':
1865 elif op == 'cgss':
1864 doit(parts[2].split(' '), parts[3].split(' '))
1866 doit(parts[2].split(' '), parts[3].split(' '))
1865 elif op == 'unb':
1867 elif op == 'unb':
1866 doit(parts[3].split(' '), parts[2].split(' '))
1868 doit(parts[3].split(' '), parts[2].split(' '))
1867 line = logfile.readline()
1869 line = logfile.readline()
1868 finally:
1870 finally:
1869 logfile.close()
1871 logfile.close()
1870
1872
1871 else:
1873 else:
1872 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1874 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1873 opts.get('remote_head'))
1875 opts.get('remote_head'))
1874 localrevs = opts.get('local_head')
1876 localrevs = opts.get('local_head')
1875 doit(localrevs, remoterevs)
1877 doit(localrevs, remoterevs)
1876
1878
1877 @command('debugfileset',
1879 @command('debugfileset',
1878 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1880 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1879 _('[-r REV] FILESPEC'))
1881 _('[-r REV] FILESPEC'))
1880 def debugfileset(ui, repo, expr, **opts):
1882 def debugfileset(ui, repo, expr, **opts):
1881 '''parse and apply a fileset specification'''
1883 '''parse and apply a fileset specification'''
1882 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1884 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1883 if ui.verbose:
1885 if ui.verbose:
1884 tree = fileset.parse(expr)[0]
1886 tree = fileset.parse(expr)[0]
1885 ui.note(tree, "\n")
1887 ui.note(tree, "\n")
1886
1888
1887 for f in fileset.getfileset(ctx, expr):
1889 for f in fileset.getfileset(ctx, expr):
1888 ui.write("%s\n" % f)
1890 ui.write("%s\n" % f)
1889
1891
1890 @command('debugfsinfo', [], _('[PATH]'))
1892 @command('debugfsinfo', [], _('[PATH]'))
1891 def debugfsinfo(ui, path = "."):
1893 def debugfsinfo(ui, path = "."):
1892 """show information detected about current filesystem"""
1894 """show information detected about current filesystem"""
1893 util.writefile('.debugfsinfo', '')
1895 util.writefile('.debugfsinfo', '')
1894 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1896 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1895 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1897 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1896 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1898 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1897 and 'yes' or 'no'))
1899 and 'yes' or 'no'))
1898 os.unlink('.debugfsinfo')
1900 os.unlink('.debugfsinfo')
1899
1901
1900 @command('debuggetbundle',
1902 @command('debuggetbundle',
1901 [('H', 'head', [], _('id of head node'), _('ID')),
1903 [('H', 'head', [], _('id of head node'), _('ID')),
1902 ('C', 'common', [], _('id of common node'), _('ID')),
1904 ('C', 'common', [], _('id of common node'), _('ID')),
1903 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1905 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1904 _('REPO FILE [-H|-C ID]...'))
1906 _('REPO FILE [-H|-C ID]...'))
1905 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1907 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1906 """retrieves a bundle from a repo
1908 """retrieves a bundle from a repo
1907
1909
1908 Every ID must be a full-length hex node id string. Saves the bundle to the
1910 Every ID must be a full-length hex node id string. Saves the bundle to the
1909 given file.
1911 given file.
1910 """
1912 """
1911 repo = hg.peer(ui, opts, repopath)
1913 repo = hg.peer(ui, opts, repopath)
1912 if not repo.capable('getbundle'):
1914 if not repo.capable('getbundle'):
1913 raise util.Abort("getbundle() not supported by target repository")
1915 raise util.Abort("getbundle() not supported by target repository")
1914 args = {}
1916 args = {}
1915 if common:
1917 if common:
1916 args['common'] = [bin(s) for s in common]
1918 args['common'] = [bin(s) for s in common]
1917 if head:
1919 if head:
1918 args['heads'] = [bin(s) for s in head]
1920 args['heads'] = [bin(s) for s in head]
1919 # TODO: get desired bundlecaps from command line.
1921 # TODO: get desired bundlecaps from command line.
1920 args['bundlecaps'] = None
1922 args['bundlecaps'] = None
1921 bundle = repo.getbundle('debug', **args)
1923 bundle = repo.getbundle('debug', **args)
1922
1924
1923 bundletype = opts.get('type', 'bzip2').lower()
1925 bundletype = opts.get('type', 'bzip2').lower()
1924 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1926 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1925 bundletype = btypes.get(bundletype)
1927 bundletype = btypes.get(bundletype)
1926 if bundletype not in changegroup.bundletypes:
1928 if bundletype not in changegroup.bundletypes:
1927 raise util.Abort(_('unknown bundle type specified with --type'))
1929 raise util.Abort(_('unknown bundle type specified with --type'))
1928 changegroup.writebundle(bundle, bundlepath, bundletype)
1930 changegroup.writebundle(bundle, bundlepath, bundletype)
1929
1931
1930 @command('debugignore', [], '')
1932 @command('debugignore', [], '')
1931 def debugignore(ui, repo, *values, **opts):
1933 def debugignore(ui, repo, *values, **opts):
1932 """display the combined ignore pattern"""
1934 """display the combined ignore pattern"""
1933 ignore = repo.dirstate._ignore
1935 ignore = repo.dirstate._ignore
1934 includepat = getattr(ignore, 'includepat', None)
1936 includepat = getattr(ignore, 'includepat', None)
1935 if includepat is not None:
1937 if includepat is not None:
1936 ui.write("%s\n" % includepat)
1938 ui.write("%s\n" % includepat)
1937 else:
1939 else:
1938 raise util.Abort(_("no ignore patterns found"))
1940 raise util.Abort(_("no ignore patterns found"))
1939
1941
1940 @command('debugindex',
1942 @command('debugindex',
1941 [('c', 'changelog', False, _('open changelog')),
1943 [('c', 'changelog', False, _('open changelog')),
1942 ('m', 'manifest', False, _('open manifest')),
1944 ('m', 'manifest', False, _('open manifest')),
1943 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1945 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1944 _('[-f FORMAT] -c|-m|FILE'))
1946 _('[-f FORMAT] -c|-m|FILE'))
1945 def debugindex(ui, repo, file_ = None, **opts):
1947 def debugindex(ui, repo, file_ = None, **opts):
1946 """dump the contents of an index file"""
1948 """dump the contents of an index file"""
1947 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1949 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1948 format = opts.get('format', 0)
1950 format = opts.get('format', 0)
1949 if format not in (0, 1):
1951 if format not in (0, 1):
1950 raise util.Abort(_("unknown format %d") % format)
1952 raise util.Abort(_("unknown format %d") % format)
1951
1953
1952 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1954 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1953 if generaldelta:
1955 if generaldelta:
1954 basehdr = ' delta'
1956 basehdr = ' delta'
1955 else:
1957 else:
1956 basehdr = ' base'
1958 basehdr = ' base'
1957
1959
1958 if format == 0:
1960 if format == 0:
1959 ui.write(" rev offset length " + basehdr + " linkrev"
1961 ui.write(" rev offset length " + basehdr + " linkrev"
1960 " nodeid p1 p2\n")
1962 " nodeid p1 p2\n")
1961 elif format == 1:
1963 elif format == 1:
1962 ui.write(" rev flag offset length"
1964 ui.write(" rev flag offset length"
1963 " size " + basehdr + " link p1 p2"
1965 " size " + basehdr + " link p1 p2"
1964 " nodeid\n")
1966 " nodeid\n")
1965
1967
1966 for i in r:
1968 for i in r:
1967 node = r.node(i)
1969 node = r.node(i)
1968 if generaldelta:
1970 if generaldelta:
1969 base = r.deltaparent(i)
1971 base = r.deltaparent(i)
1970 else:
1972 else:
1971 base = r.chainbase(i)
1973 base = r.chainbase(i)
1972 if format == 0:
1974 if format == 0:
1973 try:
1975 try:
1974 pp = r.parents(node)
1976 pp = r.parents(node)
1975 except Exception:
1977 except Exception:
1976 pp = [nullid, nullid]
1978 pp = [nullid, nullid]
1977 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1979 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1978 i, r.start(i), r.length(i), base, r.linkrev(i),
1980 i, r.start(i), r.length(i), base, r.linkrev(i),
1979 short(node), short(pp[0]), short(pp[1])))
1981 short(node), short(pp[0]), short(pp[1])))
1980 elif format == 1:
1982 elif format == 1:
1981 pr = r.parentrevs(i)
1983 pr = r.parentrevs(i)
1982 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1984 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1983 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1985 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1984 base, r.linkrev(i), pr[0], pr[1], short(node)))
1986 base, r.linkrev(i), pr[0], pr[1], short(node)))
1985
1987
1986 @command('debugindexdot', [], _('FILE'))
1988 @command('debugindexdot', [], _('FILE'))
1987 def debugindexdot(ui, repo, file_):
1989 def debugindexdot(ui, repo, file_):
1988 """dump an index DAG as a graphviz dot file"""
1990 """dump an index DAG as a graphviz dot file"""
1989 r = None
1991 r = None
1990 if repo:
1992 if repo:
1991 filelog = repo.file(file_)
1993 filelog = repo.file(file_)
1992 if len(filelog):
1994 if len(filelog):
1993 r = filelog
1995 r = filelog
1994 if not r:
1996 if not r:
1995 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1997 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1996 ui.write(("digraph G {\n"))
1998 ui.write(("digraph G {\n"))
1997 for i in r:
1999 for i in r:
1998 node = r.node(i)
2000 node = r.node(i)
1999 pp = r.parents(node)
2001 pp = r.parents(node)
2000 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2002 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2001 if pp[1] != nullid:
2003 if pp[1] != nullid:
2002 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2004 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2003 ui.write("}\n")
2005 ui.write("}\n")
2004
2006
2005 @command('debuginstall', [], '')
2007 @command('debuginstall', [], '')
2006 def debuginstall(ui):
2008 def debuginstall(ui):
2007 '''test Mercurial installation
2009 '''test Mercurial installation
2008
2010
2009 Returns 0 on success.
2011 Returns 0 on success.
2010 '''
2012 '''
2011
2013
2012 def writetemp(contents):
2014 def writetemp(contents):
2013 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2015 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2014 f = os.fdopen(fd, "wb")
2016 f = os.fdopen(fd, "wb")
2015 f.write(contents)
2017 f.write(contents)
2016 f.close()
2018 f.close()
2017 return name
2019 return name
2018
2020
2019 problems = 0
2021 problems = 0
2020
2022
2021 # encoding
2023 # encoding
2022 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2024 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2023 try:
2025 try:
2024 encoding.fromlocal("test")
2026 encoding.fromlocal("test")
2025 except util.Abort, inst:
2027 except util.Abort, inst:
2026 ui.write(" %s\n" % inst)
2028 ui.write(" %s\n" % inst)
2027 ui.write(_(" (check that your locale is properly set)\n"))
2029 ui.write(_(" (check that your locale is properly set)\n"))
2028 problems += 1
2030 problems += 1
2029
2031
2030 # Python lib
2032 # Python lib
2031 ui.status(_("checking Python lib (%s)...\n")
2033 ui.status(_("checking Python lib (%s)...\n")
2032 % os.path.dirname(os.__file__))
2034 % os.path.dirname(os.__file__))
2033
2035
2034 # compiled modules
2036 # compiled modules
2035 ui.status(_("checking installed modules (%s)...\n")
2037 ui.status(_("checking installed modules (%s)...\n")
2036 % os.path.dirname(__file__))
2038 % os.path.dirname(__file__))
2037 try:
2039 try:
2038 import bdiff, mpatch, base85, osutil
2040 import bdiff, mpatch, base85, osutil
2039 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2041 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2040 except Exception, inst:
2042 except Exception, inst:
2041 ui.write(" %s\n" % inst)
2043 ui.write(" %s\n" % inst)
2042 ui.write(_(" One or more extensions could not be found"))
2044 ui.write(_(" One or more extensions could not be found"))
2043 ui.write(_(" (check that you compiled the extensions)\n"))
2045 ui.write(_(" (check that you compiled the extensions)\n"))
2044 problems += 1
2046 problems += 1
2045
2047
2046 # templates
2048 # templates
2047 import templater
2049 import templater
2048 p = templater.templatepath()
2050 p = templater.templatepath()
2049 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2051 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2050 try:
2052 try:
2051 templater.templater(templater.templatepath("map-cmdline.default"))
2053 templater.templater(templater.templatepath("map-cmdline.default"))
2052 except Exception, inst:
2054 except Exception, inst:
2053 ui.write(" %s\n" % inst)
2055 ui.write(" %s\n" % inst)
2054 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2056 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2055 problems += 1
2057 problems += 1
2056
2058
2057 # editor
2059 # editor
2058 ui.status(_("checking commit editor...\n"))
2060 ui.status(_("checking commit editor...\n"))
2059 editor = ui.geteditor()
2061 editor = ui.geteditor()
2060 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2062 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2061 if not cmdpath:
2063 if not cmdpath:
2062 if editor == 'vi':
2064 if editor == 'vi':
2063 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2065 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2064 ui.write(_(" (specify a commit editor in your configuration"
2066 ui.write(_(" (specify a commit editor in your configuration"
2065 " file)\n"))
2067 " file)\n"))
2066 else:
2068 else:
2067 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2069 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2068 ui.write(_(" (specify a commit editor in your configuration"
2070 ui.write(_(" (specify a commit editor in your configuration"
2069 " file)\n"))
2071 " file)\n"))
2070 problems += 1
2072 problems += 1
2071
2073
2072 # check username
2074 # check username
2073 ui.status(_("checking username...\n"))
2075 ui.status(_("checking username...\n"))
2074 try:
2076 try:
2075 ui.username()
2077 ui.username()
2076 except util.Abort, e:
2078 except util.Abort, e:
2077 ui.write(" %s\n" % e)
2079 ui.write(" %s\n" % e)
2078 ui.write(_(" (specify a username in your configuration file)\n"))
2080 ui.write(_(" (specify a username in your configuration file)\n"))
2079 problems += 1
2081 problems += 1
2080
2082
2081 if not problems:
2083 if not problems:
2082 ui.status(_("no problems detected\n"))
2084 ui.status(_("no problems detected\n"))
2083 else:
2085 else:
2084 ui.write(_("%s problems detected,"
2086 ui.write(_("%s problems detected,"
2085 " please check your install!\n") % problems)
2087 " please check your install!\n") % problems)
2086
2088
2087 return problems
2089 return problems
2088
2090
2089 @command('debugknown', [], _('REPO ID...'))
2091 @command('debugknown', [], _('REPO ID...'))
2090 def debugknown(ui, repopath, *ids, **opts):
2092 def debugknown(ui, repopath, *ids, **opts):
2091 """test whether node ids are known to a repo
2093 """test whether node ids are known to a repo
2092
2094
2093 Every ID must be a full-length hex node id string. Returns a list of 0s
2095 Every ID must be a full-length hex node id string. Returns a list of 0s
2094 and 1s indicating unknown/known.
2096 and 1s indicating unknown/known.
2095 """
2097 """
2096 repo = hg.peer(ui, opts, repopath)
2098 repo = hg.peer(ui, opts, repopath)
2097 if not repo.capable('known'):
2099 if not repo.capable('known'):
2098 raise util.Abort("known() not supported by target repository")
2100 raise util.Abort("known() not supported by target repository")
2099 flags = repo.known([bin(s) for s in ids])
2101 flags = repo.known([bin(s) for s in ids])
2100 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2102 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2101
2103
2102 @command('debuglabelcomplete', [], _('LABEL...'))
2104 @command('debuglabelcomplete', [], _('LABEL...'))
2103 def debuglabelcomplete(ui, repo, *args):
2105 def debuglabelcomplete(ui, repo, *args):
2104 '''complete "labels" - tags, open branch names, bookmark names'''
2106 '''complete "labels" - tags, open branch names, bookmark names'''
2105
2107
2106 labels = set()
2108 labels = set()
2107 labels.update(t[0] for t in repo.tagslist())
2109 labels.update(t[0] for t in repo.tagslist())
2108 labels.update(repo._bookmarks.keys())
2110 labels.update(repo._bookmarks.keys())
2109 for heads in repo.branchmap().itervalues():
2111 for heads in repo.branchmap().itervalues():
2110 for h in heads:
2112 for h in heads:
2111 ctx = repo[h]
2113 ctx = repo[h]
2112 if not ctx.closesbranch():
2114 if not ctx.closesbranch():
2113 labels.add(ctx.branch())
2115 labels.add(ctx.branch())
2114 completions = set()
2116 completions = set()
2115 if not args:
2117 if not args:
2116 args = ['']
2118 args = ['']
2117 for a in args:
2119 for a in args:
2118 completions.update(l for l in labels if l.startswith(a))
2120 completions.update(l for l in labels if l.startswith(a))
2119 ui.write('\n'.join(sorted(completions)))
2121 ui.write('\n'.join(sorted(completions)))
2120 ui.write('\n')
2122 ui.write('\n')
2121
2123
2122 @command('debugobsolete',
2124 @command('debugobsolete',
2123 [('', 'flags', 0, _('markers flag')),
2125 [('', 'flags', 0, _('markers flag')),
2124 ] + commitopts2,
2126 ] + commitopts2,
2125 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2127 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2126 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2128 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2127 """create arbitrary obsolete marker
2129 """create arbitrary obsolete marker
2128
2130
2129 With no arguments, displays the list of obsolescence markers."""
2131 With no arguments, displays the list of obsolescence markers."""
2130 def parsenodeid(s):
2132 def parsenodeid(s):
2131 try:
2133 try:
2132 # We do not use revsingle/revrange functions here to accept
2134 # We do not use revsingle/revrange functions here to accept
2133 # arbitrary node identifiers, possibly not present in the
2135 # arbitrary node identifiers, possibly not present in the
2134 # local repository.
2136 # local repository.
2135 n = bin(s)
2137 n = bin(s)
2136 if len(n) != len(nullid):
2138 if len(n) != len(nullid):
2137 raise TypeError()
2139 raise TypeError()
2138 return n
2140 return n
2139 except TypeError:
2141 except TypeError:
2140 raise util.Abort('changeset references must be full hexadecimal '
2142 raise util.Abort('changeset references must be full hexadecimal '
2141 'node identifiers')
2143 'node identifiers')
2142
2144
2143 if precursor is not None:
2145 if precursor is not None:
2144 metadata = {}
2146 metadata = {}
2145 if 'date' in opts:
2147 if 'date' in opts:
2146 metadata['date'] = opts['date']
2148 metadata['date'] = opts['date']
2147 metadata['user'] = opts['user'] or ui.username()
2149 metadata['user'] = opts['user'] or ui.username()
2148 succs = tuple(parsenodeid(succ) for succ in successors)
2150 succs = tuple(parsenodeid(succ) for succ in successors)
2149 l = repo.lock()
2151 l = repo.lock()
2150 try:
2152 try:
2151 tr = repo.transaction('debugobsolete')
2153 tr = repo.transaction('debugobsolete')
2152 try:
2154 try:
2153 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2155 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2154 opts['flags'], metadata)
2156 opts['flags'], metadata)
2155 tr.close()
2157 tr.close()
2156 finally:
2158 finally:
2157 tr.release()
2159 tr.release()
2158 finally:
2160 finally:
2159 l.release()
2161 l.release()
2160 else:
2162 else:
2161 for m in obsolete.allmarkers(repo):
2163 for m in obsolete.allmarkers(repo):
2162 ui.write(hex(m.precnode()))
2164 ui.write(hex(m.precnode()))
2163 for repl in m.succnodes():
2165 for repl in m.succnodes():
2164 ui.write(' ')
2166 ui.write(' ')
2165 ui.write(hex(repl))
2167 ui.write(hex(repl))
2166 ui.write(' %X ' % m._data[2])
2168 ui.write(' %X ' % m._data[2])
2167 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2169 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2168 sorted(m.metadata().items()))))
2170 sorted(m.metadata().items()))))
2169 ui.write('\n')
2171 ui.write('\n')
2170
2172
2171 @command('debugpathcomplete',
2173 @command('debugpathcomplete',
2172 [('f', 'full', None, _('complete an entire path')),
2174 [('f', 'full', None, _('complete an entire path')),
2173 ('n', 'normal', None, _('show only normal files')),
2175 ('n', 'normal', None, _('show only normal files')),
2174 ('a', 'added', None, _('show only added files')),
2176 ('a', 'added', None, _('show only added files')),
2175 ('r', 'removed', None, _('show only removed files'))],
2177 ('r', 'removed', None, _('show only removed files'))],
2176 _('FILESPEC...'))
2178 _('FILESPEC...'))
2177 def debugpathcomplete(ui, repo, *specs, **opts):
2179 def debugpathcomplete(ui, repo, *specs, **opts):
2178 '''complete part or all of a tracked path
2180 '''complete part or all of a tracked path
2179
2181
2180 This command supports shells that offer path name completion. It
2182 This command supports shells that offer path name completion. It
2181 currently completes only files already known to the dirstate.
2183 currently completes only files already known to the dirstate.
2182
2184
2183 Completion extends only to the next path segment unless
2185 Completion extends only to the next path segment unless
2184 --full is specified, in which case entire paths are used.'''
2186 --full is specified, in which case entire paths are used.'''
2185
2187
2186 def complete(path, acceptable):
2188 def complete(path, acceptable):
2187 dirstate = repo.dirstate
2189 dirstate = repo.dirstate
2188 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2190 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2189 rootdir = repo.root + os.sep
2191 rootdir = repo.root + os.sep
2190 if spec != repo.root and not spec.startswith(rootdir):
2192 if spec != repo.root and not spec.startswith(rootdir):
2191 return [], []
2193 return [], []
2192 if os.path.isdir(spec):
2194 if os.path.isdir(spec):
2193 spec += '/'
2195 spec += '/'
2194 spec = spec[len(rootdir):]
2196 spec = spec[len(rootdir):]
2195 fixpaths = os.sep != '/'
2197 fixpaths = os.sep != '/'
2196 if fixpaths:
2198 if fixpaths:
2197 spec = spec.replace(os.sep, '/')
2199 spec = spec.replace(os.sep, '/')
2198 speclen = len(spec)
2200 speclen = len(spec)
2199 fullpaths = opts['full']
2201 fullpaths = opts['full']
2200 files, dirs = set(), set()
2202 files, dirs = set(), set()
2201 adddir, addfile = dirs.add, files.add
2203 adddir, addfile = dirs.add, files.add
2202 for f, st in dirstate.iteritems():
2204 for f, st in dirstate.iteritems():
2203 if f.startswith(spec) and st[0] in acceptable:
2205 if f.startswith(spec) and st[0] in acceptable:
2204 if fixpaths:
2206 if fixpaths:
2205 f = f.replace('/', os.sep)
2207 f = f.replace('/', os.sep)
2206 if fullpaths:
2208 if fullpaths:
2207 addfile(f)
2209 addfile(f)
2208 continue
2210 continue
2209 s = f.find(os.sep, speclen)
2211 s = f.find(os.sep, speclen)
2210 if s >= 0:
2212 if s >= 0:
2211 adddir(f[:s + 1])
2213 adddir(f[:s + 1])
2212 else:
2214 else:
2213 addfile(f)
2215 addfile(f)
2214 return files, dirs
2216 return files, dirs
2215
2217
2216 acceptable = ''
2218 acceptable = ''
2217 if opts['normal']:
2219 if opts['normal']:
2218 acceptable += 'nm'
2220 acceptable += 'nm'
2219 if opts['added']:
2221 if opts['added']:
2220 acceptable += 'a'
2222 acceptable += 'a'
2221 if opts['removed']:
2223 if opts['removed']:
2222 acceptable += 'r'
2224 acceptable += 'r'
2223 cwd = repo.getcwd()
2225 cwd = repo.getcwd()
2224 if not specs:
2226 if not specs:
2225 specs = ['.']
2227 specs = ['.']
2226
2228
2227 files, dirs = set(), set()
2229 files, dirs = set(), set()
2228 for spec in specs:
2230 for spec in specs:
2229 f, d = complete(spec, acceptable or 'nmar')
2231 f, d = complete(spec, acceptable or 'nmar')
2230 files.update(f)
2232 files.update(f)
2231 dirs.update(d)
2233 dirs.update(d)
2232 if not files and len(dirs) == 1:
2234 if not files and len(dirs) == 1:
2233 # force the shell to consider a completion that matches one
2235 # force the shell to consider a completion that matches one
2234 # directory and zero files to be ambiguous
2236 # directory and zero files to be ambiguous
2235 dirs.add(iter(dirs).next() + '.')
2237 dirs.add(iter(dirs).next() + '.')
2236 files.update(dirs)
2238 files.update(dirs)
2237 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2239 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2238 ui.write('\n')
2240 ui.write('\n')
2239
2241
2240 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2242 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2241 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2243 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2242 '''access the pushkey key/value protocol
2244 '''access the pushkey key/value protocol
2243
2245
2244 With two args, list the keys in the given namespace.
2246 With two args, list the keys in the given namespace.
2245
2247
2246 With five args, set a key to new if it currently is set to old.
2248 With five args, set a key to new if it currently is set to old.
2247 Reports success or failure.
2249 Reports success or failure.
2248 '''
2250 '''
2249
2251
2250 target = hg.peer(ui, {}, repopath)
2252 target = hg.peer(ui, {}, repopath)
2251 if keyinfo:
2253 if keyinfo:
2252 key, old, new = keyinfo
2254 key, old, new = keyinfo
2253 r = target.pushkey(namespace, key, old, new)
2255 r = target.pushkey(namespace, key, old, new)
2254 ui.status(str(r) + '\n')
2256 ui.status(str(r) + '\n')
2255 return not r
2257 return not r
2256 else:
2258 else:
2257 for k, v in sorted(target.listkeys(namespace).iteritems()):
2259 for k, v in sorted(target.listkeys(namespace).iteritems()):
2258 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2260 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2259 v.encode('string-escape')))
2261 v.encode('string-escape')))
2260
2262
2261 @command('debugpvec', [], _('A B'))
2263 @command('debugpvec', [], _('A B'))
2262 def debugpvec(ui, repo, a, b=None):
2264 def debugpvec(ui, repo, a, b=None):
2263 ca = scmutil.revsingle(repo, a)
2265 ca = scmutil.revsingle(repo, a)
2264 cb = scmutil.revsingle(repo, b)
2266 cb = scmutil.revsingle(repo, b)
2265 pa = pvec.ctxpvec(ca)
2267 pa = pvec.ctxpvec(ca)
2266 pb = pvec.ctxpvec(cb)
2268 pb = pvec.ctxpvec(cb)
2267 if pa == pb:
2269 if pa == pb:
2268 rel = "="
2270 rel = "="
2269 elif pa > pb:
2271 elif pa > pb:
2270 rel = ">"
2272 rel = ">"
2271 elif pa < pb:
2273 elif pa < pb:
2272 rel = "<"
2274 rel = "<"
2273 elif pa | pb:
2275 elif pa | pb:
2274 rel = "|"
2276 rel = "|"
2275 ui.write(_("a: %s\n") % pa)
2277 ui.write(_("a: %s\n") % pa)
2276 ui.write(_("b: %s\n") % pb)
2278 ui.write(_("b: %s\n") % pb)
2277 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2279 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2278 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2280 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2279 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2281 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2280 pa.distance(pb), rel))
2282 pa.distance(pb), rel))
2281
2283
2282 @command('debugrebuilddirstate|debugrebuildstate',
2284 @command('debugrebuilddirstate|debugrebuildstate',
2283 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2285 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2284 _('[-r REV]'))
2286 _('[-r REV]'))
2285 def debugrebuilddirstate(ui, repo, rev):
2287 def debugrebuilddirstate(ui, repo, rev):
2286 """rebuild the dirstate as it would look like for the given revision
2288 """rebuild the dirstate as it would look like for the given revision
2287
2289
2288 If no revision is specified the first current parent will be used.
2290 If no revision is specified the first current parent will be used.
2289
2291
2290 The dirstate will be set to the files of the given revision.
2292 The dirstate will be set to the files of the given revision.
2291 The actual working directory content or existing dirstate
2293 The actual working directory content or existing dirstate
2292 information such as adds or removes is not considered.
2294 information such as adds or removes is not considered.
2293
2295
2294 One use of this command is to make the next :hg:`status` invocation
2296 One use of this command is to make the next :hg:`status` invocation
2295 check the actual file content.
2297 check the actual file content.
2296 """
2298 """
2297 ctx = scmutil.revsingle(repo, rev)
2299 ctx = scmutil.revsingle(repo, rev)
2298 wlock = repo.wlock()
2300 wlock = repo.wlock()
2299 try:
2301 try:
2300 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2302 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2301 finally:
2303 finally:
2302 wlock.release()
2304 wlock.release()
2303
2305
2304 @command('debugrename',
2306 @command('debugrename',
2305 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2307 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2306 _('[-r REV] FILE'))
2308 _('[-r REV] FILE'))
2307 def debugrename(ui, repo, file1, *pats, **opts):
2309 def debugrename(ui, repo, file1, *pats, **opts):
2308 """dump rename information"""
2310 """dump rename information"""
2309
2311
2310 ctx = scmutil.revsingle(repo, opts.get('rev'))
2312 ctx = scmutil.revsingle(repo, opts.get('rev'))
2311 m = scmutil.match(ctx, (file1,) + pats, opts)
2313 m = scmutil.match(ctx, (file1,) + pats, opts)
2312 for abs in ctx.walk(m):
2314 for abs in ctx.walk(m):
2313 fctx = ctx[abs]
2315 fctx = ctx[abs]
2314 o = fctx.filelog().renamed(fctx.filenode())
2316 o = fctx.filelog().renamed(fctx.filenode())
2315 rel = m.rel(abs)
2317 rel = m.rel(abs)
2316 if o:
2318 if o:
2317 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2319 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2318 else:
2320 else:
2319 ui.write(_("%s not renamed\n") % rel)
2321 ui.write(_("%s not renamed\n") % rel)
2320
2322
2321 @command('debugrevlog',
2323 @command('debugrevlog',
2322 [('c', 'changelog', False, _('open changelog')),
2324 [('c', 'changelog', False, _('open changelog')),
2323 ('m', 'manifest', False, _('open manifest')),
2325 ('m', 'manifest', False, _('open manifest')),
2324 ('d', 'dump', False, _('dump index data'))],
2326 ('d', 'dump', False, _('dump index data'))],
2325 _('-c|-m|FILE'))
2327 _('-c|-m|FILE'))
2326 def debugrevlog(ui, repo, file_ = None, **opts):
2328 def debugrevlog(ui, repo, file_ = None, **opts):
2327 """show data and statistics about a revlog"""
2329 """show data and statistics about a revlog"""
2328 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2330 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2329
2331
2330 if opts.get("dump"):
2332 if opts.get("dump"):
2331 numrevs = len(r)
2333 numrevs = len(r)
2332 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2334 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2333 " rawsize totalsize compression heads\n")
2335 " rawsize totalsize compression heads\n")
2334 ts = 0
2336 ts = 0
2335 heads = set()
2337 heads = set()
2336 for rev in xrange(numrevs):
2338 for rev in xrange(numrevs):
2337 dbase = r.deltaparent(rev)
2339 dbase = r.deltaparent(rev)
2338 if dbase == -1:
2340 if dbase == -1:
2339 dbase = rev
2341 dbase = rev
2340 cbase = r.chainbase(rev)
2342 cbase = r.chainbase(rev)
2341 p1, p2 = r.parentrevs(rev)
2343 p1, p2 = r.parentrevs(rev)
2342 rs = r.rawsize(rev)
2344 rs = r.rawsize(rev)
2343 ts = ts + rs
2345 ts = ts + rs
2344 heads -= set(r.parentrevs(rev))
2346 heads -= set(r.parentrevs(rev))
2345 heads.add(rev)
2347 heads.add(rev)
2346 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2348 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2347 (rev, p1, p2, r.start(rev), r.end(rev),
2349 (rev, p1, p2, r.start(rev), r.end(rev),
2348 r.start(dbase), r.start(cbase),
2350 r.start(dbase), r.start(cbase),
2349 r.start(p1), r.start(p2),
2351 r.start(p1), r.start(p2),
2350 rs, ts, ts / r.end(rev), len(heads)))
2352 rs, ts, ts / r.end(rev), len(heads)))
2351 return 0
2353 return 0
2352
2354
2353 v = r.version
2355 v = r.version
2354 format = v & 0xFFFF
2356 format = v & 0xFFFF
2355 flags = []
2357 flags = []
2356 gdelta = False
2358 gdelta = False
2357 if v & revlog.REVLOGNGINLINEDATA:
2359 if v & revlog.REVLOGNGINLINEDATA:
2358 flags.append('inline')
2360 flags.append('inline')
2359 if v & revlog.REVLOGGENERALDELTA:
2361 if v & revlog.REVLOGGENERALDELTA:
2360 gdelta = True
2362 gdelta = True
2361 flags.append('generaldelta')
2363 flags.append('generaldelta')
2362 if not flags:
2364 if not flags:
2363 flags = ['(none)']
2365 flags = ['(none)']
2364
2366
2365 nummerges = 0
2367 nummerges = 0
2366 numfull = 0
2368 numfull = 0
2367 numprev = 0
2369 numprev = 0
2368 nump1 = 0
2370 nump1 = 0
2369 nump2 = 0
2371 nump2 = 0
2370 numother = 0
2372 numother = 0
2371 nump1prev = 0
2373 nump1prev = 0
2372 nump2prev = 0
2374 nump2prev = 0
2373 chainlengths = []
2375 chainlengths = []
2374
2376
2375 datasize = [None, 0, 0L]
2377 datasize = [None, 0, 0L]
2376 fullsize = [None, 0, 0L]
2378 fullsize = [None, 0, 0L]
2377 deltasize = [None, 0, 0L]
2379 deltasize = [None, 0, 0L]
2378
2380
2379 def addsize(size, l):
2381 def addsize(size, l):
2380 if l[0] is None or size < l[0]:
2382 if l[0] is None or size < l[0]:
2381 l[0] = size
2383 l[0] = size
2382 if size > l[1]:
2384 if size > l[1]:
2383 l[1] = size
2385 l[1] = size
2384 l[2] += size
2386 l[2] += size
2385
2387
2386 numrevs = len(r)
2388 numrevs = len(r)
2387 for rev in xrange(numrevs):
2389 for rev in xrange(numrevs):
2388 p1, p2 = r.parentrevs(rev)
2390 p1, p2 = r.parentrevs(rev)
2389 delta = r.deltaparent(rev)
2391 delta = r.deltaparent(rev)
2390 if format > 0:
2392 if format > 0:
2391 addsize(r.rawsize(rev), datasize)
2393 addsize(r.rawsize(rev), datasize)
2392 if p2 != nullrev:
2394 if p2 != nullrev:
2393 nummerges += 1
2395 nummerges += 1
2394 size = r.length(rev)
2396 size = r.length(rev)
2395 if delta == nullrev:
2397 if delta == nullrev:
2396 chainlengths.append(0)
2398 chainlengths.append(0)
2397 numfull += 1
2399 numfull += 1
2398 addsize(size, fullsize)
2400 addsize(size, fullsize)
2399 else:
2401 else:
2400 chainlengths.append(chainlengths[delta] + 1)
2402 chainlengths.append(chainlengths[delta] + 1)
2401 addsize(size, deltasize)
2403 addsize(size, deltasize)
2402 if delta == rev - 1:
2404 if delta == rev - 1:
2403 numprev += 1
2405 numprev += 1
2404 if delta == p1:
2406 if delta == p1:
2405 nump1prev += 1
2407 nump1prev += 1
2406 elif delta == p2:
2408 elif delta == p2:
2407 nump2prev += 1
2409 nump2prev += 1
2408 elif delta == p1:
2410 elif delta == p1:
2409 nump1 += 1
2411 nump1 += 1
2410 elif delta == p2:
2412 elif delta == p2:
2411 nump2 += 1
2413 nump2 += 1
2412 elif delta != nullrev:
2414 elif delta != nullrev:
2413 numother += 1
2415 numother += 1
2414
2416
2415 # Adjust size min value for empty cases
2417 # Adjust size min value for empty cases
2416 for size in (datasize, fullsize, deltasize):
2418 for size in (datasize, fullsize, deltasize):
2417 if size[0] is None:
2419 if size[0] is None:
2418 size[0] = 0
2420 size[0] = 0
2419
2421
2420 numdeltas = numrevs - numfull
2422 numdeltas = numrevs - numfull
2421 numoprev = numprev - nump1prev - nump2prev
2423 numoprev = numprev - nump1prev - nump2prev
2422 totalrawsize = datasize[2]
2424 totalrawsize = datasize[2]
2423 datasize[2] /= numrevs
2425 datasize[2] /= numrevs
2424 fulltotal = fullsize[2]
2426 fulltotal = fullsize[2]
2425 fullsize[2] /= numfull
2427 fullsize[2] /= numfull
2426 deltatotal = deltasize[2]
2428 deltatotal = deltasize[2]
2427 if numrevs - numfull > 0:
2429 if numrevs - numfull > 0:
2428 deltasize[2] /= numrevs - numfull
2430 deltasize[2] /= numrevs - numfull
2429 totalsize = fulltotal + deltatotal
2431 totalsize = fulltotal + deltatotal
2430 avgchainlen = sum(chainlengths) / numrevs
2432 avgchainlen = sum(chainlengths) / numrevs
2431 compratio = totalrawsize / totalsize
2433 compratio = totalrawsize / totalsize
2432
2434
2433 basedfmtstr = '%%%dd\n'
2435 basedfmtstr = '%%%dd\n'
2434 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2436 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2435
2437
2436 def dfmtstr(max):
2438 def dfmtstr(max):
2437 return basedfmtstr % len(str(max))
2439 return basedfmtstr % len(str(max))
2438 def pcfmtstr(max, padding=0):
2440 def pcfmtstr(max, padding=0):
2439 return basepcfmtstr % (len(str(max)), ' ' * padding)
2441 return basepcfmtstr % (len(str(max)), ' ' * padding)
2440
2442
2441 def pcfmt(value, total):
2443 def pcfmt(value, total):
2442 return (value, 100 * float(value) / total)
2444 return (value, 100 * float(value) / total)
2443
2445
2444 ui.write(('format : %d\n') % format)
2446 ui.write(('format : %d\n') % format)
2445 ui.write(('flags : %s\n') % ', '.join(flags))
2447 ui.write(('flags : %s\n') % ', '.join(flags))
2446
2448
2447 ui.write('\n')
2449 ui.write('\n')
2448 fmt = pcfmtstr(totalsize)
2450 fmt = pcfmtstr(totalsize)
2449 fmt2 = dfmtstr(totalsize)
2451 fmt2 = dfmtstr(totalsize)
2450 ui.write(('revisions : ') + fmt2 % numrevs)
2452 ui.write(('revisions : ') + fmt2 % numrevs)
2451 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2453 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2452 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2454 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2453 ui.write(('revisions : ') + fmt2 % numrevs)
2455 ui.write(('revisions : ') + fmt2 % numrevs)
2454 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2456 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2455 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2457 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2456 ui.write(('revision size : ') + fmt2 % totalsize)
2458 ui.write(('revision size : ') + fmt2 % totalsize)
2457 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2459 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2458 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2460 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2459
2461
2460 ui.write('\n')
2462 ui.write('\n')
2461 fmt = dfmtstr(max(avgchainlen, compratio))
2463 fmt = dfmtstr(max(avgchainlen, compratio))
2462 ui.write(('avg chain length : ') + fmt % avgchainlen)
2464 ui.write(('avg chain length : ') + fmt % avgchainlen)
2463 ui.write(('compression ratio : ') + fmt % compratio)
2465 ui.write(('compression ratio : ') + fmt % compratio)
2464
2466
2465 if format > 0:
2467 if format > 0:
2466 ui.write('\n')
2468 ui.write('\n')
2467 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2469 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2468 % tuple(datasize))
2470 % tuple(datasize))
2469 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2471 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2470 % tuple(fullsize))
2472 % tuple(fullsize))
2471 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2473 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2472 % tuple(deltasize))
2474 % tuple(deltasize))
2473
2475
2474 if numdeltas > 0:
2476 if numdeltas > 0:
2475 ui.write('\n')
2477 ui.write('\n')
2476 fmt = pcfmtstr(numdeltas)
2478 fmt = pcfmtstr(numdeltas)
2477 fmt2 = pcfmtstr(numdeltas, 4)
2479 fmt2 = pcfmtstr(numdeltas, 4)
2478 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2480 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2479 if numprev > 0:
2481 if numprev > 0:
2480 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2482 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2481 numprev))
2483 numprev))
2482 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2484 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2483 numprev))
2485 numprev))
2484 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2486 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2485 numprev))
2487 numprev))
2486 if gdelta:
2488 if gdelta:
2487 ui.write(('deltas against p1 : ')
2489 ui.write(('deltas against p1 : ')
2488 + fmt % pcfmt(nump1, numdeltas))
2490 + fmt % pcfmt(nump1, numdeltas))
2489 ui.write(('deltas against p2 : ')
2491 ui.write(('deltas against p2 : ')
2490 + fmt % pcfmt(nump2, numdeltas))
2492 + fmt % pcfmt(nump2, numdeltas))
2491 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2493 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2492 numdeltas))
2494 numdeltas))
2493
2495
2494 @command('debugrevspec', [], ('REVSPEC'))
2496 @command('debugrevspec', [], ('REVSPEC'))
2495 def debugrevspec(ui, repo, expr):
2497 def debugrevspec(ui, repo, expr):
2496 """parse and apply a revision specification
2498 """parse and apply a revision specification
2497
2499
2498 Use --verbose to print the parsed tree before and after aliases
2500 Use --verbose to print the parsed tree before and after aliases
2499 expansion.
2501 expansion.
2500 """
2502 """
2501 if ui.verbose:
2503 if ui.verbose:
2502 tree = revset.parse(expr)[0]
2504 tree = revset.parse(expr)[0]
2503 ui.note(revset.prettyformat(tree), "\n")
2505 ui.note(revset.prettyformat(tree), "\n")
2504 newtree = revset.findaliases(ui, tree)
2506 newtree = revset.findaliases(ui, tree)
2505 if newtree != tree:
2507 if newtree != tree:
2506 ui.note(revset.prettyformat(newtree), "\n")
2508 ui.note(revset.prettyformat(newtree), "\n")
2507 func = revset.match(ui, expr)
2509 func = revset.match(ui, expr)
2508 for c in func(repo, range(len(repo))):
2510 for c in func(repo, range(len(repo))):
2509 ui.write("%s\n" % c)
2511 ui.write("%s\n" % c)
2510
2512
2511 @command('debugsetparents', [], _('REV1 [REV2]'))
2513 @command('debugsetparents', [], _('REV1 [REV2]'))
2512 def debugsetparents(ui, repo, rev1, rev2=None):
2514 def debugsetparents(ui, repo, rev1, rev2=None):
2513 """manually set the parents of the current working directory
2515 """manually set the parents of the current working directory
2514
2516
2515 This is useful for writing repository conversion tools, but should
2517 This is useful for writing repository conversion tools, but should
2516 be used with care.
2518 be used with care.
2517
2519
2518 Returns 0 on success.
2520 Returns 0 on success.
2519 """
2521 """
2520
2522
2521 r1 = scmutil.revsingle(repo, rev1).node()
2523 r1 = scmutil.revsingle(repo, rev1).node()
2522 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2524 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2523
2525
2524 wlock = repo.wlock()
2526 wlock = repo.wlock()
2525 try:
2527 try:
2526 repo.setparents(r1, r2)
2528 repo.setparents(r1, r2)
2527 finally:
2529 finally:
2528 wlock.release()
2530 wlock.release()
2529
2531
2530 @command('debugdirstate|debugstate',
2532 @command('debugdirstate|debugstate',
2531 [('', 'nodates', None, _('do not display the saved mtime')),
2533 [('', 'nodates', None, _('do not display the saved mtime')),
2532 ('', 'datesort', None, _('sort by saved mtime'))],
2534 ('', 'datesort', None, _('sort by saved mtime'))],
2533 _('[OPTION]...'))
2535 _('[OPTION]...'))
2534 def debugstate(ui, repo, nodates=None, datesort=None):
2536 def debugstate(ui, repo, nodates=None, datesort=None):
2535 """show the contents of the current dirstate"""
2537 """show the contents of the current dirstate"""
2536 timestr = ""
2538 timestr = ""
2537 showdate = not nodates
2539 showdate = not nodates
2538 if datesort:
2540 if datesort:
2539 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2541 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2540 else:
2542 else:
2541 keyfunc = None # sort by filename
2543 keyfunc = None # sort by filename
2542 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2544 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2543 if showdate:
2545 if showdate:
2544 if ent[3] == -1:
2546 if ent[3] == -1:
2545 # Pad or slice to locale representation
2547 # Pad or slice to locale representation
2546 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2548 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2547 time.localtime(0)))
2549 time.localtime(0)))
2548 timestr = 'unset'
2550 timestr = 'unset'
2549 timestr = (timestr[:locale_len] +
2551 timestr = (timestr[:locale_len] +
2550 ' ' * (locale_len - len(timestr)))
2552 ' ' * (locale_len - len(timestr)))
2551 else:
2553 else:
2552 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2554 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2553 time.localtime(ent[3]))
2555 time.localtime(ent[3]))
2554 if ent[1] & 020000:
2556 if ent[1] & 020000:
2555 mode = 'lnk'
2557 mode = 'lnk'
2556 else:
2558 else:
2557 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2559 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2558 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2560 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2559 for f in repo.dirstate.copies():
2561 for f in repo.dirstate.copies():
2560 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2562 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2561
2563
2562 @command('debugsub',
2564 @command('debugsub',
2563 [('r', 'rev', '',
2565 [('r', 'rev', '',
2564 _('revision to check'), _('REV'))],
2566 _('revision to check'), _('REV'))],
2565 _('[-r REV] [REV]'))
2567 _('[-r REV] [REV]'))
2566 def debugsub(ui, repo, rev=None):
2568 def debugsub(ui, repo, rev=None):
2567 ctx = scmutil.revsingle(repo, rev, None)
2569 ctx = scmutil.revsingle(repo, rev, None)
2568 for k, v in sorted(ctx.substate.items()):
2570 for k, v in sorted(ctx.substate.items()):
2569 ui.write(('path %s\n') % k)
2571 ui.write(('path %s\n') % k)
2570 ui.write((' source %s\n') % v[0])
2572 ui.write((' source %s\n') % v[0])
2571 ui.write((' revision %s\n') % v[1])
2573 ui.write((' revision %s\n') % v[1])
2572
2574
2573 @command('debugsuccessorssets',
2575 @command('debugsuccessorssets',
2574 [],
2576 [],
2575 _('[REV]'))
2577 _('[REV]'))
2576 def debugsuccessorssets(ui, repo, *revs):
2578 def debugsuccessorssets(ui, repo, *revs):
2577 """show set of successors for revision
2579 """show set of successors for revision
2578
2580
2579 A successors set of changeset A is a consistent group of revisions that
2581 A successors set of changeset A is a consistent group of revisions that
2580 succeed A. It contains non-obsolete changesets only.
2582 succeed A. It contains non-obsolete changesets only.
2581
2583
2582 In most cases a changeset A has a single successors set containing a single
2584 In most cases a changeset A has a single successors set containing a single
2583 successor (changeset A replaced by A').
2585 successor (changeset A replaced by A').
2584
2586
2585 A changeset that is made obsolete with no successors are called "pruned".
2587 A changeset that is made obsolete with no successors are called "pruned".
2586 Such changesets have no successors sets at all.
2588 Such changesets have no successors sets at all.
2587
2589
2588 A changeset that has been "split" will have a successors set containing
2590 A changeset that has been "split" will have a successors set containing
2589 more than one successor.
2591 more than one successor.
2590
2592
2591 A changeset that has been rewritten in multiple different ways is called
2593 A changeset that has been rewritten in multiple different ways is called
2592 "divergent". Such changesets have multiple successor sets (each of which
2594 "divergent". Such changesets have multiple successor sets (each of which
2593 may also be split, i.e. have multiple successors).
2595 may also be split, i.e. have multiple successors).
2594
2596
2595 Results are displayed as follows::
2597 Results are displayed as follows::
2596
2598
2597 <rev1>
2599 <rev1>
2598 <successors-1A>
2600 <successors-1A>
2599 <rev2>
2601 <rev2>
2600 <successors-2A>
2602 <successors-2A>
2601 <successors-2B1> <successors-2B2> <successors-2B3>
2603 <successors-2B1> <successors-2B2> <successors-2B3>
2602
2604
2603 Here rev2 has two possible (i.e. divergent) successors sets. The first
2605 Here rev2 has two possible (i.e. divergent) successors sets. The first
2604 holds one element, whereas the second holds three (i.e. the changeset has
2606 holds one element, whereas the second holds three (i.e. the changeset has
2605 been split).
2607 been split).
2606 """
2608 """
2607 # passed to successorssets caching computation from one call to another
2609 # passed to successorssets caching computation from one call to another
2608 cache = {}
2610 cache = {}
2609 ctx2str = str
2611 ctx2str = str
2610 node2str = short
2612 node2str = short
2611 if ui.debug():
2613 if ui.debug():
2612 def ctx2str(ctx):
2614 def ctx2str(ctx):
2613 return ctx.hex()
2615 return ctx.hex()
2614 node2str = hex
2616 node2str = hex
2615 for rev in scmutil.revrange(repo, revs):
2617 for rev in scmutil.revrange(repo, revs):
2616 ctx = repo[rev]
2618 ctx = repo[rev]
2617 ui.write('%s\n'% ctx2str(ctx))
2619 ui.write('%s\n'% ctx2str(ctx))
2618 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2620 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2619 if succsset:
2621 if succsset:
2620 ui.write(' ')
2622 ui.write(' ')
2621 ui.write(node2str(succsset[0]))
2623 ui.write(node2str(succsset[0]))
2622 for node in succsset[1:]:
2624 for node in succsset[1:]:
2623 ui.write(' ')
2625 ui.write(' ')
2624 ui.write(node2str(node))
2626 ui.write(node2str(node))
2625 ui.write('\n')
2627 ui.write('\n')
2626
2628
2627 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2629 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2628 def debugwalk(ui, repo, *pats, **opts):
2630 def debugwalk(ui, repo, *pats, **opts):
2629 """show how files match on given patterns"""
2631 """show how files match on given patterns"""
2630 m = scmutil.match(repo[None], pats, opts)
2632 m = scmutil.match(repo[None], pats, opts)
2631 items = list(repo.walk(m))
2633 items = list(repo.walk(m))
2632 if not items:
2634 if not items:
2633 return
2635 return
2634 f = lambda fn: fn
2636 f = lambda fn: fn
2635 if ui.configbool('ui', 'slash') and os.sep != '/':
2637 if ui.configbool('ui', 'slash') and os.sep != '/':
2636 f = lambda fn: util.normpath(fn)
2638 f = lambda fn: util.normpath(fn)
2637 fmt = 'f %%-%ds %%-%ds %%s' % (
2639 fmt = 'f %%-%ds %%-%ds %%s' % (
2638 max([len(abs) for abs in items]),
2640 max([len(abs) for abs in items]),
2639 max([len(m.rel(abs)) for abs in items]))
2641 max([len(m.rel(abs)) for abs in items]))
2640 for abs in items:
2642 for abs in items:
2641 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2643 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2642 ui.write("%s\n" % line.rstrip())
2644 ui.write("%s\n" % line.rstrip())
2643
2645
2644 @command('debugwireargs',
2646 @command('debugwireargs',
2645 [('', 'three', '', 'three'),
2647 [('', 'three', '', 'three'),
2646 ('', 'four', '', 'four'),
2648 ('', 'four', '', 'four'),
2647 ('', 'five', '', 'five'),
2649 ('', 'five', '', 'five'),
2648 ] + remoteopts,
2650 ] + remoteopts,
2649 _('REPO [OPTIONS]... [ONE [TWO]]'))
2651 _('REPO [OPTIONS]... [ONE [TWO]]'))
2650 def debugwireargs(ui, repopath, *vals, **opts):
2652 def debugwireargs(ui, repopath, *vals, **opts):
2651 repo = hg.peer(ui, opts, repopath)
2653 repo = hg.peer(ui, opts, repopath)
2652 for opt in remoteopts:
2654 for opt in remoteopts:
2653 del opts[opt[1]]
2655 del opts[opt[1]]
2654 args = {}
2656 args = {}
2655 for k, v in opts.iteritems():
2657 for k, v in opts.iteritems():
2656 if v:
2658 if v:
2657 args[k] = v
2659 args[k] = v
2658 # run twice to check that we don't mess up the stream for the next command
2660 # run twice to check that we don't mess up the stream for the next command
2659 res1 = repo.debugwireargs(*vals, **args)
2661 res1 = repo.debugwireargs(*vals, **args)
2660 res2 = repo.debugwireargs(*vals, **args)
2662 res2 = repo.debugwireargs(*vals, **args)
2661 ui.write("%s\n" % res1)
2663 ui.write("%s\n" % res1)
2662 if res1 != res2:
2664 if res1 != res2:
2663 ui.warn("%s\n" % res2)
2665 ui.warn("%s\n" % res2)
2664
2666
2665 @command('^diff',
2667 @command('^diff',
2666 [('r', 'rev', [], _('revision'), _('REV')),
2668 [('r', 'rev', [], _('revision'), _('REV')),
2667 ('c', 'change', '', _('change made by revision'), _('REV'))
2669 ('c', 'change', '', _('change made by revision'), _('REV'))
2668 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2670 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2669 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2671 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2670 def diff(ui, repo, *pats, **opts):
2672 def diff(ui, repo, *pats, **opts):
2671 """diff repository (or selected files)
2673 """diff repository (or selected files)
2672
2674
2673 Show differences between revisions for the specified files.
2675 Show differences between revisions for the specified files.
2674
2676
2675 Differences between files are shown using the unified diff format.
2677 Differences between files are shown using the unified diff format.
2676
2678
2677 .. note::
2679 .. note::
2678 diff may generate unexpected results for merges, as it will
2680 diff may generate unexpected results for merges, as it will
2679 default to comparing against the working directory's first
2681 default to comparing against the working directory's first
2680 parent changeset if no revisions are specified.
2682 parent changeset if no revisions are specified.
2681
2683
2682 When two revision arguments are given, then changes are shown
2684 When two revision arguments are given, then changes are shown
2683 between those revisions. If only one revision is specified then
2685 between those revisions. If only one revision is specified then
2684 that revision is compared to the working directory, and, when no
2686 that revision is compared to the working directory, and, when no
2685 revisions are specified, the working directory files are compared
2687 revisions are specified, the working directory files are compared
2686 to its parent.
2688 to its parent.
2687
2689
2688 Alternatively you can specify -c/--change with a revision to see
2690 Alternatively you can specify -c/--change with a revision to see
2689 the changes in that changeset relative to its first parent.
2691 the changes in that changeset relative to its first parent.
2690
2692
2691 Without the -a/--text option, diff will avoid generating diffs of
2693 Without the -a/--text option, diff will avoid generating diffs of
2692 files it detects as binary. With -a, diff will generate a diff
2694 files it detects as binary. With -a, diff will generate a diff
2693 anyway, probably with undesirable results.
2695 anyway, probably with undesirable results.
2694
2696
2695 Use the -g/--git option to generate diffs in the git extended diff
2697 Use the -g/--git option to generate diffs in the git extended diff
2696 format. For more information, read :hg:`help diffs`.
2698 format. For more information, read :hg:`help diffs`.
2697
2699
2698 .. container:: verbose
2700 .. container:: verbose
2699
2701
2700 Examples:
2702 Examples:
2701
2703
2702 - compare a file in the current working directory to its parent::
2704 - compare a file in the current working directory to its parent::
2703
2705
2704 hg diff foo.c
2706 hg diff foo.c
2705
2707
2706 - compare two historical versions of a directory, with rename info::
2708 - compare two historical versions of a directory, with rename info::
2707
2709
2708 hg diff --git -r 1.0:1.2 lib/
2710 hg diff --git -r 1.0:1.2 lib/
2709
2711
2710 - get change stats relative to the last change on some date::
2712 - get change stats relative to the last change on some date::
2711
2713
2712 hg diff --stat -r "date('may 2')"
2714 hg diff --stat -r "date('may 2')"
2713
2715
2714 - diff all newly-added files that contain a keyword::
2716 - diff all newly-added files that contain a keyword::
2715
2717
2716 hg diff "set:added() and grep(GNU)"
2718 hg diff "set:added() and grep(GNU)"
2717
2719
2718 - compare a revision and its parents::
2720 - compare a revision and its parents::
2719
2721
2720 hg diff -c 9353 # compare against first parent
2722 hg diff -c 9353 # compare against first parent
2721 hg diff -r 9353^:9353 # same using revset syntax
2723 hg diff -r 9353^:9353 # same using revset syntax
2722 hg diff -r 9353^2:9353 # compare against the second parent
2724 hg diff -r 9353^2:9353 # compare against the second parent
2723
2725
2724 Returns 0 on success.
2726 Returns 0 on success.
2725 """
2727 """
2726
2728
2727 revs = opts.get('rev')
2729 revs = opts.get('rev')
2728 change = opts.get('change')
2730 change = opts.get('change')
2729 stat = opts.get('stat')
2731 stat = opts.get('stat')
2730 reverse = opts.get('reverse')
2732 reverse = opts.get('reverse')
2731
2733
2732 if revs and change:
2734 if revs and change:
2733 msg = _('cannot specify --rev and --change at the same time')
2735 msg = _('cannot specify --rev and --change at the same time')
2734 raise util.Abort(msg)
2736 raise util.Abort(msg)
2735 elif change:
2737 elif change:
2736 node2 = scmutil.revsingle(repo, change, None).node()
2738 node2 = scmutil.revsingle(repo, change, None).node()
2737 node1 = repo[node2].p1().node()
2739 node1 = repo[node2].p1().node()
2738 else:
2740 else:
2739 node1, node2 = scmutil.revpair(repo, revs)
2741 node1, node2 = scmutil.revpair(repo, revs)
2740
2742
2741 if reverse:
2743 if reverse:
2742 node1, node2 = node2, node1
2744 node1, node2 = node2, node1
2743
2745
2744 diffopts = patch.diffopts(ui, opts)
2746 diffopts = patch.diffopts(ui, opts)
2745 m = scmutil.match(repo[node2], pats, opts)
2747 m = scmutil.match(repo[node2], pats, opts)
2746 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2748 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2747 listsubrepos=opts.get('subrepos'))
2749 listsubrepos=opts.get('subrepos'))
2748
2750
2749 @command('^export',
2751 @command('^export',
2750 [('o', 'output', '',
2752 [('o', 'output', '',
2751 _('print output to file with formatted name'), _('FORMAT')),
2753 _('print output to file with formatted name'), _('FORMAT')),
2752 ('', 'switch-parent', None, _('diff against the second parent')),
2754 ('', 'switch-parent', None, _('diff against the second parent')),
2753 ('r', 'rev', [], _('revisions to export'), _('REV')),
2755 ('r', 'rev', [], _('revisions to export'), _('REV')),
2754 ] + diffopts,
2756 ] + diffopts,
2755 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2757 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2756 def export(ui, repo, *changesets, **opts):
2758 def export(ui, repo, *changesets, **opts):
2757 """dump the header and diffs for one or more changesets
2759 """dump the header and diffs for one or more changesets
2758
2760
2759 Print the changeset header and diffs for one or more revisions.
2761 Print the changeset header and diffs for one or more revisions.
2760 If no revision is given, the parent of the working directory is used.
2762 If no revision is given, the parent of the working directory is used.
2761
2763
2762 The information shown in the changeset header is: author, date,
2764 The information shown in the changeset header is: author, date,
2763 branch name (if non-default), changeset hash, parent(s) and commit
2765 branch name (if non-default), changeset hash, parent(s) and commit
2764 comment.
2766 comment.
2765
2767
2766 .. note::
2768 .. note::
2767 export may generate unexpected diff output for merge
2769 export may generate unexpected diff output for merge
2768 changesets, as it will compare the merge changeset against its
2770 changesets, as it will compare the merge changeset against its
2769 first parent only.
2771 first parent only.
2770
2772
2771 Output may be to a file, in which case the name of the file is
2773 Output may be to a file, in which case the name of the file is
2772 given using a format string. The formatting rules are as follows:
2774 given using a format string. The formatting rules are as follows:
2773
2775
2774 :``%%``: literal "%" character
2776 :``%%``: literal "%" character
2775 :``%H``: changeset hash (40 hexadecimal digits)
2777 :``%H``: changeset hash (40 hexadecimal digits)
2776 :``%N``: number of patches being generated
2778 :``%N``: number of patches being generated
2777 :``%R``: changeset revision number
2779 :``%R``: changeset revision number
2778 :``%b``: basename of the exporting repository
2780 :``%b``: basename of the exporting repository
2779 :``%h``: short-form changeset hash (12 hexadecimal digits)
2781 :``%h``: short-form changeset hash (12 hexadecimal digits)
2780 :``%m``: first line of the commit message (only alphanumeric characters)
2782 :``%m``: first line of the commit message (only alphanumeric characters)
2781 :``%n``: zero-padded sequence number, starting at 1
2783 :``%n``: zero-padded sequence number, starting at 1
2782 :``%r``: zero-padded changeset revision number
2784 :``%r``: zero-padded changeset revision number
2783
2785
2784 Without the -a/--text option, export will avoid generating diffs
2786 Without the -a/--text option, export will avoid generating diffs
2785 of files it detects as binary. With -a, export will generate a
2787 of files it detects as binary. With -a, export will generate a
2786 diff anyway, probably with undesirable results.
2788 diff anyway, probably with undesirable results.
2787
2789
2788 Use the -g/--git option to generate diffs in the git extended diff
2790 Use the -g/--git option to generate diffs in the git extended diff
2789 format. See :hg:`help diffs` for more information.
2791 format. See :hg:`help diffs` for more information.
2790
2792
2791 With the --switch-parent option, the diff will be against the
2793 With the --switch-parent option, the diff will be against the
2792 second parent. It can be useful to review a merge.
2794 second parent. It can be useful to review a merge.
2793
2795
2794 .. container:: verbose
2796 .. container:: verbose
2795
2797
2796 Examples:
2798 Examples:
2797
2799
2798 - use export and import to transplant a bugfix to the current
2800 - use export and import to transplant a bugfix to the current
2799 branch::
2801 branch::
2800
2802
2801 hg export -r 9353 | hg import -
2803 hg export -r 9353 | hg import -
2802
2804
2803 - export all the changesets between two revisions to a file with
2805 - export all the changesets between two revisions to a file with
2804 rename information::
2806 rename information::
2805
2807
2806 hg export --git -r 123:150 > changes.txt
2808 hg export --git -r 123:150 > changes.txt
2807
2809
2808 - split outgoing changes into a series of patches with
2810 - split outgoing changes into a series of patches with
2809 descriptive names::
2811 descriptive names::
2810
2812
2811 hg export -r "outgoing()" -o "%n-%m.patch"
2813 hg export -r "outgoing()" -o "%n-%m.patch"
2812
2814
2813 Returns 0 on success.
2815 Returns 0 on success.
2814 """
2816 """
2815 changesets += tuple(opts.get('rev', []))
2817 changesets += tuple(opts.get('rev', []))
2816 if not changesets:
2818 if not changesets:
2817 changesets = ['.']
2819 changesets = ['.']
2818 revs = scmutil.revrange(repo, changesets)
2820 revs = scmutil.revrange(repo, changesets)
2819 if not revs:
2821 if not revs:
2820 raise util.Abort(_("export requires at least one changeset"))
2822 raise util.Abort(_("export requires at least one changeset"))
2821 if len(revs) > 1:
2823 if len(revs) > 1:
2822 ui.note(_('exporting patches:\n'))
2824 ui.note(_('exporting patches:\n'))
2823 else:
2825 else:
2824 ui.note(_('exporting patch:\n'))
2826 ui.note(_('exporting patch:\n'))
2825 cmdutil.export(repo, revs, template=opts.get('output'),
2827 cmdutil.export(repo, revs, template=opts.get('output'),
2826 switch_parent=opts.get('switch_parent'),
2828 switch_parent=opts.get('switch_parent'),
2827 opts=patch.diffopts(ui, opts))
2829 opts=patch.diffopts(ui, opts))
2828
2830
2829 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2831 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2830 def forget(ui, repo, *pats, **opts):
2832 def forget(ui, repo, *pats, **opts):
2831 """forget the specified files on the next commit
2833 """forget the specified files on the next commit
2832
2834
2833 Mark the specified files so they will no longer be tracked
2835 Mark the specified files so they will no longer be tracked
2834 after the next commit.
2836 after the next commit.
2835
2837
2836 This only removes files from the current branch, not from the
2838 This only removes files from the current branch, not from the
2837 entire project history, and it does not delete them from the
2839 entire project history, and it does not delete them from the
2838 working directory.
2840 working directory.
2839
2841
2840 To undo a forget before the next commit, see :hg:`add`.
2842 To undo a forget before the next commit, see :hg:`add`.
2841
2843
2842 .. container:: verbose
2844 .. container:: verbose
2843
2845
2844 Examples:
2846 Examples:
2845
2847
2846 - forget newly-added binary files::
2848 - forget newly-added binary files::
2847
2849
2848 hg forget "set:added() and binary()"
2850 hg forget "set:added() and binary()"
2849
2851
2850 - forget files that would be excluded by .hgignore::
2852 - forget files that would be excluded by .hgignore::
2851
2853
2852 hg forget "set:hgignore()"
2854 hg forget "set:hgignore()"
2853
2855
2854 Returns 0 on success.
2856 Returns 0 on success.
2855 """
2857 """
2856
2858
2857 if not pats:
2859 if not pats:
2858 raise util.Abort(_('no files specified'))
2860 raise util.Abort(_('no files specified'))
2859
2861
2860 m = scmutil.match(repo[None], pats, opts)
2862 m = scmutil.match(repo[None], pats, opts)
2861 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2863 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2862 return rejected and 1 or 0
2864 return rejected and 1 or 0
2863
2865
2864 @command(
2866 @command(
2865 'graft',
2867 'graft',
2866 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2868 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2867 ('c', 'continue', False, _('resume interrupted graft')),
2869 ('c', 'continue', False, _('resume interrupted graft')),
2868 ('e', 'edit', False, _('invoke editor on commit messages')),
2870 ('e', 'edit', False, _('invoke editor on commit messages')),
2869 ('', 'log', None, _('append graft info to log message')),
2871 ('', 'log', None, _('append graft info to log message')),
2870 ('D', 'currentdate', False,
2872 ('D', 'currentdate', False,
2871 _('record the current date as commit date')),
2873 _('record the current date as commit date')),
2872 ('U', 'currentuser', False,
2874 ('U', 'currentuser', False,
2873 _('record the current user as committer'), _('DATE'))]
2875 _('record the current user as committer'), _('DATE'))]
2874 + commitopts2 + mergetoolopts + dryrunopts,
2876 + commitopts2 + mergetoolopts + dryrunopts,
2875 _('[OPTION]... [-r] REV...'))
2877 _('[OPTION]... [-r] REV...'))
2876 def graft(ui, repo, *revs, **opts):
2878 def graft(ui, repo, *revs, **opts):
2877 '''copy changes from other branches onto the current branch
2879 '''copy changes from other branches onto the current branch
2878
2880
2879 This command uses Mercurial's merge logic to copy individual
2881 This command uses Mercurial's merge logic to copy individual
2880 changes from other branches without merging branches in the
2882 changes from other branches without merging branches in the
2881 history graph. This is sometimes known as 'backporting' or
2883 history graph. This is sometimes known as 'backporting' or
2882 'cherry-picking'. By default, graft will copy user, date, and
2884 'cherry-picking'. By default, graft will copy user, date, and
2883 description from the source changesets.
2885 description from the source changesets.
2884
2886
2885 Changesets that are ancestors of the current revision, that have
2887 Changesets that are ancestors of the current revision, that have
2886 already been grafted, or that are merges will be skipped.
2888 already been grafted, or that are merges will be skipped.
2887
2889
2888 If --log is specified, log messages will have a comment appended
2890 If --log is specified, log messages will have a comment appended
2889 of the form::
2891 of the form::
2890
2892
2891 (grafted from CHANGESETHASH)
2893 (grafted from CHANGESETHASH)
2892
2894
2893 If a graft merge results in conflicts, the graft process is
2895 If a graft merge results in conflicts, the graft process is
2894 interrupted so that the current merge can be manually resolved.
2896 interrupted so that the current merge can be manually resolved.
2895 Once all conflicts are addressed, the graft process can be
2897 Once all conflicts are addressed, the graft process can be
2896 continued with the -c/--continue option.
2898 continued with the -c/--continue option.
2897
2899
2898 .. note::
2900 .. note::
2899 The -c/--continue option does not reapply earlier options.
2901 The -c/--continue option does not reapply earlier options.
2900
2902
2901 .. container:: verbose
2903 .. container:: verbose
2902
2904
2903 Examples:
2905 Examples:
2904
2906
2905 - copy a single change to the stable branch and edit its description::
2907 - copy a single change to the stable branch and edit its description::
2906
2908
2907 hg update stable
2909 hg update stable
2908 hg graft --edit 9393
2910 hg graft --edit 9393
2909
2911
2910 - graft a range of changesets with one exception, updating dates::
2912 - graft a range of changesets with one exception, updating dates::
2911
2913
2912 hg graft -D "2085::2093 and not 2091"
2914 hg graft -D "2085::2093 and not 2091"
2913
2915
2914 - continue a graft after resolving conflicts::
2916 - continue a graft after resolving conflicts::
2915
2917
2916 hg graft -c
2918 hg graft -c
2917
2919
2918 - show the source of a grafted changeset::
2920 - show the source of a grafted changeset::
2919
2921
2920 hg log --debug -r tip
2922 hg log --debug -r tip
2921
2923
2922 Returns 0 on successful completion.
2924 Returns 0 on successful completion.
2923 '''
2925 '''
2924
2926
2925 revs = list(revs)
2927 revs = list(revs)
2926 revs.extend(opts['rev'])
2928 revs.extend(opts['rev'])
2927
2929
2928 if not opts.get('user') and opts.get('currentuser'):
2930 if not opts.get('user') and opts.get('currentuser'):
2929 opts['user'] = ui.username()
2931 opts['user'] = ui.username()
2930 if not opts.get('date') and opts.get('currentdate'):
2932 if not opts.get('date') and opts.get('currentdate'):
2931 opts['date'] = "%d %d" % util.makedate()
2933 opts['date'] = "%d %d" % util.makedate()
2932
2934
2933 editor = None
2935 editor = None
2934 if opts.get('edit'):
2936 if opts.get('edit'):
2935 editor = cmdutil.commitforceeditor
2937 editor = cmdutil.commitforceeditor
2936
2938
2937 cont = False
2939 cont = False
2938 if opts['continue']:
2940 if opts['continue']:
2939 cont = True
2941 cont = True
2940 if revs:
2942 if revs:
2941 raise util.Abort(_("can't specify --continue and revisions"))
2943 raise util.Abort(_("can't specify --continue and revisions"))
2942 # read in unfinished revisions
2944 # read in unfinished revisions
2943 try:
2945 try:
2944 nodes = repo.opener.read('graftstate').splitlines()
2946 nodes = repo.opener.read('graftstate').splitlines()
2945 revs = [repo[node].rev() for node in nodes]
2947 revs = [repo[node].rev() for node in nodes]
2946 except IOError, inst:
2948 except IOError, inst:
2947 if inst.errno != errno.ENOENT:
2949 if inst.errno != errno.ENOENT:
2948 raise
2950 raise
2949 raise util.Abort(_("no graft state found, can't continue"))
2951 raise util.Abort(_("no graft state found, can't continue"))
2950 else:
2952 else:
2951 cmdutil.bailifchanged(repo)
2953 cmdutil.bailifchanged(repo)
2952 if not revs:
2954 if not revs:
2953 raise util.Abort(_('no revisions specified'))
2955 raise util.Abort(_('no revisions specified'))
2954 revs = scmutil.revrange(repo, revs)
2956 revs = scmutil.revrange(repo, revs)
2955
2957
2956 # check for merges
2958 # check for merges
2957 for rev in repo.revs('%ld and merge()', revs):
2959 for rev in repo.revs('%ld and merge()', revs):
2958 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2960 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2959 revs.remove(rev)
2961 revs.remove(rev)
2960 if not revs:
2962 if not revs:
2961 return -1
2963 return -1
2962
2964
2963 # check for ancestors of dest branch
2965 # check for ancestors of dest branch
2964 crev = repo['.'].rev()
2966 crev = repo['.'].rev()
2965 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2967 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2966 # don't mutate while iterating, create a copy
2968 # don't mutate while iterating, create a copy
2967 for rev in list(revs):
2969 for rev in list(revs):
2968 if rev in ancestors:
2970 if rev in ancestors:
2969 ui.warn(_('skipping ancestor revision %s\n') % rev)
2971 ui.warn(_('skipping ancestor revision %s\n') % rev)
2970 revs.remove(rev)
2972 revs.remove(rev)
2971 if not revs:
2973 if not revs:
2972 return -1
2974 return -1
2973
2975
2974 # analyze revs for earlier grafts
2976 # analyze revs for earlier grafts
2975 ids = {}
2977 ids = {}
2976 for ctx in repo.set("%ld", revs):
2978 for ctx in repo.set("%ld", revs):
2977 ids[ctx.hex()] = ctx.rev()
2979 ids[ctx.hex()] = ctx.rev()
2978 n = ctx.extra().get('source')
2980 n = ctx.extra().get('source')
2979 if n:
2981 if n:
2980 ids[n] = ctx.rev()
2982 ids[n] = ctx.rev()
2981
2983
2982 # check ancestors for earlier grafts
2984 # check ancestors for earlier grafts
2983 ui.debug('scanning for duplicate grafts\n')
2985 ui.debug('scanning for duplicate grafts\n')
2984
2986
2985 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2987 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2986 ctx = repo[rev]
2988 ctx = repo[rev]
2987 n = ctx.extra().get('source')
2989 n = ctx.extra().get('source')
2988 if n in ids:
2990 if n in ids:
2989 r = repo[n].rev()
2991 r = repo[n].rev()
2990 if r in revs:
2992 if r in revs:
2991 ui.warn(_('skipping already grafted revision %s\n') % r)
2993 ui.warn(_('skipping already grafted revision %s\n') % r)
2992 revs.remove(r)
2994 revs.remove(r)
2993 elif ids[n] in revs:
2995 elif ids[n] in revs:
2994 ui.warn(_('skipping already grafted revision %s '
2996 ui.warn(_('skipping already grafted revision %s '
2995 '(same origin %d)\n') % (ids[n], r))
2997 '(same origin %d)\n') % (ids[n], r))
2996 revs.remove(ids[n])
2998 revs.remove(ids[n])
2997 elif ctx.hex() in ids:
2999 elif ctx.hex() in ids:
2998 r = ids[ctx.hex()]
3000 r = ids[ctx.hex()]
2999 ui.warn(_('skipping already grafted revision %s '
3001 ui.warn(_('skipping already grafted revision %s '
3000 '(was grafted from %d)\n') % (r, rev))
3002 '(was grafted from %d)\n') % (r, rev))
3001 revs.remove(r)
3003 revs.remove(r)
3002 if not revs:
3004 if not revs:
3003 return -1
3005 return -1
3004
3006
3005 wlock = repo.wlock()
3007 wlock = repo.wlock()
3006 try:
3008 try:
3007 current = repo['.']
3009 current = repo['.']
3008 for pos, ctx in enumerate(repo.set("%ld", revs)):
3010 for pos, ctx in enumerate(repo.set("%ld", revs)):
3009
3011
3010 ui.status(_('grafting revision %s\n') % ctx.rev())
3012 ui.status(_('grafting revision %s\n') % ctx.rev())
3011 if opts.get('dry_run'):
3013 if opts.get('dry_run'):
3012 continue
3014 continue
3013
3015
3014 source = ctx.extra().get('source')
3016 source = ctx.extra().get('source')
3015 if not source:
3017 if not source:
3016 source = ctx.hex()
3018 source = ctx.hex()
3017 extra = {'source': source}
3019 extra = {'source': source}
3018 user = ctx.user()
3020 user = ctx.user()
3019 if opts.get('user'):
3021 if opts.get('user'):
3020 user = opts['user']
3022 user = opts['user']
3021 date = ctx.date()
3023 date = ctx.date()
3022 if opts.get('date'):
3024 if opts.get('date'):
3023 date = opts['date']
3025 date = opts['date']
3024 message = ctx.description()
3026 message = ctx.description()
3025 if opts.get('log'):
3027 if opts.get('log'):
3026 message += '\n(grafted from %s)' % ctx.hex()
3028 message += '\n(grafted from %s)' % ctx.hex()
3027
3029
3028 # we don't merge the first commit when continuing
3030 # we don't merge the first commit when continuing
3029 if not cont:
3031 if not cont:
3030 # perform the graft merge with p1(rev) as 'ancestor'
3032 # perform the graft merge with p1(rev) as 'ancestor'
3031 try:
3033 try:
3032 # ui.forcemerge is an internal variable, do not document
3034 # ui.forcemerge is an internal variable, do not document
3033 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3035 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3034 stats = mergemod.update(repo, ctx.node(), True, True, False,
3036 stats = mergemod.update(repo, ctx.node(), True, True, False,
3035 ctx.p1().node())
3037 ctx.p1().node())
3036 finally:
3038 finally:
3037 repo.ui.setconfig('ui', 'forcemerge', '')
3039 repo.ui.setconfig('ui', 'forcemerge', '')
3038 # report any conflicts
3040 # report any conflicts
3039 if stats and stats[3] > 0:
3041 if stats and stats[3] > 0:
3040 # write out state for --continue
3042 # write out state for --continue
3041 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3043 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3042 repo.opener.write('graftstate', ''.join(nodelines))
3044 repo.opener.write('graftstate', ''.join(nodelines))
3043 raise util.Abort(
3045 raise util.Abort(
3044 _("unresolved conflicts, can't continue"),
3046 _("unresolved conflicts, can't continue"),
3045 hint=_('use hg resolve and hg graft --continue'))
3047 hint=_('use hg resolve and hg graft --continue'))
3046 else:
3048 else:
3047 cont = False
3049 cont = False
3048
3050
3049 # drop the second merge parent
3051 # drop the second merge parent
3050 repo.setparents(current.node(), nullid)
3052 repo.setparents(current.node(), nullid)
3051 repo.dirstate.write()
3053 repo.dirstate.write()
3052 # fix up dirstate for copies and renames
3054 # fix up dirstate for copies and renames
3053 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3055 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3054
3056
3055 # commit
3057 # commit
3056 node = repo.commit(text=message, user=user,
3058 node = repo.commit(text=message, user=user,
3057 date=date, extra=extra, editor=editor)
3059 date=date, extra=extra, editor=editor)
3058 if node is None:
3060 if node is None:
3059 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3061 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3060 else:
3062 else:
3061 current = repo[node]
3063 current = repo[node]
3062 finally:
3064 finally:
3063 wlock.release()
3065 wlock.release()
3064
3066
3065 # remove state when we complete successfully
3067 # remove state when we complete successfully
3066 if not opts.get('dry_run'):
3068 if not opts.get('dry_run'):
3067 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3069 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3068
3070
3069 return 0
3071 return 0
3070
3072
3071 @command('grep',
3073 @command('grep',
3072 [('0', 'print0', None, _('end fields with NUL')),
3074 [('0', 'print0', None, _('end fields with NUL')),
3073 ('', 'all', None, _('print all revisions that match')),
3075 ('', 'all', None, _('print all revisions that match')),
3074 ('a', 'text', None, _('treat all files as text')),
3076 ('a', 'text', None, _('treat all files as text')),
3075 ('f', 'follow', None,
3077 ('f', 'follow', None,
3076 _('follow changeset history,'
3078 _('follow changeset history,'
3077 ' or file history across copies and renames')),
3079 ' or file history across copies and renames')),
3078 ('i', 'ignore-case', None, _('ignore case when matching')),
3080 ('i', 'ignore-case', None, _('ignore case when matching')),
3079 ('l', 'files-with-matches', None,
3081 ('l', 'files-with-matches', None,
3080 _('print only filenames and revisions that match')),
3082 _('print only filenames and revisions that match')),
3081 ('n', 'line-number', None, _('print matching line numbers')),
3083 ('n', 'line-number', None, _('print matching line numbers')),
3082 ('r', 'rev', [],
3084 ('r', 'rev', [],
3083 _('only search files changed within revision range'), _('REV')),
3085 _('only search files changed within revision range'), _('REV')),
3084 ('u', 'user', None, _('list the author (long with -v)')),
3086 ('u', 'user', None, _('list the author (long with -v)')),
3085 ('d', 'date', None, _('list the date (short with -q)')),
3087 ('d', 'date', None, _('list the date (short with -q)')),
3086 ] + walkopts,
3088 ] + walkopts,
3087 _('[OPTION]... PATTERN [FILE]...'))
3089 _('[OPTION]... PATTERN [FILE]...'))
3088 def grep(ui, repo, pattern, *pats, **opts):
3090 def grep(ui, repo, pattern, *pats, **opts):
3089 """search for a pattern in specified files and revisions
3091 """search for a pattern in specified files and revisions
3090
3092
3091 Search revisions of files for a regular expression.
3093 Search revisions of files for a regular expression.
3092
3094
3093 This command behaves differently than Unix grep. It only accepts
3095 This command behaves differently than Unix grep. It only accepts
3094 Python/Perl regexps. It searches repository history, not the
3096 Python/Perl regexps. It searches repository history, not the
3095 working directory. It always prints the revision number in which a
3097 working directory. It always prints the revision number in which a
3096 match appears.
3098 match appears.
3097
3099
3098 By default, grep only prints output for the first revision of a
3100 By default, grep only prints output for the first revision of a
3099 file in which it finds a match. To get it to print every revision
3101 file in which it finds a match. To get it to print every revision
3100 that contains a change in match status ("-" for a match that
3102 that contains a change in match status ("-" for a match that
3101 becomes a non-match, or "+" for a non-match that becomes a match),
3103 becomes a non-match, or "+" for a non-match that becomes a match),
3102 use the --all flag.
3104 use the --all flag.
3103
3105
3104 Returns 0 if a match is found, 1 otherwise.
3106 Returns 0 if a match is found, 1 otherwise.
3105 """
3107 """
3106 reflags = re.M
3108 reflags = re.M
3107 if opts.get('ignore_case'):
3109 if opts.get('ignore_case'):
3108 reflags |= re.I
3110 reflags |= re.I
3109 try:
3111 try:
3110 regexp = util.compilere(pattern, reflags)
3112 regexp = util.compilere(pattern, reflags)
3111 except re.error, inst:
3113 except re.error, inst:
3112 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3114 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3113 return 1
3115 return 1
3114 sep, eol = ':', '\n'
3116 sep, eol = ':', '\n'
3115 if opts.get('print0'):
3117 if opts.get('print0'):
3116 sep = eol = '\0'
3118 sep = eol = '\0'
3117
3119
3118 getfile = util.lrucachefunc(repo.file)
3120 getfile = util.lrucachefunc(repo.file)
3119
3121
3120 def matchlines(body):
3122 def matchlines(body):
3121 begin = 0
3123 begin = 0
3122 linenum = 0
3124 linenum = 0
3123 while begin < len(body):
3125 while begin < len(body):
3124 match = regexp.search(body, begin)
3126 match = regexp.search(body, begin)
3125 if not match:
3127 if not match:
3126 break
3128 break
3127 mstart, mend = match.span()
3129 mstart, mend = match.span()
3128 linenum += body.count('\n', begin, mstart) + 1
3130 linenum += body.count('\n', begin, mstart) + 1
3129 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3131 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3130 begin = body.find('\n', mend) + 1 or len(body) + 1
3132 begin = body.find('\n', mend) + 1 or len(body) + 1
3131 lend = begin - 1
3133 lend = begin - 1
3132 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3134 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3133
3135
3134 class linestate(object):
3136 class linestate(object):
3135 def __init__(self, line, linenum, colstart, colend):
3137 def __init__(self, line, linenum, colstart, colend):
3136 self.line = line
3138 self.line = line
3137 self.linenum = linenum
3139 self.linenum = linenum
3138 self.colstart = colstart
3140 self.colstart = colstart
3139 self.colend = colend
3141 self.colend = colend
3140
3142
3141 def __hash__(self):
3143 def __hash__(self):
3142 return hash((self.linenum, self.line))
3144 return hash((self.linenum, self.line))
3143
3145
3144 def __eq__(self, other):
3146 def __eq__(self, other):
3145 return self.line == other.line
3147 return self.line == other.line
3146
3148
3147 matches = {}
3149 matches = {}
3148 copies = {}
3150 copies = {}
3149 def grepbody(fn, rev, body):
3151 def grepbody(fn, rev, body):
3150 matches[rev].setdefault(fn, [])
3152 matches[rev].setdefault(fn, [])
3151 m = matches[rev][fn]
3153 m = matches[rev][fn]
3152 for lnum, cstart, cend, line in matchlines(body):
3154 for lnum, cstart, cend, line in matchlines(body):
3153 s = linestate(line, lnum, cstart, cend)
3155 s = linestate(line, lnum, cstart, cend)
3154 m.append(s)
3156 m.append(s)
3155
3157
3156 def difflinestates(a, b):
3158 def difflinestates(a, b):
3157 sm = difflib.SequenceMatcher(None, a, b)
3159 sm = difflib.SequenceMatcher(None, a, b)
3158 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3160 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3159 if tag == 'insert':
3161 if tag == 'insert':
3160 for i in xrange(blo, bhi):
3162 for i in xrange(blo, bhi):
3161 yield ('+', b[i])
3163 yield ('+', b[i])
3162 elif tag == 'delete':
3164 elif tag == 'delete':
3163 for i in xrange(alo, ahi):
3165 for i in xrange(alo, ahi):
3164 yield ('-', a[i])
3166 yield ('-', a[i])
3165 elif tag == 'replace':
3167 elif tag == 'replace':
3166 for i in xrange(alo, ahi):
3168 for i in xrange(alo, ahi):
3167 yield ('-', a[i])
3169 yield ('-', a[i])
3168 for i in xrange(blo, bhi):
3170 for i in xrange(blo, bhi):
3169 yield ('+', b[i])
3171 yield ('+', b[i])
3170
3172
3171 def display(fn, ctx, pstates, states):
3173 def display(fn, ctx, pstates, states):
3172 rev = ctx.rev()
3174 rev = ctx.rev()
3173 datefunc = ui.quiet and util.shortdate or util.datestr
3175 datefunc = ui.quiet and util.shortdate or util.datestr
3174 found = False
3176 found = False
3175 filerevmatches = {}
3177 filerevmatches = {}
3176 def binary():
3178 def binary():
3177 flog = getfile(fn)
3179 flog = getfile(fn)
3178 return util.binary(flog.read(ctx.filenode(fn)))
3180 return util.binary(flog.read(ctx.filenode(fn)))
3179
3181
3180 if opts.get('all'):
3182 if opts.get('all'):
3181 iter = difflinestates(pstates, states)
3183 iter = difflinestates(pstates, states)
3182 else:
3184 else:
3183 iter = [('', l) for l in states]
3185 iter = [('', l) for l in states]
3184 for change, l in iter:
3186 for change, l in iter:
3185 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3187 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3186 before, match, after = None, None, None
3188 before, match, after = None, None, None
3187
3189
3188 if opts.get('line_number'):
3190 if opts.get('line_number'):
3189 cols.append((str(l.linenum), 'grep.linenumber'))
3191 cols.append((str(l.linenum), 'grep.linenumber'))
3190 if opts.get('all'):
3192 if opts.get('all'):
3191 cols.append((change, 'grep.change'))
3193 cols.append((change, 'grep.change'))
3192 if opts.get('user'):
3194 if opts.get('user'):
3193 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3195 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3194 if opts.get('date'):
3196 if opts.get('date'):
3195 cols.append((datefunc(ctx.date()), 'grep.date'))
3197 cols.append((datefunc(ctx.date()), 'grep.date'))
3196 if opts.get('files_with_matches'):
3198 if opts.get('files_with_matches'):
3197 c = (fn, rev)
3199 c = (fn, rev)
3198 if c in filerevmatches:
3200 if c in filerevmatches:
3199 continue
3201 continue
3200 filerevmatches[c] = 1
3202 filerevmatches[c] = 1
3201 else:
3203 else:
3202 before = l.line[:l.colstart]
3204 before = l.line[:l.colstart]
3203 match = l.line[l.colstart:l.colend]
3205 match = l.line[l.colstart:l.colend]
3204 after = l.line[l.colend:]
3206 after = l.line[l.colend:]
3205 for col, label in cols[:-1]:
3207 for col, label in cols[:-1]:
3206 ui.write(col, label=label)
3208 ui.write(col, label=label)
3207 ui.write(sep, label='grep.sep')
3209 ui.write(sep, label='grep.sep')
3208 ui.write(cols[-1][0], label=cols[-1][1])
3210 ui.write(cols[-1][0], label=cols[-1][1])
3209 if before is not None:
3211 if before is not None:
3210 ui.write(sep, label='grep.sep')
3212 ui.write(sep, label='grep.sep')
3211 if not opts.get('text') and binary():
3213 if not opts.get('text') and binary():
3212 ui.write(" Binary file matches")
3214 ui.write(" Binary file matches")
3213 else:
3215 else:
3214 ui.write(before)
3216 ui.write(before)
3215 ui.write(match, label='grep.match')
3217 ui.write(match, label='grep.match')
3216 ui.write(after)
3218 ui.write(after)
3217 ui.write(eol)
3219 ui.write(eol)
3218 found = True
3220 found = True
3219 return found
3221 return found
3220
3222
3221 skip = {}
3223 skip = {}
3222 revfiles = {}
3224 revfiles = {}
3223 matchfn = scmutil.match(repo[None], pats, opts)
3225 matchfn = scmutil.match(repo[None], pats, opts)
3224 found = False
3226 found = False
3225 follow = opts.get('follow')
3227 follow = opts.get('follow')
3226
3228
3227 def prep(ctx, fns):
3229 def prep(ctx, fns):
3228 rev = ctx.rev()
3230 rev = ctx.rev()
3229 pctx = ctx.p1()
3231 pctx = ctx.p1()
3230 parent = pctx.rev()
3232 parent = pctx.rev()
3231 matches.setdefault(rev, {})
3233 matches.setdefault(rev, {})
3232 matches.setdefault(parent, {})
3234 matches.setdefault(parent, {})
3233 files = revfiles.setdefault(rev, [])
3235 files = revfiles.setdefault(rev, [])
3234 for fn in fns:
3236 for fn in fns:
3235 flog = getfile(fn)
3237 flog = getfile(fn)
3236 try:
3238 try:
3237 fnode = ctx.filenode(fn)
3239 fnode = ctx.filenode(fn)
3238 except error.LookupError:
3240 except error.LookupError:
3239 continue
3241 continue
3240
3242
3241 copied = flog.renamed(fnode)
3243 copied = flog.renamed(fnode)
3242 copy = follow and copied and copied[0]
3244 copy = follow and copied and copied[0]
3243 if copy:
3245 if copy:
3244 copies.setdefault(rev, {})[fn] = copy
3246 copies.setdefault(rev, {})[fn] = copy
3245 if fn in skip:
3247 if fn in skip:
3246 if copy:
3248 if copy:
3247 skip[copy] = True
3249 skip[copy] = True
3248 continue
3250 continue
3249 files.append(fn)
3251 files.append(fn)
3250
3252
3251 if fn not in matches[rev]:
3253 if fn not in matches[rev]:
3252 grepbody(fn, rev, flog.read(fnode))
3254 grepbody(fn, rev, flog.read(fnode))
3253
3255
3254 pfn = copy or fn
3256 pfn = copy or fn
3255 if pfn not in matches[parent]:
3257 if pfn not in matches[parent]:
3256 try:
3258 try:
3257 fnode = pctx.filenode(pfn)
3259 fnode = pctx.filenode(pfn)
3258 grepbody(pfn, parent, flog.read(fnode))
3260 grepbody(pfn, parent, flog.read(fnode))
3259 except error.LookupError:
3261 except error.LookupError:
3260 pass
3262 pass
3261
3263
3262 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3264 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3263 rev = ctx.rev()
3265 rev = ctx.rev()
3264 parent = ctx.p1().rev()
3266 parent = ctx.p1().rev()
3265 for fn in sorted(revfiles.get(rev, [])):
3267 for fn in sorted(revfiles.get(rev, [])):
3266 states = matches[rev][fn]
3268 states = matches[rev][fn]
3267 copy = copies.get(rev, {}).get(fn)
3269 copy = copies.get(rev, {}).get(fn)
3268 if fn in skip:
3270 if fn in skip:
3269 if copy:
3271 if copy:
3270 skip[copy] = True
3272 skip[copy] = True
3271 continue
3273 continue
3272 pstates = matches.get(parent, {}).get(copy or fn, [])
3274 pstates = matches.get(parent, {}).get(copy or fn, [])
3273 if pstates or states:
3275 if pstates or states:
3274 r = display(fn, ctx, pstates, states)
3276 r = display(fn, ctx, pstates, states)
3275 found = found or r
3277 found = found or r
3276 if r and not opts.get('all'):
3278 if r and not opts.get('all'):
3277 skip[fn] = True
3279 skip[fn] = True
3278 if copy:
3280 if copy:
3279 skip[copy] = True
3281 skip[copy] = True
3280 del matches[rev]
3282 del matches[rev]
3281 del revfiles[rev]
3283 del revfiles[rev]
3282
3284
3283 return not found
3285 return not found
3284
3286
3285 @command('heads',
3287 @command('heads',
3286 [('r', 'rev', '',
3288 [('r', 'rev', '',
3287 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3289 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3288 ('t', 'topo', False, _('show topological heads only')),
3290 ('t', 'topo', False, _('show topological heads only')),
3289 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3291 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3290 ('c', 'closed', False, _('show normal and closed branch heads')),
3292 ('c', 'closed', False, _('show normal and closed branch heads')),
3291 ] + templateopts,
3293 ] + templateopts,
3292 _('[-ct] [-r STARTREV] [REV]...'))
3294 _('[-ct] [-r STARTREV] [REV]...'))
3293 def heads(ui, repo, *branchrevs, **opts):
3295 def heads(ui, repo, *branchrevs, **opts):
3294 """show current repository heads or show branch heads
3296 """show current repository heads or show branch heads
3295
3297
3296 With no arguments, show all repository branch heads.
3298 With no arguments, show all repository branch heads.
3297
3299
3298 Repository "heads" are changesets with no child changesets. They are
3300 Repository "heads" are changesets with no child changesets. They are
3299 where development generally takes place and are the usual targets
3301 where development generally takes place and are the usual targets
3300 for update and merge operations. Branch heads are changesets that have
3302 for update and merge operations. Branch heads are changesets that have
3301 no child changeset on the same branch.
3303 no child changeset on the same branch.
3302
3304
3303 If one or more REVs are given, only branch heads on the branches
3305 If one or more REVs are given, only branch heads on the branches
3304 associated with the specified changesets are shown. This means
3306 associated with the specified changesets are shown. This means
3305 that you can use :hg:`heads foo` to see the heads on a branch
3307 that you can use :hg:`heads foo` to see the heads on a branch
3306 named ``foo``.
3308 named ``foo``.
3307
3309
3308 If -c/--closed is specified, also show branch heads marked closed
3310 If -c/--closed is specified, also show branch heads marked closed
3309 (see :hg:`commit --close-branch`).
3311 (see :hg:`commit --close-branch`).
3310
3312
3311 If STARTREV is specified, only those heads that are descendants of
3313 If STARTREV is specified, only those heads that are descendants of
3312 STARTREV will be displayed.
3314 STARTREV will be displayed.
3313
3315
3314 If -t/--topo is specified, named branch mechanics will be ignored and only
3316 If -t/--topo is specified, named branch mechanics will be ignored and only
3315 changesets without children will be shown.
3317 changesets without children will be shown.
3316
3318
3317 Returns 0 if matching heads are found, 1 if not.
3319 Returns 0 if matching heads are found, 1 if not.
3318 """
3320 """
3319
3321
3320 start = None
3322 start = None
3321 if 'rev' in opts:
3323 if 'rev' in opts:
3322 start = scmutil.revsingle(repo, opts['rev'], None).node()
3324 start = scmutil.revsingle(repo, opts['rev'], None).node()
3323
3325
3324 if opts.get('topo'):
3326 if opts.get('topo'):
3325 heads = [repo[h] for h in repo.heads(start)]
3327 heads = [repo[h] for h in repo.heads(start)]
3326 else:
3328 else:
3327 heads = []
3329 heads = []
3328 for branch in repo.branchmap():
3330 for branch in repo.branchmap():
3329 heads += repo.branchheads(branch, start, opts.get('closed'))
3331 heads += repo.branchheads(branch, start, opts.get('closed'))
3330 heads = [repo[h] for h in heads]
3332 heads = [repo[h] for h in heads]
3331
3333
3332 if branchrevs:
3334 if branchrevs:
3333 branches = set(repo[br].branch() for br in branchrevs)
3335 branches = set(repo[br].branch() for br in branchrevs)
3334 heads = [h for h in heads if h.branch() in branches]
3336 heads = [h for h in heads if h.branch() in branches]
3335
3337
3336 if opts.get('active') and branchrevs:
3338 if opts.get('active') and branchrevs:
3337 dagheads = repo.heads(start)
3339 dagheads = repo.heads(start)
3338 heads = [h for h in heads if h.node() in dagheads]
3340 heads = [h for h in heads if h.node() in dagheads]
3339
3341
3340 if branchrevs:
3342 if branchrevs:
3341 haveheads = set(h.branch() for h in heads)
3343 haveheads = set(h.branch() for h in heads)
3342 if branches - haveheads:
3344 if branches - haveheads:
3343 headless = ', '.join(b for b in branches - haveheads)
3345 headless = ', '.join(b for b in branches - haveheads)
3344 msg = _('no open branch heads found on branches %s')
3346 msg = _('no open branch heads found on branches %s')
3345 if opts.get('rev'):
3347 if opts.get('rev'):
3346 msg += _(' (started at %s)') % opts['rev']
3348 msg += _(' (started at %s)') % opts['rev']
3347 ui.warn((msg + '\n') % headless)
3349 ui.warn((msg + '\n') % headless)
3348
3350
3349 if not heads:
3351 if not heads:
3350 return 1
3352 return 1
3351
3353
3352 heads = sorted(heads, key=lambda x: -x.rev())
3354 heads = sorted(heads, key=lambda x: -x.rev())
3353 displayer = cmdutil.show_changeset(ui, repo, opts)
3355 displayer = cmdutil.show_changeset(ui, repo, opts)
3354 for ctx in heads:
3356 for ctx in heads:
3355 displayer.show(ctx)
3357 displayer.show(ctx)
3356 displayer.close()
3358 displayer.close()
3357
3359
3358 @command('help',
3360 @command('help',
3359 [('e', 'extension', None, _('show only help for extensions')),
3361 [('e', 'extension', None, _('show only help for extensions')),
3360 ('c', 'command', None, _('show only help for commands')),
3362 ('c', 'command', None, _('show only help for commands')),
3361 ('k', 'keyword', '', _('show topics matching keyword')),
3363 ('k', 'keyword', '', _('show topics matching keyword')),
3362 ],
3364 ],
3363 _('[-ec] [TOPIC]'))
3365 _('[-ec] [TOPIC]'))
3364 def help_(ui, name=None, **opts):
3366 def help_(ui, name=None, **opts):
3365 """show help for a given topic or a help overview
3367 """show help for a given topic or a help overview
3366
3368
3367 With no arguments, print a list of commands with short help messages.
3369 With no arguments, print a list of commands with short help messages.
3368
3370
3369 Given a topic, extension, or command name, print help for that
3371 Given a topic, extension, or command name, print help for that
3370 topic.
3372 topic.
3371
3373
3372 Returns 0 if successful.
3374 Returns 0 if successful.
3373 """
3375 """
3374
3376
3375 textwidth = min(ui.termwidth(), 80) - 2
3377 textwidth = min(ui.termwidth(), 80) - 2
3376
3378
3377 keep = ui.verbose and ['verbose'] or []
3379 keep = ui.verbose and ['verbose'] or []
3378 text = help.help_(ui, name, **opts)
3380 text = help.help_(ui, name, **opts)
3379
3381
3380 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3382 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3381 if 'verbose' in pruned:
3383 if 'verbose' in pruned:
3382 keep.append('omitted')
3384 keep.append('omitted')
3383 else:
3385 else:
3384 keep.append('notomitted')
3386 keep.append('notomitted')
3385 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3387 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3386 ui.write(formatted)
3388 ui.write(formatted)
3387
3389
3388
3390
3389 @command('identify|id',
3391 @command('identify|id',
3390 [('r', 'rev', '',
3392 [('r', 'rev', '',
3391 _('identify the specified revision'), _('REV')),
3393 _('identify the specified revision'), _('REV')),
3392 ('n', 'num', None, _('show local revision number')),
3394 ('n', 'num', None, _('show local revision number')),
3393 ('i', 'id', None, _('show global revision id')),
3395 ('i', 'id', None, _('show global revision id')),
3394 ('b', 'branch', None, _('show branch')),
3396 ('b', 'branch', None, _('show branch')),
3395 ('t', 'tags', None, _('show tags')),
3397 ('t', 'tags', None, _('show tags')),
3396 ('B', 'bookmarks', None, _('show bookmarks')),
3398 ('B', 'bookmarks', None, _('show bookmarks')),
3397 ] + remoteopts,
3399 ] + remoteopts,
3398 _('[-nibtB] [-r REV] [SOURCE]'))
3400 _('[-nibtB] [-r REV] [SOURCE]'))
3399 def identify(ui, repo, source=None, rev=None,
3401 def identify(ui, repo, source=None, rev=None,
3400 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3402 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3401 """identify the working copy or specified revision
3403 """identify the working copy or specified revision
3402
3404
3403 Print a summary identifying the repository state at REV using one or
3405 Print a summary identifying the repository state at REV using one or
3404 two parent hash identifiers, followed by a "+" if the working
3406 two parent hash identifiers, followed by a "+" if the working
3405 directory has uncommitted changes, the branch name (if not default),
3407 directory has uncommitted changes, the branch name (if not default),
3406 a list of tags, and a list of bookmarks.
3408 a list of tags, and a list of bookmarks.
3407
3409
3408 When REV is not given, print a summary of the current state of the
3410 When REV is not given, print a summary of the current state of the
3409 repository.
3411 repository.
3410
3412
3411 Specifying a path to a repository root or Mercurial bundle will
3413 Specifying a path to a repository root or Mercurial bundle will
3412 cause lookup to operate on that repository/bundle.
3414 cause lookup to operate on that repository/bundle.
3413
3415
3414 .. container:: verbose
3416 .. container:: verbose
3415
3417
3416 Examples:
3418 Examples:
3417
3419
3418 - generate a build identifier for the working directory::
3420 - generate a build identifier for the working directory::
3419
3421
3420 hg id --id > build-id.dat
3422 hg id --id > build-id.dat
3421
3423
3422 - find the revision corresponding to a tag::
3424 - find the revision corresponding to a tag::
3423
3425
3424 hg id -n -r 1.3
3426 hg id -n -r 1.3
3425
3427
3426 - check the most recent revision of a remote repository::
3428 - check the most recent revision of a remote repository::
3427
3429
3428 hg id -r tip http://selenic.com/hg/
3430 hg id -r tip http://selenic.com/hg/
3429
3431
3430 Returns 0 if successful.
3432 Returns 0 if successful.
3431 """
3433 """
3432
3434
3433 if not repo and not source:
3435 if not repo and not source:
3434 raise util.Abort(_("there is no Mercurial repository here "
3436 raise util.Abort(_("there is no Mercurial repository here "
3435 "(.hg not found)"))
3437 "(.hg not found)"))
3436
3438
3437 hexfunc = ui.debugflag and hex or short
3439 hexfunc = ui.debugflag and hex or short
3438 default = not (num or id or branch or tags or bookmarks)
3440 default = not (num or id or branch or tags or bookmarks)
3439 output = []
3441 output = []
3440 revs = []
3442 revs = []
3441
3443
3442 if source:
3444 if source:
3443 source, branches = hg.parseurl(ui.expandpath(source))
3445 source, branches = hg.parseurl(ui.expandpath(source))
3444 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3446 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3445 repo = peer.local()
3447 repo = peer.local()
3446 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3448 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3447
3449
3448 if not repo:
3450 if not repo:
3449 if num or branch or tags:
3451 if num or branch or tags:
3450 raise util.Abort(
3452 raise util.Abort(
3451 _("can't query remote revision number, branch, or tags"))
3453 _("can't query remote revision number, branch, or tags"))
3452 if not rev and revs:
3454 if not rev and revs:
3453 rev = revs[0]
3455 rev = revs[0]
3454 if not rev:
3456 if not rev:
3455 rev = "tip"
3457 rev = "tip"
3456
3458
3457 remoterev = peer.lookup(rev)
3459 remoterev = peer.lookup(rev)
3458 if default or id:
3460 if default or id:
3459 output = [hexfunc(remoterev)]
3461 output = [hexfunc(remoterev)]
3460
3462
3461 def getbms():
3463 def getbms():
3462 bms = []
3464 bms = []
3463
3465
3464 if 'bookmarks' in peer.listkeys('namespaces'):
3466 if 'bookmarks' in peer.listkeys('namespaces'):
3465 hexremoterev = hex(remoterev)
3467 hexremoterev = hex(remoterev)
3466 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3468 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3467 if bmr == hexremoterev]
3469 if bmr == hexremoterev]
3468
3470
3469 return sorted(bms)
3471 return sorted(bms)
3470
3472
3471 if bookmarks:
3473 if bookmarks:
3472 output.extend(getbms())
3474 output.extend(getbms())
3473 elif default and not ui.quiet:
3475 elif default and not ui.quiet:
3474 # multiple bookmarks for a single parent separated by '/'
3476 # multiple bookmarks for a single parent separated by '/'
3475 bm = '/'.join(getbms())
3477 bm = '/'.join(getbms())
3476 if bm:
3478 if bm:
3477 output.append(bm)
3479 output.append(bm)
3478 else:
3480 else:
3479 if not rev:
3481 if not rev:
3480 ctx = repo[None]
3482 ctx = repo[None]
3481 parents = ctx.parents()
3483 parents = ctx.parents()
3482 changed = ""
3484 changed = ""
3483 if default or id or num:
3485 if default or id or num:
3484 if (util.any(repo.status())
3486 if (util.any(repo.status())
3485 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3487 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3486 changed = '+'
3488 changed = '+'
3487 if default or id:
3489 if default or id:
3488 output = ["%s%s" %
3490 output = ["%s%s" %
3489 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3491 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3490 if num:
3492 if num:
3491 output.append("%s%s" %
3493 output.append("%s%s" %
3492 ('+'.join([str(p.rev()) for p in parents]), changed))
3494 ('+'.join([str(p.rev()) for p in parents]), changed))
3493 else:
3495 else:
3494 ctx = scmutil.revsingle(repo, rev)
3496 ctx = scmutil.revsingle(repo, rev)
3495 if default or id:
3497 if default or id:
3496 output = [hexfunc(ctx.node())]
3498 output = [hexfunc(ctx.node())]
3497 if num:
3499 if num:
3498 output.append(str(ctx.rev()))
3500 output.append(str(ctx.rev()))
3499
3501
3500 if default and not ui.quiet:
3502 if default and not ui.quiet:
3501 b = ctx.branch()
3503 b = ctx.branch()
3502 if b != 'default':
3504 if b != 'default':
3503 output.append("(%s)" % b)
3505 output.append("(%s)" % b)
3504
3506
3505 # multiple tags for a single parent separated by '/'
3507 # multiple tags for a single parent separated by '/'
3506 t = '/'.join(ctx.tags())
3508 t = '/'.join(ctx.tags())
3507 if t:
3509 if t:
3508 output.append(t)
3510 output.append(t)
3509
3511
3510 # multiple bookmarks for a single parent separated by '/'
3512 # multiple bookmarks for a single parent separated by '/'
3511 bm = '/'.join(ctx.bookmarks())
3513 bm = '/'.join(ctx.bookmarks())
3512 if bm:
3514 if bm:
3513 output.append(bm)
3515 output.append(bm)
3514 else:
3516 else:
3515 if branch:
3517 if branch:
3516 output.append(ctx.branch())
3518 output.append(ctx.branch())
3517
3519
3518 if tags:
3520 if tags:
3519 output.extend(ctx.tags())
3521 output.extend(ctx.tags())
3520
3522
3521 if bookmarks:
3523 if bookmarks:
3522 output.extend(ctx.bookmarks())
3524 output.extend(ctx.bookmarks())
3523
3525
3524 ui.write("%s\n" % ' '.join(output))
3526 ui.write("%s\n" % ' '.join(output))
3525
3527
3526 @command('import|patch',
3528 @command('import|patch',
3527 [('p', 'strip', 1,
3529 [('p', 'strip', 1,
3528 _('directory strip option for patch. This has the same '
3530 _('directory strip option for patch. This has the same '
3529 'meaning as the corresponding patch option'), _('NUM')),
3531 'meaning as the corresponding patch option'), _('NUM')),
3530 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3532 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3531 ('e', 'edit', False, _('invoke editor on commit messages')),
3533 ('e', 'edit', False, _('invoke editor on commit messages')),
3532 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3534 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3533 ('', 'no-commit', None,
3535 ('', 'no-commit', None,
3534 _("don't commit, just update the working directory")),
3536 _("don't commit, just update the working directory")),
3535 ('', 'bypass', None,
3537 ('', 'bypass', None,
3536 _("apply patch without touching the working directory")),
3538 _("apply patch without touching the working directory")),
3537 ('', 'exact', None,
3539 ('', 'exact', None,
3538 _('apply patch to the nodes from which it was generated')),
3540 _('apply patch to the nodes from which it was generated')),
3539 ('', 'import-branch', None,
3541 ('', 'import-branch', None,
3540 _('use any branch information in patch (implied by --exact)'))] +
3542 _('use any branch information in patch (implied by --exact)'))] +
3541 commitopts + commitopts2 + similarityopts,
3543 commitopts + commitopts2 + similarityopts,
3542 _('[OPTION]... PATCH...'))
3544 _('[OPTION]... PATCH...'))
3543 def import_(ui, repo, patch1=None, *patches, **opts):
3545 def import_(ui, repo, patch1=None, *patches, **opts):
3544 """import an ordered set of patches
3546 """import an ordered set of patches
3545
3547
3546 Import a list of patches and commit them individually (unless
3548 Import a list of patches and commit them individually (unless
3547 --no-commit is specified).
3549 --no-commit is specified).
3548
3550
3549 If there are outstanding changes in the working directory, import
3551 If there are outstanding changes in the working directory, import
3550 will abort unless given the -f/--force flag.
3552 will abort unless given the -f/--force flag.
3551
3553
3552 You can import a patch straight from a mail message. Even patches
3554 You can import a patch straight from a mail message. Even patches
3553 as attachments work (to use the body part, it must have type
3555 as attachments work (to use the body part, it must have type
3554 text/plain or text/x-patch). From and Subject headers of email
3556 text/plain or text/x-patch). From and Subject headers of email
3555 message are used as default committer and commit message. All
3557 message are used as default committer and commit message. All
3556 text/plain body parts before first diff are added to commit
3558 text/plain body parts before first diff are added to commit
3557 message.
3559 message.
3558
3560
3559 If the imported patch was generated by :hg:`export`, user and
3561 If the imported patch was generated by :hg:`export`, user and
3560 description from patch override values from message headers and
3562 description from patch override values from message headers and
3561 body. Values given on command line with -m/--message and -u/--user
3563 body. Values given on command line with -m/--message and -u/--user
3562 override these.
3564 override these.
3563
3565
3564 If --exact is specified, import will set the working directory to
3566 If --exact is specified, import will set the working directory to
3565 the parent of each patch before applying it, and will abort if the
3567 the parent of each patch before applying it, and will abort if the
3566 resulting changeset has a different ID than the one recorded in
3568 resulting changeset has a different ID than the one recorded in
3567 the patch. This may happen due to character set problems or other
3569 the patch. This may happen due to character set problems or other
3568 deficiencies in the text patch format.
3570 deficiencies in the text patch format.
3569
3571
3570 Use --bypass to apply and commit patches directly to the
3572 Use --bypass to apply and commit patches directly to the
3571 repository, not touching the working directory. Without --exact,
3573 repository, not touching the working directory. Without --exact,
3572 patches will be applied on top of the working directory parent
3574 patches will be applied on top of the working directory parent
3573 revision.
3575 revision.
3574
3576
3575 With -s/--similarity, hg will attempt to discover renames and
3577 With -s/--similarity, hg will attempt to discover renames and
3576 copies in the patch in the same way as :hg:`addremove`.
3578 copies in the patch in the same way as :hg:`addremove`.
3577
3579
3578 To read a patch from standard input, use "-" as the patch name. If
3580 To read a patch from standard input, use "-" as the patch name. If
3579 a URL is specified, the patch will be downloaded from it.
3581 a URL is specified, the patch will be downloaded from it.
3580 See :hg:`help dates` for a list of formats valid for -d/--date.
3582 See :hg:`help dates` for a list of formats valid for -d/--date.
3581
3583
3582 .. container:: verbose
3584 .. container:: verbose
3583
3585
3584 Examples:
3586 Examples:
3585
3587
3586 - import a traditional patch from a website and detect renames::
3588 - import a traditional patch from a website and detect renames::
3587
3589
3588 hg import -s 80 http://example.com/bugfix.patch
3590 hg import -s 80 http://example.com/bugfix.patch
3589
3591
3590 - import a changeset from an hgweb server::
3592 - import a changeset from an hgweb server::
3591
3593
3592 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3594 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3593
3595
3594 - import all the patches in an Unix-style mbox::
3596 - import all the patches in an Unix-style mbox::
3595
3597
3596 hg import incoming-patches.mbox
3598 hg import incoming-patches.mbox
3597
3599
3598 - attempt to exactly restore an exported changeset (not always
3600 - attempt to exactly restore an exported changeset (not always
3599 possible)::
3601 possible)::
3600
3602
3601 hg import --exact proposed-fix.patch
3603 hg import --exact proposed-fix.patch
3602
3604
3603 Returns 0 on success.
3605 Returns 0 on success.
3604 """
3606 """
3605
3607
3606 if not patch1:
3608 if not patch1:
3607 raise util.Abort(_('need at least one patch to import'))
3609 raise util.Abort(_('need at least one patch to import'))
3608
3610
3609 patches = (patch1,) + patches
3611 patches = (patch1,) + patches
3610
3612
3611 date = opts.get('date')
3613 date = opts.get('date')
3612 if date:
3614 if date:
3613 opts['date'] = util.parsedate(date)
3615 opts['date'] = util.parsedate(date)
3614
3616
3615 editor = cmdutil.commiteditor
3617 editor = cmdutil.commiteditor
3616 if opts.get('edit'):
3618 if opts.get('edit'):
3617 editor = cmdutil.commitforceeditor
3619 editor = cmdutil.commitforceeditor
3618
3620
3619 update = not opts.get('bypass')
3621 update = not opts.get('bypass')
3620 if not update and opts.get('no_commit'):
3622 if not update and opts.get('no_commit'):
3621 raise util.Abort(_('cannot use --no-commit with --bypass'))
3623 raise util.Abort(_('cannot use --no-commit with --bypass'))
3622 try:
3624 try:
3623 sim = float(opts.get('similarity') or 0)
3625 sim = float(opts.get('similarity') or 0)
3624 except ValueError:
3626 except ValueError:
3625 raise util.Abort(_('similarity must be a number'))
3627 raise util.Abort(_('similarity must be a number'))
3626 if sim < 0 or sim > 100:
3628 if sim < 0 or sim > 100:
3627 raise util.Abort(_('similarity must be between 0 and 100'))
3629 raise util.Abort(_('similarity must be between 0 and 100'))
3628 if sim and not update:
3630 if sim and not update:
3629 raise util.Abort(_('cannot use --similarity with --bypass'))
3631 raise util.Abort(_('cannot use --similarity with --bypass'))
3630
3632
3631 if (opts.get('exact') or not opts.get('force')) and update:
3633 if (opts.get('exact') or not opts.get('force')) and update:
3632 cmdutil.bailifchanged(repo)
3634 cmdutil.bailifchanged(repo)
3633
3635
3634 base = opts["base"]
3636 base = opts["base"]
3635 strip = opts["strip"]
3637 strip = opts["strip"]
3636 wlock = lock = tr = None
3638 wlock = lock = tr = None
3637 msgs = []
3639 msgs = []
3638
3640
3639 def tryone(ui, hunk, parents):
3641 def tryone(ui, hunk, parents):
3640 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3642 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3641 patch.extract(ui, hunk)
3643 patch.extract(ui, hunk)
3642
3644
3643 if not tmpname:
3645 if not tmpname:
3644 return (None, None)
3646 return (None, None)
3645 msg = _('applied to working directory')
3647 msg = _('applied to working directory')
3646
3648
3647 try:
3649 try:
3648 cmdline_message = cmdutil.logmessage(ui, opts)
3650 cmdline_message = cmdutil.logmessage(ui, opts)
3649 if cmdline_message:
3651 if cmdline_message:
3650 # pickup the cmdline msg
3652 # pickup the cmdline msg
3651 message = cmdline_message
3653 message = cmdline_message
3652 elif message:
3654 elif message:
3653 # pickup the patch msg
3655 # pickup the patch msg
3654 message = message.strip()
3656 message = message.strip()
3655 else:
3657 else:
3656 # launch the editor
3658 # launch the editor
3657 message = None
3659 message = None
3658 ui.debug('message:\n%s\n' % message)
3660 ui.debug('message:\n%s\n' % message)
3659
3661
3660 if len(parents) == 1:
3662 if len(parents) == 1:
3661 parents.append(repo[nullid])
3663 parents.append(repo[nullid])
3662 if opts.get('exact'):
3664 if opts.get('exact'):
3663 if not nodeid or not p1:
3665 if not nodeid or not p1:
3664 raise util.Abort(_('not a Mercurial patch'))
3666 raise util.Abort(_('not a Mercurial patch'))
3665 p1 = repo[p1]
3667 p1 = repo[p1]
3666 p2 = repo[p2 or nullid]
3668 p2 = repo[p2 or nullid]
3667 elif p2:
3669 elif p2:
3668 try:
3670 try:
3669 p1 = repo[p1]
3671 p1 = repo[p1]
3670 p2 = repo[p2]
3672 p2 = repo[p2]
3671 # Without any options, consider p2 only if the
3673 # Without any options, consider p2 only if the
3672 # patch is being applied on top of the recorded
3674 # patch is being applied on top of the recorded
3673 # first parent.
3675 # first parent.
3674 if p1 != parents[0]:
3676 if p1 != parents[0]:
3675 p1 = parents[0]
3677 p1 = parents[0]
3676 p2 = repo[nullid]
3678 p2 = repo[nullid]
3677 except error.RepoError:
3679 except error.RepoError:
3678 p1, p2 = parents
3680 p1, p2 = parents
3679 else:
3681 else:
3680 p1, p2 = parents
3682 p1, p2 = parents
3681
3683
3682 n = None
3684 n = None
3683 if update:
3685 if update:
3684 if p1 != parents[0]:
3686 if p1 != parents[0]:
3685 hg.clean(repo, p1.node())
3687 hg.clean(repo, p1.node())
3686 if p2 != parents[1]:
3688 if p2 != parents[1]:
3687 repo.setparents(p1.node(), p2.node())
3689 repo.setparents(p1.node(), p2.node())
3688
3690
3689 if opts.get('exact') or opts.get('import_branch'):
3691 if opts.get('exact') or opts.get('import_branch'):
3690 repo.dirstate.setbranch(branch or 'default')
3692 repo.dirstate.setbranch(branch or 'default')
3691
3693
3692 files = set()
3694 files = set()
3693 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3695 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3694 eolmode=None, similarity=sim / 100.0)
3696 eolmode=None, similarity=sim / 100.0)
3695 files = list(files)
3697 files = list(files)
3696 if opts.get('no_commit'):
3698 if opts.get('no_commit'):
3697 if message:
3699 if message:
3698 msgs.append(message)
3700 msgs.append(message)
3699 else:
3701 else:
3700 if opts.get('exact') or p2:
3702 if opts.get('exact') or p2:
3701 # If you got here, you either use --force and know what
3703 # If you got here, you either use --force and know what
3702 # you are doing or used --exact or a merge patch while
3704 # you are doing or used --exact or a merge patch while
3703 # being updated to its first parent.
3705 # being updated to its first parent.
3704 m = None
3706 m = None
3705 else:
3707 else:
3706 m = scmutil.matchfiles(repo, files or [])
3708 m = scmutil.matchfiles(repo, files or [])
3707 n = repo.commit(message, opts.get('user') or user,
3709 n = repo.commit(message, opts.get('user') or user,
3708 opts.get('date') or date, match=m,
3710 opts.get('date') or date, match=m,
3709 editor=editor)
3711 editor=editor)
3710 else:
3712 else:
3711 if opts.get('exact') or opts.get('import_branch'):
3713 if opts.get('exact') or opts.get('import_branch'):
3712 branch = branch or 'default'
3714 branch = branch or 'default'
3713 else:
3715 else:
3714 branch = p1.branch()
3716 branch = p1.branch()
3715 store = patch.filestore()
3717 store = patch.filestore()
3716 try:
3718 try:
3717 files = set()
3719 files = set()
3718 try:
3720 try:
3719 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3721 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3720 files, eolmode=None)
3722 files, eolmode=None)
3721 except patch.PatchError, e:
3723 except patch.PatchError, e:
3722 raise util.Abort(str(e))
3724 raise util.Abort(str(e))
3723 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3725 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3724 message,
3726 message,
3725 opts.get('user') or user,
3727 opts.get('user') or user,
3726 opts.get('date') or date,
3728 opts.get('date') or date,
3727 branch, files, store,
3729 branch, files, store,
3728 editor=cmdutil.commiteditor)
3730 editor=cmdutil.commiteditor)
3729 repo.savecommitmessage(memctx.description())
3731 repo.savecommitmessage(memctx.description())
3730 n = memctx.commit()
3732 n = memctx.commit()
3731 finally:
3733 finally:
3732 store.close()
3734 store.close()
3733 if opts.get('exact') and hex(n) != nodeid:
3735 if opts.get('exact') and hex(n) != nodeid:
3734 raise util.Abort(_('patch is damaged or loses information'))
3736 raise util.Abort(_('patch is damaged or loses information'))
3735 if n:
3737 if n:
3736 # i18n: refers to a short changeset id
3738 # i18n: refers to a short changeset id
3737 msg = _('created %s') % short(n)
3739 msg = _('created %s') % short(n)
3738 return (msg, n)
3740 return (msg, n)
3739 finally:
3741 finally:
3740 os.unlink(tmpname)
3742 os.unlink(tmpname)
3741
3743
3742 try:
3744 try:
3743 try:
3745 try:
3744 wlock = repo.wlock()
3746 wlock = repo.wlock()
3745 if not opts.get('no_commit'):
3747 if not opts.get('no_commit'):
3746 lock = repo.lock()
3748 lock = repo.lock()
3747 tr = repo.transaction('import')
3749 tr = repo.transaction('import')
3748 parents = repo.parents()
3750 parents = repo.parents()
3749 for patchurl in patches:
3751 for patchurl in patches:
3750 if patchurl == '-':
3752 if patchurl == '-':
3751 ui.status(_('applying patch from stdin\n'))
3753 ui.status(_('applying patch from stdin\n'))
3752 patchfile = ui.fin
3754 patchfile = ui.fin
3753 patchurl = 'stdin' # for error message
3755 patchurl = 'stdin' # for error message
3754 else:
3756 else:
3755 patchurl = os.path.join(base, patchurl)
3757 patchurl = os.path.join(base, patchurl)
3756 ui.status(_('applying %s\n') % patchurl)
3758 ui.status(_('applying %s\n') % patchurl)
3757 patchfile = hg.openpath(ui, patchurl)
3759 patchfile = hg.openpath(ui, patchurl)
3758
3760
3759 haspatch = False
3761 haspatch = False
3760 for hunk in patch.split(patchfile):
3762 for hunk in patch.split(patchfile):
3761 (msg, node) = tryone(ui, hunk, parents)
3763 (msg, node) = tryone(ui, hunk, parents)
3762 if msg:
3764 if msg:
3763 haspatch = True
3765 haspatch = True
3764 ui.note(msg + '\n')
3766 ui.note(msg + '\n')
3765 if update or opts.get('exact'):
3767 if update or opts.get('exact'):
3766 parents = repo.parents()
3768 parents = repo.parents()
3767 else:
3769 else:
3768 parents = [repo[node]]
3770 parents = [repo[node]]
3769
3771
3770 if not haspatch:
3772 if not haspatch:
3771 raise util.Abort(_('%s: no diffs found') % patchurl)
3773 raise util.Abort(_('%s: no diffs found') % patchurl)
3772
3774
3773 if tr:
3775 if tr:
3774 tr.close()
3776 tr.close()
3775 if msgs:
3777 if msgs:
3776 repo.savecommitmessage('\n* * *\n'.join(msgs))
3778 repo.savecommitmessage('\n* * *\n'.join(msgs))
3777 except: # re-raises
3779 except: # re-raises
3778 # wlock.release() indirectly calls dirstate.write(): since
3780 # wlock.release() indirectly calls dirstate.write(): since
3779 # we're crashing, we do not want to change the working dir
3781 # we're crashing, we do not want to change the working dir
3780 # parent after all, so make sure it writes nothing
3782 # parent after all, so make sure it writes nothing
3781 repo.dirstate.invalidate()
3783 repo.dirstate.invalidate()
3782 raise
3784 raise
3783 finally:
3785 finally:
3784 if tr:
3786 if tr:
3785 tr.release()
3787 tr.release()
3786 release(lock, wlock)
3788 release(lock, wlock)
3787
3789
3788 @command('incoming|in',
3790 @command('incoming|in',
3789 [('f', 'force', None,
3791 [('f', 'force', None,
3790 _('run even if remote repository is unrelated')),
3792 _('run even if remote repository is unrelated')),
3791 ('n', 'newest-first', None, _('show newest record first')),
3793 ('n', 'newest-first', None, _('show newest record first')),
3792 ('', 'bundle', '',
3794 ('', 'bundle', '',
3793 _('file to store the bundles into'), _('FILE')),
3795 _('file to store the bundles into'), _('FILE')),
3794 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3796 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3795 ('B', 'bookmarks', False, _("compare bookmarks")),
3797 ('B', 'bookmarks', False, _("compare bookmarks")),
3796 ('b', 'branch', [],
3798 ('b', 'branch', [],
3797 _('a specific branch you would like to pull'), _('BRANCH')),
3799 _('a specific branch you would like to pull'), _('BRANCH')),
3798 ] + logopts + remoteopts + subrepoopts,
3800 ] + logopts + remoteopts + subrepoopts,
3799 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3801 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3800 def incoming(ui, repo, source="default", **opts):
3802 def incoming(ui, repo, source="default", **opts):
3801 """show new changesets found in source
3803 """show new changesets found in source
3802
3804
3803 Show new changesets found in the specified path/URL or the default
3805 Show new changesets found in the specified path/URL or the default
3804 pull location. These are the changesets that would have been pulled
3806 pull location. These are the changesets that would have been pulled
3805 if a pull at the time you issued this command.
3807 if a pull at the time you issued this command.
3806
3808
3807 For remote repository, using --bundle avoids downloading the
3809 For remote repository, using --bundle avoids downloading the
3808 changesets twice if the incoming is followed by a pull.
3810 changesets twice if the incoming is followed by a pull.
3809
3811
3810 See pull for valid source format details.
3812 See pull for valid source format details.
3811
3813
3812 Returns 0 if there are incoming changes, 1 otherwise.
3814 Returns 0 if there are incoming changes, 1 otherwise.
3813 """
3815 """
3814 if opts.get('graph'):
3816 if opts.get('graph'):
3815 cmdutil.checkunsupportedgraphflags([], opts)
3817 cmdutil.checkunsupportedgraphflags([], opts)
3816 def display(other, chlist, displayer):
3818 def display(other, chlist, displayer):
3817 revdag = cmdutil.graphrevs(other, chlist, opts)
3819 revdag = cmdutil.graphrevs(other, chlist, opts)
3818 showparents = [ctx.node() for ctx in repo[None].parents()]
3820 showparents = [ctx.node() for ctx in repo[None].parents()]
3819 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3821 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3820 graphmod.asciiedges)
3822 graphmod.asciiedges)
3821
3823
3822 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3824 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3823 return 0
3825 return 0
3824
3826
3825 if opts.get('bundle') and opts.get('subrepos'):
3827 if opts.get('bundle') and opts.get('subrepos'):
3826 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3828 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3827
3829
3828 if opts.get('bookmarks'):
3830 if opts.get('bookmarks'):
3829 source, branches = hg.parseurl(ui.expandpath(source),
3831 source, branches = hg.parseurl(ui.expandpath(source),
3830 opts.get('branch'))
3832 opts.get('branch'))
3831 other = hg.peer(repo, opts, source)
3833 other = hg.peer(repo, opts, source)
3832 if 'bookmarks' not in other.listkeys('namespaces'):
3834 if 'bookmarks' not in other.listkeys('namespaces'):
3833 ui.warn(_("remote doesn't support bookmarks\n"))
3835 ui.warn(_("remote doesn't support bookmarks\n"))
3834 return 0
3836 return 0
3835 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3837 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3836 return bookmarks.diff(ui, repo, other)
3838 return bookmarks.diff(ui, repo, other)
3837
3839
3838 repo._subtoppath = ui.expandpath(source)
3840 repo._subtoppath = ui.expandpath(source)
3839 try:
3841 try:
3840 return hg.incoming(ui, repo, source, opts)
3842 return hg.incoming(ui, repo, source, opts)
3841 finally:
3843 finally:
3842 del repo._subtoppath
3844 del repo._subtoppath
3843
3845
3844
3846
3845 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3847 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3846 def init(ui, dest=".", **opts):
3848 def init(ui, dest=".", **opts):
3847 """create a new repository in the given directory
3849 """create a new repository in the given directory
3848
3850
3849 Initialize a new repository in the given directory. If the given
3851 Initialize a new repository in the given directory. If the given
3850 directory does not exist, it will be created.
3852 directory does not exist, it will be created.
3851
3853
3852 If no directory is given, the current directory is used.
3854 If no directory is given, the current directory is used.
3853
3855
3854 It is possible to specify an ``ssh://`` URL as the destination.
3856 It is possible to specify an ``ssh://`` URL as the destination.
3855 See :hg:`help urls` for more information.
3857 See :hg:`help urls` for more information.
3856
3858
3857 Returns 0 on success.
3859 Returns 0 on success.
3858 """
3860 """
3859 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3861 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3860
3862
3861 @command('locate',
3863 @command('locate',
3862 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3864 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3863 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3865 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3864 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3866 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3865 ] + walkopts,
3867 ] + walkopts,
3866 _('[OPTION]... [PATTERN]...'))
3868 _('[OPTION]... [PATTERN]...'))
3867 def locate(ui, repo, *pats, **opts):
3869 def locate(ui, repo, *pats, **opts):
3868 """locate files matching specific patterns
3870 """locate files matching specific patterns
3869
3871
3870 Print files under Mercurial control in the working directory whose
3872 Print files under Mercurial control in the working directory whose
3871 names match the given patterns.
3873 names match the given patterns.
3872
3874
3873 By default, this command searches all directories in the working
3875 By default, this command searches all directories in the working
3874 directory. To search just the current directory and its
3876 directory. To search just the current directory and its
3875 subdirectories, use "--include .".
3877 subdirectories, use "--include .".
3876
3878
3877 If no patterns are given to match, this command prints the names
3879 If no patterns are given to match, this command prints the names
3878 of all files under Mercurial control in the working directory.
3880 of all files under Mercurial control in the working directory.
3879
3881
3880 If you want to feed the output of this command into the "xargs"
3882 If you want to feed the output of this command into the "xargs"
3881 command, use the -0 option to both this command and "xargs". This
3883 command, use the -0 option to both this command and "xargs". This
3882 will avoid the problem of "xargs" treating single filenames that
3884 will avoid the problem of "xargs" treating single filenames that
3883 contain whitespace as multiple filenames.
3885 contain whitespace as multiple filenames.
3884
3886
3885 Returns 0 if a match is found, 1 otherwise.
3887 Returns 0 if a match is found, 1 otherwise.
3886 """
3888 """
3887 end = opts.get('print0') and '\0' or '\n'
3889 end = opts.get('print0') and '\0' or '\n'
3888 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3890 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3889
3891
3890 ret = 1
3892 ret = 1
3891 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3893 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3892 m.bad = lambda x, y: False
3894 m.bad = lambda x, y: False
3893 for abs in repo[rev].walk(m):
3895 for abs in repo[rev].walk(m):
3894 if not rev and abs not in repo.dirstate:
3896 if not rev and abs not in repo.dirstate:
3895 continue
3897 continue
3896 if opts.get('fullpath'):
3898 if opts.get('fullpath'):
3897 ui.write(repo.wjoin(abs), end)
3899 ui.write(repo.wjoin(abs), end)
3898 else:
3900 else:
3899 ui.write(((pats and m.rel(abs)) or abs), end)
3901 ui.write(((pats and m.rel(abs)) or abs), end)
3900 ret = 0
3902 ret = 0
3901
3903
3902 return ret
3904 return ret
3903
3905
3904 @command('^log|history',
3906 @command('^log|history',
3905 [('f', 'follow', None,
3907 [('f', 'follow', None,
3906 _('follow changeset history, or file history across copies and renames')),
3908 _('follow changeset history, or file history across copies and renames')),
3907 ('', 'follow-first', None,
3909 ('', 'follow-first', None,
3908 _('only follow the first parent of merge changesets (DEPRECATED)')),
3910 _('only follow the first parent of merge changesets (DEPRECATED)')),
3909 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3911 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3910 ('C', 'copies', None, _('show copied files')),
3912 ('C', 'copies', None, _('show copied files')),
3911 ('k', 'keyword', [],
3913 ('k', 'keyword', [],
3912 _('do case-insensitive search for a given text'), _('TEXT')),
3914 _('do case-insensitive search for a given text'), _('TEXT')),
3913 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3915 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3914 ('', 'removed', None, _('include revisions where files were removed')),
3916 ('', 'removed', None, _('include revisions where files were removed')),
3915 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3917 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3916 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3918 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3917 ('', 'only-branch', [],
3919 ('', 'only-branch', [],
3918 _('show only changesets within the given named branch (DEPRECATED)'),
3920 _('show only changesets within the given named branch (DEPRECATED)'),
3919 _('BRANCH')),
3921 _('BRANCH')),
3920 ('b', 'branch', [],
3922 ('b', 'branch', [],
3921 _('show changesets within the given named branch'), _('BRANCH')),
3923 _('show changesets within the given named branch'), _('BRANCH')),
3922 ('P', 'prune', [],
3924 ('P', 'prune', [],
3923 _('do not display revision or any of its ancestors'), _('REV')),
3925 _('do not display revision or any of its ancestors'), _('REV')),
3924 ] + logopts + walkopts,
3926 ] + logopts + walkopts,
3925 _('[OPTION]... [FILE]'))
3927 _('[OPTION]... [FILE]'))
3926 def log(ui, repo, *pats, **opts):
3928 def log(ui, repo, *pats, **opts):
3927 """show revision history of entire repository or files
3929 """show revision history of entire repository or files
3928
3930
3929 Print the revision history of the specified files or the entire
3931 Print the revision history of the specified files or the entire
3930 project.
3932 project.
3931
3933
3932 If no revision range is specified, the default is ``tip:0`` unless
3934 If no revision range is specified, the default is ``tip:0`` unless
3933 --follow is set, in which case the working directory parent is
3935 --follow is set, in which case the working directory parent is
3934 used as the starting revision.
3936 used as the starting revision.
3935
3937
3936 File history is shown without following rename or copy history of
3938 File history is shown without following rename or copy history of
3937 files. Use -f/--follow with a filename to follow history across
3939 files. Use -f/--follow with a filename to follow history across
3938 renames and copies. --follow without a filename will only show
3940 renames and copies. --follow without a filename will only show
3939 ancestors or descendants of the starting revision.
3941 ancestors or descendants of the starting revision.
3940
3942
3941 By default this command prints revision number and changeset id,
3943 By default this command prints revision number and changeset id,
3942 tags, non-trivial parents, user, date and time, and a summary for
3944 tags, non-trivial parents, user, date and time, and a summary for
3943 each commit. When the -v/--verbose switch is used, the list of
3945 each commit. When the -v/--verbose switch is used, the list of
3944 changed files and full commit message are shown.
3946 changed files and full commit message are shown.
3945
3947
3946 .. note::
3948 .. note::
3947 log -p/--patch may generate unexpected diff output for merge
3949 log -p/--patch may generate unexpected diff output for merge
3948 changesets, as it will only compare the merge changeset against
3950 changesets, as it will only compare the merge changeset against
3949 its first parent. Also, only files different from BOTH parents
3951 its first parent. Also, only files different from BOTH parents
3950 will appear in files:.
3952 will appear in files:.
3951
3953
3952 .. note::
3954 .. note::
3953 for performance reasons, log FILE may omit duplicate changes
3955 for performance reasons, log FILE may omit duplicate changes
3954 made on branches and will not show deletions. To see all
3956 made on branches and will not show deletions. To see all
3955 changes including duplicates and deletions, use the --removed
3957 changes including duplicates and deletions, use the --removed
3956 switch.
3958 switch.
3957
3959
3958 .. container:: verbose
3960 .. container:: verbose
3959
3961
3960 Some examples:
3962 Some examples:
3961
3963
3962 - changesets with full descriptions and file lists::
3964 - changesets with full descriptions and file lists::
3963
3965
3964 hg log -v
3966 hg log -v
3965
3967
3966 - changesets ancestral to the working directory::
3968 - changesets ancestral to the working directory::
3967
3969
3968 hg log -f
3970 hg log -f
3969
3971
3970 - last 10 commits on the current branch::
3972 - last 10 commits on the current branch::
3971
3973
3972 hg log -l 10 -b .
3974 hg log -l 10 -b .
3973
3975
3974 - changesets showing all modifications of a file, including removals::
3976 - changesets showing all modifications of a file, including removals::
3975
3977
3976 hg log --removed file.c
3978 hg log --removed file.c
3977
3979
3978 - all changesets that touch a directory, with diffs, excluding merges::
3980 - all changesets that touch a directory, with diffs, excluding merges::
3979
3981
3980 hg log -Mp lib/
3982 hg log -Mp lib/
3981
3983
3982 - all revision numbers that match a keyword::
3984 - all revision numbers that match a keyword::
3983
3985
3984 hg log -k bug --template "{rev}\\n"
3986 hg log -k bug --template "{rev}\\n"
3985
3987
3986 - check if a given changeset is included is a tagged release::
3988 - check if a given changeset is included is a tagged release::
3987
3989
3988 hg log -r "a21ccf and ancestor(1.9)"
3990 hg log -r "a21ccf and ancestor(1.9)"
3989
3991
3990 - find all changesets by some user in a date range::
3992 - find all changesets by some user in a date range::
3991
3993
3992 hg log -k alice -d "may 2008 to jul 2008"
3994 hg log -k alice -d "may 2008 to jul 2008"
3993
3995
3994 - summary of all changesets after the last tag::
3996 - summary of all changesets after the last tag::
3995
3997
3996 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3998 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3997
3999
3998 See :hg:`help dates` for a list of formats valid for -d/--date.
4000 See :hg:`help dates` for a list of formats valid for -d/--date.
3999
4001
4000 See :hg:`help revisions` and :hg:`help revsets` for more about
4002 See :hg:`help revisions` and :hg:`help revsets` for more about
4001 specifying revisions.
4003 specifying revisions.
4002
4004
4003 See :hg:`help templates` for more about pre-packaged styles and
4005 See :hg:`help templates` for more about pre-packaged styles and
4004 specifying custom templates.
4006 specifying custom templates.
4005
4007
4006 Returns 0 on success.
4008 Returns 0 on success.
4007 """
4009 """
4008 if opts.get('graph'):
4010 if opts.get('graph'):
4009 return cmdutil.graphlog(ui, repo, *pats, **opts)
4011 return cmdutil.graphlog(ui, repo, *pats, **opts)
4010
4012
4011 matchfn = scmutil.match(repo[None], pats, opts)
4013 matchfn = scmutil.match(repo[None], pats, opts)
4012 limit = cmdutil.loglimit(opts)
4014 limit = cmdutil.loglimit(opts)
4013 count = 0
4015 count = 0
4014
4016
4015 getrenamed, endrev = None, None
4017 getrenamed, endrev = None, None
4016 if opts.get('copies'):
4018 if opts.get('copies'):
4017 if opts.get('rev'):
4019 if opts.get('rev'):
4018 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4020 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4019 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4021 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4020
4022
4021 df = False
4023 df = False
4022 if opts.get("date"):
4024 if opts.get("date"):
4023 df = util.matchdate(opts["date"])
4025 df = util.matchdate(opts["date"])
4024
4026
4025 branches = opts.get('branch', []) + opts.get('only_branch', [])
4027 branches = opts.get('branch', []) + opts.get('only_branch', [])
4026 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4028 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4027
4029
4028 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4030 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4029 def prep(ctx, fns):
4031 def prep(ctx, fns):
4030 rev = ctx.rev()
4032 rev = ctx.rev()
4031 parents = [p for p in repo.changelog.parentrevs(rev)
4033 parents = [p for p in repo.changelog.parentrevs(rev)
4032 if p != nullrev]
4034 if p != nullrev]
4033 if opts.get('no_merges') and len(parents) == 2:
4035 if opts.get('no_merges') and len(parents) == 2:
4034 return
4036 return
4035 if opts.get('only_merges') and len(parents) != 2:
4037 if opts.get('only_merges') and len(parents) != 2:
4036 return
4038 return
4037 if opts.get('branch') and ctx.branch() not in opts['branch']:
4039 if opts.get('branch') and ctx.branch() not in opts['branch']:
4038 return
4040 return
4039 if df and not df(ctx.date()[0]):
4041 if df and not df(ctx.date()[0]):
4040 return
4042 return
4041
4043
4042 lower = encoding.lower
4044 lower = encoding.lower
4043 if opts.get('user'):
4045 if opts.get('user'):
4044 luser = lower(ctx.user())
4046 luser = lower(ctx.user())
4045 for k in [lower(x) for x in opts['user']]:
4047 for k in [lower(x) for x in opts['user']]:
4046 if (k in luser):
4048 if (k in luser):
4047 break
4049 break
4048 else:
4050 else:
4049 return
4051 return
4050 if opts.get('keyword'):
4052 if opts.get('keyword'):
4051 luser = lower(ctx.user())
4053 luser = lower(ctx.user())
4052 ldesc = lower(ctx.description())
4054 ldesc = lower(ctx.description())
4053 lfiles = lower(" ".join(ctx.files()))
4055 lfiles = lower(" ".join(ctx.files()))
4054 for k in [lower(x) for x in opts['keyword']]:
4056 for k in [lower(x) for x in opts['keyword']]:
4055 if (k in luser or k in ldesc or k in lfiles):
4057 if (k in luser or k in ldesc or k in lfiles):
4056 break
4058 break
4057 else:
4059 else:
4058 return
4060 return
4059
4061
4060 copies = None
4062 copies = None
4061 if getrenamed is not None and rev:
4063 if getrenamed is not None and rev:
4062 copies = []
4064 copies = []
4063 for fn in ctx.files():
4065 for fn in ctx.files():
4064 rename = getrenamed(fn, rev)
4066 rename = getrenamed(fn, rev)
4065 if rename:
4067 if rename:
4066 copies.append((fn, rename[0]))
4068 copies.append((fn, rename[0]))
4067
4069
4068 revmatchfn = None
4070 revmatchfn = None
4069 if opts.get('patch') or opts.get('stat'):
4071 if opts.get('patch') or opts.get('stat'):
4070 if opts.get('follow') or opts.get('follow_first'):
4072 if opts.get('follow') or opts.get('follow_first'):
4071 # note: this might be wrong when following through merges
4073 # note: this might be wrong when following through merges
4072 revmatchfn = scmutil.match(repo[None], fns, default='path')
4074 revmatchfn = scmutil.match(repo[None], fns, default='path')
4073 else:
4075 else:
4074 revmatchfn = matchfn
4076 revmatchfn = matchfn
4075
4077
4076 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4078 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4077
4079
4078 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4080 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4079 if displayer.flush(ctx.rev()):
4081 if displayer.flush(ctx.rev()):
4080 count += 1
4082 count += 1
4081 if count == limit:
4083 if count == limit:
4082 break
4084 break
4083 displayer.close()
4085 displayer.close()
4084
4086
4085 @command('manifest',
4087 @command('manifest',
4086 [('r', 'rev', '', _('revision to display'), _('REV')),
4088 [('r', 'rev', '', _('revision to display'), _('REV')),
4087 ('', 'all', False, _("list files from all revisions"))],
4089 ('', 'all', False, _("list files from all revisions"))],
4088 _('[-r REV]'))
4090 _('[-r REV]'))
4089 def manifest(ui, repo, node=None, rev=None, **opts):
4091 def manifest(ui, repo, node=None, rev=None, **opts):
4090 """output the current or given revision of the project manifest
4092 """output the current or given revision of the project manifest
4091
4093
4092 Print a list of version controlled files for the given revision.
4094 Print a list of version controlled files for the given revision.
4093 If no revision is given, the first parent of the working directory
4095 If no revision is given, the first parent of the working directory
4094 is used, or the null revision if no revision is checked out.
4096 is used, or the null revision if no revision is checked out.
4095
4097
4096 With -v, print file permissions, symlink and executable bits.
4098 With -v, print file permissions, symlink and executable bits.
4097 With --debug, print file revision hashes.
4099 With --debug, print file revision hashes.
4098
4100
4099 If option --all is specified, the list of all files from all revisions
4101 If option --all is specified, the list of all files from all revisions
4100 is printed. This includes deleted and renamed files.
4102 is printed. This includes deleted and renamed files.
4101
4103
4102 Returns 0 on success.
4104 Returns 0 on success.
4103 """
4105 """
4104
4106
4105 fm = ui.formatter('manifest', opts)
4107 fm = ui.formatter('manifest', opts)
4106
4108
4107 if opts.get('all'):
4109 if opts.get('all'):
4108 if rev or node:
4110 if rev or node:
4109 raise util.Abort(_("can't specify a revision with --all"))
4111 raise util.Abort(_("can't specify a revision with --all"))
4110
4112
4111 res = []
4113 res = []
4112 prefix = "data/"
4114 prefix = "data/"
4113 suffix = ".i"
4115 suffix = ".i"
4114 plen = len(prefix)
4116 plen = len(prefix)
4115 slen = len(suffix)
4117 slen = len(suffix)
4116 lock = repo.lock()
4118 lock = repo.lock()
4117 try:
4119 try:
4118 for fn, b, size in repo.store.datafiles():
4120 for fn, b, size in repo.store.datafiles():
4119 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4121 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4120 res.append(fn[plen:-slen])
4122 res.append(fn[plen:-slen])
4121 finally:
4123 finally:
4122 lock.release()
4124 lock.release()
4123 for f in res:
4125 for f in res:
4124 fm.startitem()
4126 fm.startitem()
4125 fm.write("path", '%s\n', f)
4127 fm.write("path", '%s\n', f)
4126 fm.end()
4128 fm.end()
4127 return
4129 return
4128
4130
4129 if rev and node:
4131 if rev and node:
4130 raise util.Abort(_("please specify just one revision"))
4132 raise util.Abort(_("please specify just one revision"))
4131
4133
4132 if not node:
4134 if not node:
4133 node = rev
4135 node = rev
4134
4136
4135 char = {'l': '@', 'x': '*', '': ''}
4137 char = {'l': '@', 'x': '*', '': ''}
4136 mode = {'l': '644', 'x': '755', '': '644'}
4138 mode = {'l': '644', 'x': '755', '': '644'}
4137 ctx = scmutil.revsingle(repo, node)
4139 ctx = scmutil.revsingle(repo, node)
4138 mf = ctx.manifest()
4140 mf = ctx.manifest()
4139 for f in ctx:
4141 for f in ctx:
4140 fm.startitem()
4142 fm.startitem()
4141 fl = ctx[f].flags()
4143 fl = ctx[f].flags()
4142 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4144 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4143 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4145 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4144 fm.write('path', '%s\n', f)
4146 fm.write('path', '%s\n', f)
4145 fm.end()
4147 fm.end()
4146
4148
4147 @command('^merge',
4149 @command('^merge',
4148 [('f', 'force', None, _('force a merge with outstanding changes')),
4150 [('f', 'force', None, _('force a merge with outstanding changes')),
4149 ('r', 'rev', '', _('revision to merge'), _('REV')),
4151 ('r', 'rev', '', _('revision to merge'), _('REV')),
4150 ('P', 'preview', None,
4152 ('P', 'preview', None,
4151 _('review revisions to merge (no merge is performed)'))
4153 _('review revisions to merge (no merge is performed)'))
4152 ] + mergetoolopts,
4154 ] + mergetoolopts,
4153 _('[-P] [-f] [[-r] REV]'))
4155 _('[-P] [-f] [[-r] REV]'))
4154 def merge(ui, repo, node=None, **opts):
4156 def merge(ui, repo, node=None, **opts):
4155 """merge working directory with another revision
4157 """merge working directory with another revision
4156
4158
4157 The current working directory is updated with all changes made in
4159 The current working directory is updated with all changes made in
4158 the requested revision since the last common predecessor revision.
4160 the requested revision since the last common predecessor revision.
4159
4161
4160 Files that changed between either parent are marked as changed for
4162 Files that changed between either parent are marked as changed for
4161 the next commit and a commit must be performed before any further
4163 the next commit and a commit must be performed before any further
4162 updates to the repository are allowed. The next commit will have
4164 updates to the repository are allowed. The next commit will have
4163 two parents.
4165 two parents.
4164
4166
4165 ``--tool`` can be used to specify the merge tool used for file
4167 ``--tool`` can be used to specify the merge tool used for file
4166 merges. It overrides the HGMERGE environment variable and your
4168 merges. It overrides the HGMERGE environment variable and your
4167 configuration files. See :hg:`help merge-tools` for options.
4169 configuration files. See :hg:`help merge-tools` for options.
4168
4170
4169 If no revision is specified, the working directory's parent is a
4171 If no revision is specified, the working directory's parent is a
4170 head revision, and the current branch contains exactly one other
4172 head revision, and the current branch contains exactly one other
4171 head, the other head is merged with by default. Otherwise, an
4173 head, the other head is merged with by default. Otherwise, an
4172 explicit revision with which to merge with must be provided.
4174 explicit revision with which to merge with must be provided.
4173
4175
4174 :hg:`resolve` must be used to resolve unresolved files.
4176 :hg:`resolve` must be used to resolve unresolved files.
4175
4177
4176 To undo an uncommitted merge, use :hg:`update --clean .` which
4178 To undo an uncommitted merge, use :hg:`update --clean .` which
4177 will check out a clean copy of the original merge parent, losing
4179 will check out a clean copy of the original merge parent, losing
4178 all changes.
4180 all changes.
4179
4181
4180 Returns 0 on success, 1 if there are unresolved files.
4182 Returns 0 on success, 1 if there are unresolved files.
4181 """
4183 """
4182
4184
4183 if opts.get('rev') and node:
4185 if opts.get('rev') and node:
4184 raise util.Abort(_("please specify just one revision"))
4186 raise util.Abort(_("please specify just one revision"))
4185 if not node:
4187 if not node:
4186 node = opts.get('rev')
4188 node = opts.get('rev')
4187
4189
4188 if node:
4190 if node:
4189 node = scmutil.revsingle(repo, node).node()
4191 node = scmutil.revsingle(repo, node).node()
4190
4192
4191 if not node and repo._bookmarkcurrent:
4193 if not node and repo._bookmarkcurrent:
4192 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4194 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4193 curhead = repo[repo._bookmarkcurrent].node()
4195 curhead = repo[repo._bookmarkcurrent].node()
4194 if len(bmheads) == 2:
4196 if len(bmheads) == 2:
4195 if curhead == bmheads[0]:
4197 if curhead == bmheads[0]:
4196 node = bmheads[1]
4198 node = bmheads[1]
4197 else:
4199 else:
4198 node = bmheads[0]
4200 node = bmheads[0]
4199 elif len(bmheads) > 2:
4201 elif len(bmheads) > 2:
4200 raise util.Abort(_("multiple matching bookmarks to merge - "
4202 raise util.Abort(_("multiple matching bookmarks to merge - "
4201 "please merge with an explicit rev or bookmark"),
4203 "please merge with an explicit rev or bookmark"),
4202 hint=_("run 'hg heads' to see all heads"))
4204 hint=_("run 'hg heads' to see all heads"))
4203 elif len(bmheads) <= 1:
4205 elif len(bmheads) <= 1:
4204 raise util.Abort(_("no matching bookmark to merge - "
4206 raise util.Abort(_("no matching bookmark to merge - "
4205 "please merge with an explicit rev or bookmark"),
4207 "please merge with an explicit rev or bookmark"),
4206 hint=_("run 'hg heads' to see all heads"))
4208 hint=_("run 'hg heads' to see all heads"))
4207
4209
4208 if not node and not repo._bookmarkcurrent:
4210 if not node and not repo._bookmarkcurrent:
4209 branch = repo[None].branch()
4211 branch = repo[None].branch()
4210 bheads = repo.branchheads(branch)
4212 bheads = repo.branchheads(branch)
4211 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4213 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4212
4214
4213 if len(nbhs) > 2:
4215 if len(nbhs) > 2:
4214 raise util.Abort(_("branch '%s' has %d heads - "
4216 raise util.Abort(_("branch '%s' has %d heads - "
4215 "please merge with an explicit rev")
4217 "please merge with an explicit rev")
4216 % (branch, len(bheads)),
4218 % (branch, len(bheads)),
4217 hint=_("run 'hg heads .' to see heads"))
4219 hint=_("run 'hg heads .' to see heads"))
4218
4220
4219 parent = repo.dirstate.p1()
4221 parent = repo.dirstate.p1()
4220 if len(nbhs) <= 1:
4222 if len(nbhs) <= 1:
4221 if len(bheads) > 1:
4223 if len(bheads) > 1:
4222 raise util.Abort(_("heads are bookmarked - "
4224 raise util.Abort(_("heads are bookmarked - "
4223 "please merge with an explicit rev"),
4225 "please merge with an explicit rev"),
4224 hint=_("run 'hg heads' to see all heads"))
4226 hint=_("run 'hg heads' to see all heads"))
4225 if len(repo.heads()) > 1:
4227 if len(repo.heads()) > 1:
4226 raise util.Abort(_("branch '%s' has one head - "
4228 raise util.Abort(_("branch '%s' has one head - "
4227 "please merge with an explicit rev")
4229 "please merge with an explicit rev")
4228 % branch,
4230 % branch,
4229 hint=_("run 'hg heads' to see all heads"))
4231 hint=_("run 'hg heads' to see all heads"))
4230 msg, hint = _('nothing to merge'), None
4232 msg, hint = _('nothing to merge'), None
4231 if parent != repo.lookup(branch):
4233 if parent != repo.lookup(branch):
4232 hint = _("use 'hg update' instead")
4234 hint = _("use 'hg update' instead")
4233 raise util.Abort(msg, hint=hint)
4235 raise util.Abort(msg, hint=hint)
4234
4236
4235 if parent not in bheads:
4237 if parent not in bheads:
4236 raise util.Abort(_('working directory not at a head revision'),
4238 raise util.Abort(_('working directory not at a head revision'),
4237 hint=_("use 'hg update' or merge with an "
4239 hint=_("use 'hg update' or merge with an "
4238 "explicit revision"))
4240 "explicit revision"))
4239 if parent == nbhs[0]:
4241 if parent == nbhs[0]:
4240 node = nbhs[-1]
4242 node = nbhs[-1]
4241 else:
4243 else:
4242 node = nbhs[0]
4244 node = nbhs[0]
4243
4245
4244 if opts.get('preview'):
4246 if opts.get('preview'):
4245 # find nodes that are ancestors of p2 but not of p1
4247 # find nodes that are ancestors of p2 but not of p1
4246 p1 = repo.lookup('.')
4248 p1 = repo.lookup('.')
4247 p2 = repo.lookup(node)
4249 p2 = repo.lookup(node)
4248 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4250 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4249
4251
4250 displayer = cmdutil.show_changeset(ui, repo, opts)
4252 displayer = cmdutil.show_changeset(ui, repo, opts)
4251 for node in nodes:
4253 for node in nodes:
4252 displayer.show(repo[node])
4254 displayer.show(repo[node])
4253 displayer.close()
4255 displayer.close()
4254 return 0
4256 return 0
4255
4257
4256 try:
4258 try:
4257 # ui.forcemerge is an internal variable, do not document
4259 # ui.forcemerge is an internal variable, do not document
4258 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4260 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4259 return hg.merge(repo, node, force=opts.get('force'))
4261 return hg.merge(repo, node, force=opts.get('force'))
4260 finally:
4262 finally:
4261 ui.setconfig('ui', 'forcemerge', '')
4263 ui.setconfig('ui', 'forcemerge', '')
4262
4264
4263 @command('outgoing|out',
4265 @command('outgoing|out',
4264 [('f', 'force', None, _('run even when the destination is unrelated')),
4266 [('f', 'force', None, _('run even when the destination is unrelated')),
4265 ('r', 'rev', [],
4267 ('r', 'rev', [],
4266 _('a changeset intended to be included in the destination'), _('REV')),
4268 _('a changeset intended to be included in the destination'), _('REV')),
4267 ('n', 'newest-first', None, _('show newest record first')),
4269 ('n', 'newest-first', None, _('show newest record first')),
4268 ('B', 'bookmarks', False, _('compare bookmarks')),
4270 ('B', 'bookmarks', False, _('compare bookmarks')),
4269 ('b', 'branch', [], _('a specific branch you would like to push'),
4271 ('b', 'branch', [], _('a specific branch you would like to push'),
4270 _('BRANCH')),
4272 _('BRANCH')),
4271 ] + logopts + remoteopts + subrepoopts,
4273 ] + logopts + remoteopts + subrepoopts,
4272 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4274 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4273 def outgoing(ui, repo, dest=None, **opts):
4275 def outgoing(ui, repo, dest=None, **opts):
4274 """show changesets not found in the destination
4276 """show changesets not found in the destination
4275
4277
4276 Show changesets not found in the specified destination repository
4278 Show changesets not found in the specified destination repository
4277 or the default push location. These are the changesets that would
4279 or the default push location. These are the changesets that would
4278 be pushed if a push was requested.
4280 be pushed if a push was requested.
4279
4281
4280 See pull for details of valid destination formats.
4282 See pull for details of valid destination formats.
4281
4283
4282 Returns 0 if there are outgoing changes, 1 otherwise.
4284 Returns 0 if there are outgoing changes, 1 otherwise.
4283 """
4285 """
4284 if opts.get('graph'):
4286 if opts.get('graph'):
4285 cmdutil.checkunsupportedgraphflags([], opts)
4287 cmdutil.checkunsupportedgraphflags([], opts)
4286 o = hg._outgoing(ui, repo, dest, opts)
4288 o = hg._outgoing(ui, repo, dest, opts)
4287 if o is None:
4289 if o is None:
4288 return
4290 return
4289
4291
4290 revdag = cmdutil.graphrevs(repo, o, opts)
4292 revdag = cmdutil.graphrevs(repo, o, opts)
4291 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4293 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4292 showparents = [ctx.node() for ctx in repo[None].parents()]
4294 showparents = [ctx.node() for ctx in repo[None].parents()]
4293 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4295 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4294 graphmod.asciiedges)
4296 graphmod.asciiedges)
4295 return 0
4297 return 0
4296
4298
4297 if opts.get('bookmarks'):
4299 if opts.get('bookmarks'):
4298 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4300 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4299 dest, branches = hg.parseurl(dest, opts.get('branch'))
4301 dest, branches = hg.parseurl(dest, opts.get('branch'))
4300 other = hg.peer(repo, opts, dest)
4302 other = hg.peer(repo, opts, dest)
4301 if 'bookmarks' not in other.listkeys('namespaces'):
4303 if 'bookmarks' not in other.listkeys('namespaces'):
4302 ui.warn(_("remote doesn't support bookmarks\n"))
4304 ui.warn(_("remote doesn't support bookmarks\n"))
4303 return 0
4305 return 0
4304 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4306 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4305 return bookmarks.diff(ui, other, repo)
4307 return bookmarks.diff(ui, other, repo)
4306
4308
4307 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4309 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4308 try:
4310 try:
4309 return hg.outgoing(ui, repo, dest, opts)
4311 return hg.outgoing(ui, repo, dest, opts)
4310 finally:
4312 finally:
4311 del repo._subtoppath
4313 del repo._subtoppath
4312
4314
4313 @command('parents',
4315 @command('parents',
4314 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4316 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4315 ] + templateopts,
4317 ] + templateopts,
4316 _('[-r REV] [FILE]'))
4318 _('[-r REV] [FILE]'))
4317 def parents(ui, repo, file_=None, **opts):
4319 def parents(ui, repo, file_=None, **opts):
4318 """show the parents of the working directory or revision
4320 """show the parents of the working directory or revision
4319
4321
4320 Print the working directory's parent revisions. If a revision is
4322 Print the working directory's parent revisions. If a revision is
4321 given via -r/--rev, the parent of that revision will be printed.
4323 given via -r/--rev, the parent of that revision will be printed.
4322 If a file argument is given, the revision in which the file was
4324 If a file argument is given, the revision in which the file was
4323 last changed (before the working directory revision or the
4325 last changed (before the working directory revision or the
4324 argument to --rev if given) is printed.
4326 argument to --rev if given) is printed.
4325
4327
4326 Returns 0 on success.
4328 Returns 0 on success.
4327 """
4329 """
4328
4330
4329 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4331 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4330
4332
4331 if file_:
4333 if file_:
4332 m = scmutil.match(ctx, (file_,), opts)
4334 m = scmutil.match(ctx, (file_,), opts)
4333 if m.anypats() or len(m.files()) != 1:
4335 if m.anypats() or len(m.files()) != 1:
4334 raise util.Abort(_('can only specify an explicit filename'))
4336 raise util.Abort(_('can only specify an explicit filename'))
4335 file_ = m.files()[0]
4337 file_ = m.files()[0]
4336 filenodes = []
4338 filenodes = []
4337 for cp in ctx.parents():
4339 for cp in ctx.parents():
4338 if not cp:
4340 if not cp:
4339 continue
4341 continue
4340 try:
4342 try:
4341 filenodes.append(cp.filenode(file_))
4343 filenodes.append(cp.filenode(file_))
4342 except error.LookupError:
4344 except error.LookupError:
4343 pass
4345 pass
4344 if not filenodes:
4346 if not filenodes:
4345 raise util.Abort(_("'%s' not found in manifest!") % file_)
4347 raise util.Abort(_("'%s' not found in manifest!") % file_)
4346 fl = repo.file(file_)
4348 fl = repo.file(file_)
4347 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4349 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4348 else:
4350 else:
4349 p = [cp.node() for cp in ctx.parents()]
4351 p = [cp.node() for cp in ctx.parents()]
4350
4352
4351 displayer = cmdutil.show_changeset(ui, repo, opts)
4353 displayer = cmdutil.show_changeset(ui, repo, opts)
4352 for n in p:
4354 for n in p:
4353 if n != nullid:
4355 if n != nullid:
4354 displayer.show(repo[n])
4356 displayer.show(repo[n])
4355 displayer.close()
4357 displayer.close()
4356
4358
4357 @command('paths', [], _('[NAME]'))
4359 @command('paths', [], _('[NAME]'))
4358 def paths(ui, repo, search=None):
4360 def paths(ui, repo, search=None):
4359 """show aliases for remote repositories
4361 """show aliases for remote repositories
4360
4362
4361 Show definition of symbolic path name NAME. If no name is given,
4363 Show definition of symbolic path name NAME. If no name is given,
4362 show definition of all available names.
4364 show definition of all available names.
4363
4365
4364 Option -q/--quiet suppresses all output when searching for NAME
4366 Option -q/--quiet suppresses all output when searching for NAME
4365 and shows only the path names when listing all definitions.
4367 and shows only the path names when listing all definitions.
4366
4368
4367 Path names are defined in the [paths] section of your
4369 Path names are defined in the [paths] section of your
4368 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4370 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4369 repository, ``.hg/hgrc`` is used, too.
4371 repository, ``.hg/hgrc`` is used, too.
4370
4372
4371 The path names ``default`` and ``default-push`` have a special
4373 The path names ``default`` and ``default-push`` have a special
4372 meaning. When performing a push or pull operation, they are used
4374 meaning. When performing a push or pull operation, they are used
4373 as fallbacks if no location is specified on the command-line.
4375 as fallbacks if no location is specified on the command-line.
4374 When ``default-push`` is set, it will be used for push and
4376 When ``default-push`` is set, it will be used for push and
4375 ``default`` will be used for pull; otherwise ``default`` is used
4377 ``default`` will be used for pull; otherwise ``default`` is used
4376 as the fallback for both. When cloning a repository, the clone
4378 as the fallback for both. When cloning a repository, the clone
4377 source is written as ``default`` in ``.hg/hgrc``. Note that
4379 source is written as ``default`` in ``.hg/hgrc``. Note that
4378 ``default`` and ``default-push`` apply to all inbound (e.g.
4380 ``default`` and ``default-push`` apply to all inbound (e.g.
4379 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4381 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4380 :hg:`bundle`) operations.
4382 :hg:`bundle`) operations.
4381
4383
4382 See :hg:`help urls` for more information.
4384 See :hg:`help urls` for more information.
4383
4385
4384 Returns 0 on success.
4386 Returns 0 on success.
4385 """
4387 """
4386 if search:
4388 if search:
4387 for name, path in ui.configitems("paths"):
4389 for name, path in ui.configitems("paths"):
4388 if name == search:
4390 if name == search:
4389 ui.status("%s\n" % util.hidepassword(path))
4391 ui.status("%s\n" % util.hidepassword(path))
4390 return
4392 return
4391 if not ui.quiet:
4393 if not ui.quiet:
4392 ui.warn(_("not found!\n"))
4394 ui.warn(_("not found!\n"))
4393 return 1
4395 return 1
4394 else:
4396 else:
4395 for name, path in ui.configitems("paths"):
4397 for name, path in ui.configitems("paths"):
4396 if ui.quiet:
4398 if ui.quiet:
4397 ui.write("%s\n" % name)
4399 ui.write("%s\n" % name)
4398 else:
4400 else:
4399 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4401 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4400
4402
4401 @command('phase',
4403 @command('phase',
4402 [('p', 'public', False, _('set changeset phase to public')),
4404 [('p', 'public', False, _('set changeset phase to public')),
4403 ('d', 'draft', False, _('set changeset phase to draft')),
4405 ('d', 'draft', False, _('set changeset phase to draft')),
4404 ('s', 'secret', False, _('set changeset phase to secret')),
4406 ('s', 'secret', False, _('set changeset phase to secret')),
4405 ('f', 'force', False, _('allow to move boundary backward')),
4407 ('f', 'force', False, _('allow to move boundary backward')),
4406 ('r', 'rev', [], _('target revision'), _('REV')),
4408 ('r', 'rev', [], _('target revision'), _('REV')),
4407 ],
4409 ],
4408 _('[-p|-d|-s] [-f] [-r] REV...'))
4410 _('[-p|-d|-s] [-f] [-r] REV...'))
4409 def phase(ui, repo, *revs, **opts):
4411 def phase(ui, repo, *revs, **opts):
4410 """set or show the current phase name
4412 """set or show the current phase name
4411
4413
4412 With no argument, show the phase name of specified revisions.
4414 With no argument, show the phase name of specified revisions.
4413
4415
4414 With one of -p/--public, -d/--draft or -s/--secret, change the
4416 With one of -p/--public, -d/--draft or -s/--secret, change the
4415 phase value of the specified revisions.
4417 phase value of the specified revisions.
4416
4418
4417 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4419 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4418 lower phase to an higher phase. Phases are ordered as follows::
4420 lower phase to an higher phase. Phases are ordered as follows::
4419
4421
4420 public < draft < secret
4422 public < draft < secret
4421
4423
4422 Return 0 on success, 1 if no phases were changed or some could not
4424 Return 0 on success, 1 if no phases were changed or some could not
4423 be changed.
4425 be changed.
4424 """
4426 """
4425 # search for a unique phase argument
4427 # search for a unique phase argument
4426 targetphase = None
4428 targetphase = None
4427 for idx, name in enumerate(phases.phasenames):
4429 for idx, name in enumerate(phases.phasenames):
4428 if opts[name]:
4430 if opts[name]:
4429 if targetphase is not None:
4431 if targetphase is not None:
4430 raise util.Abort(_('only one phase can be specified'))
4432 raise util.Abort(_('only one phase can be specified'))
4431 targetphase = idx
4433 targetphase = idx
4432
4434
4433 # look for specified revision
4435 # look for specified revision
4434 revs = list(revs)
4436 revs = list(revs)
4435 revs.extend(opts['rev'])
4437 revs.extend(opts['rev'])
4436 if not revs:
4438 if not revs:
4437 raise util.Abort(_('no revisions specified'))
4439 raise util.Abort(_('no revisions specified'))
4438
4440
4439 revs = scmutil.revrange(repo, revs)
4441 revs = scmutil.revrange(repo, revs)
4440
4442
4441 lock = None
4443 lock = None
4442 ret = 0
4444 ret = 0
4443 if targetphase is None:
4445 if targetphase is None:
4444 # display
4446 # display
4445 for r in revs:
4447 for r in revs:
4446 ctx = repo[r]
4448 ctx = repo[r]
4447 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4449 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4448 else:
4450 else:
4449 lock = repo.lock()
4451 lock = repo.lock()
4450 try:
4452 try:
4451 # set phase
4453 # set phase
4452 if not revs:
4454 if not revs:
4453 raise util.Abort(_('empty revision set'))
4455 raise util.Abort(_('empty revision set'))
4454 nodes = [repo[r].node() for r in revs]
4456 nodes = [repo[r].node() for r in revs]
4455 olddata = repo._phasecache.getphaserevs(repo)[:]
4457 olddata = repo._phasecache.getphaserevs(repo)[:]
4456 phases.advanceboundary(repo, targetphase, nodes)
4458 phases.advanceboundary(repo, targetphase, nodes)
4457 if opts['force']:
4459 if opts['force']:
4458 phases.retractboundary(repo, targetphase, nodes)
4460 phases.retractboundary(repo, targetphase, nodes)
4459 finally:
4461 finally:
4460 lock.release()
4462 lock.release()
4461 # moving revision from public to draft may hide them
4463 # moving revision from public to draft may hide them
4462 # We have to check result on an unfiltered repository
4464 # We have to check result on an unfiltered repository
4463 unfi = repo.unfiltered()
4465 unfi = repo.unfiltered()
4464 newdata = repo._phasecache.getphaserevs(unfi)
4466 newdata = repo._phasecache.getphaserevs(unfi)
4465 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4467 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4466 cl = unfi.changelog
4468 cl = unfi.changelog
4467 rejected = [n for n in nodes
4469 rejected = [n for n in nodes
4468 if newdata[cl.rev(n)] < targetphase]
4470 if newdata[cl.rev(n)] < targetphase]
4469 if rejected:
4471 if rejected:
4470 ui.warn(_('cannot move %i changesets to a more permissive '
4472 ui.warn(_('cannot move %i changesets to a more permissive '
4471 'phase, use --force\n') % len(rejected))
4473 'phase, use --force\n') % len(rejected))
4472 ret = 1
4474 ret = 1
4473 if changes:
4475 if changes:
4474 msg = _('phase changed for %i changesets\n') % changes
4476 msg = _('phase changed for %i changesets\n') % changes
4475 if ret:
4477 if ret:
4476 ui.status(msg)
4478 ui.status(msg)
4477 else:
4479 else:
4478 ui.note(msg)
4480 ui.note(msg)
4479 else:
4481 else:
4480 ui.warn(_('no phases changed\n'))
4482 ui.warn(_('no phases changed\n'))
4481 ret = 1
4483 ret = 1
4482 return ret
4484 return ret
4483
4485
4484 def postincoming(ui, repo, modheads, optupdate, checkout):
4486 def postincoming(ui, repo, modheads, optupdate, checkout):
4485 if modheads == 0:
4487 if modheads == 0:
4486 return
4488 return
4487 if optupdate:
4489 if optupdate:
4488 movemarkfrom = repo['.'].node()
4490 movemarkfrom = repo['.'].node()
4489 try:
4491 try:
4490 ret = hg.update(repo, checkout)
4492 ret = hg.update(repo, checkout)
4491 except util.Abort, inst:
4493 except util.Abort, inst:
4492 ui.warn(_("not updating: %s\n") % str(inst))
4494 ui.warn(_("not updating: %s\n") % str(inst))
4493 return 0
4495 return 0
4494 if not ret and not checkout:
4496 if not ret and not checkout:
4495 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4497 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4496 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4498 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4497 return ret
4499 return ret
4498 if modheads > 1:
4500 if modheads > 1:
4499 currentbranchheads = len(repo.branchheads())
4501 currentbranchheads = len(repo.branchheads())
4500 if currentbranchheads == modheads:
4502 if currentbranchheads == modheads:
4501 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4503 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4502 elif currentbranchheads > 1:
4504 elif currentbranchheads > 1:
4503 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4505 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4504 "merge)\n"))
4506 "merge)\n"))
4505 else:
4507 else:
4506 ui.status(_("(run 'hg heads' to see heads)\n"))
4508 ui.status(_("(run 'hg heads' to see heads)\n"))
4507 else:
4509 else:
4508 ui.status(_("(run 'hg update' to get a working copy)\n"))
4510 ui.status(_("(run 'hg update' to get a working copy)\n"))
4509
4511
4510 @command('^pull',
4512 @command('^pull',
4511 [('u', 'update', None,
4513 [('u', 'update', None,
4512 _('update to new branch head if changesets were pulled')),
4514 _('update to new branch head if changesets were pulled')),
4513 ('f', 'force', None, _('run even when remote repository is unrelated')),
4515 ('f', 'force', None, _('run even when remote repository is unrelated')),
4514 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4516 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4515 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4517 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4516 ('b', 'branch', [], _('a specific branch you would like to pull'),
4518 ('b', 'branch', [], _('a specific branch you would like to pull'),
4517 _('BRANCH')),
4519 _('BRANCH')),
4518 ] + remoteopts,
4520 ] + remoteopts,
4519 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4521 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4520 def pull(ui, repo, source="default", **opts):
4522 def pull(ui, repo, source="default", **opts):
4521 """pull changes from the specified source
4523 """pull changes from the specified source
4522
4524
4523 Pull changes from a remote repository to a local one.
4525 Pull changes from a remote repository to a local one.
4524
4526
4525 This finds all changes from the repository at the specified path
4527 This finds all changes from the repository at the specified path
4526 or URL and adds them to a local repository (the current one unless
4528 or URL and adds them to a local repository (the current one unless
4527 -R is specified). By default, this does not update the copy of the
4529 -R is specified). By default, this does not update the copy of the
4528 project in the working directory.
4530 project in the working directory.
4529
4531
4530 Use :hg:`incoming` if you want to see what would have been added
4532 Use :hg:`incoming` if you want to see what would have been added
4531 by a pull at the time you issued this command. If you then decide
4533 by a pull at the time you issued this command. If you then decide
4532 to add those changes to the repository, you should use :hg:`pull
4534 to add those changes to the repository, you should use :hg:`pull
4533 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4535 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4534
4536
4535 If SOURCE is omitted, the 'default' path will be used.
4537 If SOURCE is omitted, the 'default' path will be used.
4536 See :hg:`help urls` for more information.
4538 See :hg:`help urls` for more information.
4537
4539
4538 Returns 0 on success, 1 if an update had unresolved files.
4540 Returns 0 on success, 1 if an update had unresolved files.
4539 """
4541 """
4540 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4542 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4541 other = hg.peer(repo, opts, source)
4543 other = hg.peer(repo, opts, source)
4542 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4544 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4543 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4545 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4544
4546
4545 remotebookmarks = other.listkeys('bookmarks')
4547 remotebookmarks = other.listkeys('bookmarks')
4546
4548
4547 if opts.get('bookmark'):
4549 if opts.get('bookmark'):
4548 if not revs:
4550 if not revs:
4549 revs = []
4551 revs = []
4550 for b in opts['bookmark']:
4552 for b in opts['bookmark']:
4551 if b not in remotebookmarks:
4553 if b not in remotebookmarks:
4552 raise util.Abort(_('remote bookmark %s not found!') % b)
4554 raise util.Abort(_('remote bookmark %s not found!') % b)
4553 revs.append(remotebookmarks[b])
4555 revs.append(remotebookmarks[b])
4554
4556
4555 if revs:
4557 if revs:
4556 try:
4558 try:
4557 revs = [other.lookup(rev) for rev in revs]
4559 revs = [other.lookup(rev) for rev in revs]
4558 except error.CapabilityError:
4560 except error.CapabilityError:
4559 err = _("other repository doesn't support revision lookup, "
4561 err = _("other repository doesn't support revision lookup, "
4560 "so a rev cannot be specified.")
4562 "so a rev cannot be specified.")
4561 raise util.Abort(err)
4563 raise util.Abort(err)
4562
4564
4563 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4565 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4564 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4566 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4565 if checkout:
4567 if checkout:
4566 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4568 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4567 repo._subtoppath = source
4569 repo._subtoppath = source
4568 try:
4570 try:
4569 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4571 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4570
4572
4571 finally:
4573 finally:
4572 del repo._subtoppath
4574 del repo._subtoppath
4573
4575
4574 # update specified bookmarks
4576 # update specified bookmarks
4575 if opts.get('bookmark'):
4577 if opts.get('bookmark'):
4576 marks = repo._bookmarks
4578 marks = repo._bookmarks
4577 for b in opts['bookmark']:
4579 for b in opts['bookmark']:
4578 # explicit pull overrides local bookmark if any
4580 # explicit pull overrides local bookmark if any
4579 ui.status(_("importing bookmark %s\n") % b)
4581 ui.status(_("importing bookmark %s\n") % b)
4580 marks[b] = repo[remotebookmarks[b]].node()
4582 marks[b] = repo[remotebookmarks[b]].node()
4581 marks.write()
4583 marks.write()
4582
4584
4583 return ret
4585 return ret
4584
4586
4585 @command('^push',
4587 @command('^push',
4586 [('f', 'force', None, _('force push')),
4588 [('f', 'force', None, _('force push')),
4587 ('r', 'rev', [],
4589 ('r', 'rev', [],
4588 _('a changeset intended to be included in the destination'),
4590 _('a changeset intended to be included in the destination'),
4589 _('REV')),
4591 _('REV')),
4590 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4592 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4591 ('b', 'branch', [],
4593 ('b', 'branch', [],
4592 _('a specific branch you would like to push'), _('BRANCH')),
4594 _('a specific branch you would like to push'), _('BRANCH')),
4593 ('', 'new-branch', False, _('allow pushing a new branch')),
4595 ('', 'new-branch', False, _('allow pushing a new branch')),
4594 ] + remoteopts,
4596 ] + remoteopts,
4595 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4597 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4596 def push(ui, repo, dest=None, **opts):
4598 def push(ui, repo, dest=None, **opts):
4597 """push changes to the specified destination
4599 """push changes to the specified destination
4598
4600
4599 Push changesets from the local repository to the specified
4601 Push changesets from the local repository to the specified
4600 destination.
4602 destination.
4601
4603
4602 This operation is symmetrical to pull: it is identical to a pull
4604 This operation is symmetrical to pull: it is identical to a pull
4603 in the destination repository from the current one.
4605 in the destination repository from the current one.
4604
4606
4605 By default, push will not allow creation of new heads at the
4607 By default, push will not allow creation of new heads at the
4606 destination, since multiple heads would make it unclear which head
4608 destination, since multiple heads would make it unclear which head
4607 to use. In this situation, it is recommended to pull and merge
4609 to use. In this situation, it is recommended to pull and merge
4608 before pushing.
4610 before pushing.
4609
4611
4610 Use --new-branch if you want to allow push to create a new named
4612 Use --new-branch if you want to allow push to create a new named
4611 branch that is not present at the destination. This allows you to
4613 branch that is not present at the destination. This allows you to
4612 only create a new branch without forcing other changes.
4614 only create a new branch without forcing other changes.
4613
4615
4614 Use -f/--force to override the default behavior and push all
4616 Use -f/--force to override the default behavior and push all
4615 changesets on all branches.
4617 changesets on all branches.
4616
4618
4617 If -r/--rev is used, the specified revision and all its ancestors
4619 If -r/--rev is used, the specified revision and all its ancestors
4618 will be pushed to the remote repository.
4620 will be pushed to the remote repository.
4619
4621
4620 If -B/--bookmark is used, the specified bookmarked revision, its
4622 If -B/--bookmark is used, the specified bookmarked revision, its
4621 ancestors, and the bookmark will be pushed to the remote
4623 ancestors, and the bookmark will be pushed to the remote
4622 repository.
4624 repository.
4623
4625
4624 Please see :hg:`help urls` for important details about ``ssh://``
4626 Please see :hg:`help urls` for important details about ``ssh://``
4625 URLs. If DESTINATION is omitted, a default path will be used.
4627 URLs. If DESTINATION is omitted, a default path will be used.
4626
4628
4627 Returns 0 if push was successful, 1 if nothing to push.
4629 Returns 0 if push was successful, 1 if nothing to push.
4628 """
4630 """
4629
4631
4630 if opts.get('bookmark'):
4632 if opts.get('bookmark'):
4631 for b in opts['bookmark']:
4633 for b in opts['bookmark']:
4632 # translate -B options to -r so changesets get pushed
4634 # translate -B options to -r so changesets get pushed
4633 if b in repo._bookmarks:
4635 if b in repo._bookmarks:
4634 opts.setdefault('rev', []).append(b)
4636 opts.setdefault('rev', []).append(b)
4635 else:
4637 else:
4636 # if we try to push a deleted bookmark, translate it to null
4638 # if we try to push a deleted bookmark, translate it to null
4637 # this lets simultaneous -r, -b options continue working
4639 # this lets simultaneous -r, -b options continue working
4638 opts.setdefault('rev', []).append("null")
4640 opts.setdefault('rev', []).append("null")
4639
4641
4640 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4642 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4641 dest, branches = hg.parseurl(dest, opts.get('branch'))
4643 dest, branches = hg.parseurl(dest, opts.get('branch'))
4642 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4644 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4643 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4645 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4644 other = hg.peer(repo, opts, dest)
4646 other = hg.peer(repo, opts, dest)
4645 if revs:
4647 if revs:
4646 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4648 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4647
4649
4648 repo._subtoppath = dest
4650 repo._subtoppath = dest
4649 try:
4651 try:
4650 # push subrepos depth-first for coherent ordering
4652 # push subrepos depth-first for coherent ordering
4651 c = repo['']
4653 c = repo['']
4652 subs = c.substate # only repos that are committed
4654 subs = c.substate # only repos that are committed
4653 for s in sorted(subs):
4655 for s in sorted(subs):
4654 if c.sub(s).push(opts) == 0:
4656 if c.sub(s).push(opts) == 0:
4655 return False
4657 return False
4656 finally:
4658 finally:
4657 del repo._subtoppath
4659 del repo._subtoppath
4658 result = repo.push(other, opts.get('force'), revs=revs,
4660 result = repo.push(other, opts.get('force'), revs=revs,
4659 newbranch=opts.get('new_branch'))
4661 newbranch=opts.get('new_branch'))
4660
4662
4661 result = not result
4663 result = not result
4662
4664
4663 if opts.get('bookmark'):
4665 if opts.get('bookmark'):
4664 rb = other.listkeys('bookmarks')
4666 rb = other.listkeys('bookmarks')
4665 for b in opts['bookmark']:
4667 for b in opts['bookmark']:
4666 # explicit push overrides remote bookmark if any
4668 # explicit push overrides remote bookmark if any
4667 if b in repo._bookmarks:
4669 if b in repo._bookmarks:
4668 ui.status(_("exporting bookmark %s\n") % b)
4670 ui.status(_("exporting bookmark %s\n") % b)
4669 new = repo[b].hex()
4671 new = repo[b].hex()
4670 elif b in rb:
4672 elif b in rb:
4671 ui.status(_("deleting remote bookmark %s\n") % b)
4673 ui.status(_("deleting remote bookmark %s\n") % b)
4672 new = '' # delete
4674 new = '' # delete
4673 else:
4675 else:
4674 ui.warn(_('bookmark %s does not exist on the local '
4676 ui.warn(_('bookmark %s does not exist on the local '
4675 'or remote repository!\n') % b)
4677 'or remote repository!\n') % b)
4676 return 2
4678 return 2
4677 old = rb.get(b, '')
4679 old = rb.get(b, '')
4678 r = other.pushkey('bookmarks', b, old, new)
4680 r = other.pushkey('bookmarks', b, old, new)
4679 if not r:
4681 if not r:
4680 ui.warn(_('updating bookmark %s failed!\n') % b)
4682 ui.warn(_('updating bookmark %s failed!\n') % b)
4681 if not result:
4683 if not result:
4682 result = 2
4684 result = 2
4683
4685
4684 return result
4686 return result
4685
4687
4686 @command('recover', [])
4688 @command('recover', [])
4687 def recover(ui, repo):
4689 def recover(ui, repo):
4688 """roll back an interrupted transaction
4690 """roll back an interrupted transaction
4689
4691
4690 Recover from an interrupted commit or pull.
4692 Recover from an interrupted commit or pull.
4691
4693
4692 This command tries to fix the repository status after an
4694 This command tries to fix the repository status after an
4693 interrupted operation. It should only be necessary when Mercurial
4695 interrupted operation. It should only be necessary when Mercurial
4694 suggests it.
4696 suggests it.
4695
4697
4696 Returns 0 if successful, 1 if nothing to recover or verify fails.
4698 Returns 0 if successful, 1 if nothing to recover or verify fails.
4697 """
4699 """
4698 if repo.recover():
4700 if repo.recover():
4699 return hg.verify(repo)
4701 return hg.verify(repo)
4700 return 1
4702 return 1
4701
4703
4702 @command('^remove|rm',
4704 @command('^remove|rm',
4703 [('A', 'after', None, _('record delete for missing files')),
4705 [('A', 'after', None, _('record delete for missing files')),
4704 ('f', 'force', None,
4706 ('f', 'force', None,
4705 _('remove (and delete) file even if added or modified')),
4707 _('remove (and delete) file even if added or modified')),
4706 ] + walkopts,
4708 ] + walkopts,
4707 _('[OPTION]... FILE...'))
4709 _('[OPTION]... FILE...'))
4708 def remove(ui, repo, *pats, **opts):
4710 def remove(ui, repo, *pats, **opts):
4709 """remove the specified files on the next commit
4711 """remove the specified files on the next commit
4710
4712
4711 Schedule the indicated files for removal from the current branch.
4713 Schedule the indicated files for removal from the current branch.
4712
4714
4713 This command schedules the files to be removed at the next commit.
4715 This command schedules the files to be removed at the next commit.
4714 To undo a remove before that, see :hg:`revert`. To undo added
4716 To undo a remove before that, see :hg:`revert`. To undo added
4715 files, see :hg:`forget`.
4717 files, see :hg:`forget`.
4716
4718
4717 .. container:: verbose
4719 .. container:: verbose
4718
4720
4719 -A/--after can be used to remove only files that have already
4721 -A/--after can be used to remove only files that have already
4720 been deleted, -f/--force can be used to force deletion, and -Af
4722 been deleted, -f/--force can be used to force deletion, and -Af
4721 can be used to remove files from the next revision without
4723 can be used to remove files from the next revision without
4722 deleting them from the working directory.
4724 deleting them from the working directory.
4723
4725
4724 The following table details the behavior of remove for different
4726 The following table details the behavior of remove for different
4725 file states (columns) and option combinations (rows). The file
4727 file states (columns) and option combinations (rows). The file
4726 states are Added [A], Clean [C], Modified [M] and Missing [!]
4728 states are Added [A], Clean [C], Modified [M] and Missing [!]
4727 (as reported by :hg:`status`). The actions are Warn, Remove
4729 (as reported by :hg:`status`). The actions are Warn, Remove
4728 (from branch) and Delete (from disk):
4730 (from branch) and Delete (from disk):
4729
4731
4730 ======= == == == ==
4732 ======= == == == ==
4731 A C M !
4733 A C M !
4732 ======= == == == ==
4734 ======= == == == ==
4733 none W RD W R
4735 none W RD W R
4734 -f R RD RD R
4736 -f R RD RD R
4735 -A W W W R
4737 -A W W W R
4736 -Af R R R R
4738 -Af R R R R
4737 ======= == == == ==
4739 ======= == == == ==
4738
4740
4739 Note that remove never deletes files in Added [A] state from the
4741 Note that remove never deletes files in Added [A] state from the
4740 working directory, not even if option --force is specified.
4742 working directory, not even if option --force is specified.
4741
4743
4742 Returns 0 on success, 1 if any warnings encountered.
4744 Returns 0 on success, 1 if any warnings encountered.
4743 """
4745 """
4744
4746
4745 ret = 0
4747 ret = 0
4746 after, force = opts.get('after'), opts.get('force')
4748 after, force = opts.get('after'), opts.get('force')
4747 if not pats and not after:
4749 if not pats and not after:
4748 raise util.Abort(_('no files specified'))
4750 raise util.Abort(_('no files specified'))
4749
4751
4750 m = scmutil.match(repo[None], pats, opts)
4752 m = scmutil.match(repo[None], pats, opts)
4751 s = repo.status(match=m, clean=True)
4753 s = repo.status(match=m, clean=True)
4752 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4754 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4753
4755
4754 # warn about failure to delete explicit files/dirs
4756 # warn about failure to delete explicit files/dirs
4755 wctx = repo[None]
4757 wctx = repo[None]
4756 for f in m.files():
4758 for f in m.files():
4757 if f in repo.dirstate or f in wctx.dirs():
4759 if f in repo.dirstate or f in wctx.dirs():
4758 continue
4760 continue
4759 if os.path.exists(m.rel(f)):
4761 if os.path.exists(m.rel(f)):
4760 if os.path.isdir(m.rel(f)):
4762 if os.path.isdir(m.rel(f)):
4761 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4763 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4762 else:
4764 else:
4763 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4765 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4764 # missing files will generate a warning elsewhere
4766 # missing files will generate a warning elsewhere
4765 ret = 1
4767 ret = 1
4766
4768
4767 if force:
4769 if force:
4768 list = modified + deleted + clean + added
4770 list = modified + deleted + clean + added
4769 elif after:
4771 elif after:
4770 list = deleted
4772 list = deleted
4771 for f in modified + added + clean:
4773 for f in modified + added + clean:
4772 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4774 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4773 ret = 1
4775 ret = 1
4774 else:
4776 else:
4775 list = deleted + clean
4777 list = deleted + clean
4776 for f in modified:
4778 for f in modified:
4777 ui.warn(_('not removing %s: file is modified (use -f'
4779 ui.warn(_('not removing %s: file is modified (use -f'
4778 ' to force removal)\n') % m.rel(f))
4780 ' to force removal)\n') % m.rel(f))
4779 ret = 1
4781 ret = 1
4780 for f in added:
4782 for f in added:
4781 ui.warn(_('not removing %s: file has been marked for add'
4783 ui.warn(_('not removing %s: file has been marked for add'
4782 ' (use forget to undo)\n') % m.rel(f))
4784 ' (use forget to undo)\n') % m.rel(f))
4783 ret = 1
4785 ret = 1
4784
4786
4785 for f in sorted(list):
4787 for f in sorted(list):
4786 if ui.verbose or not m.exact(f):
4788 if ui.verbose or not m.exact(f):
4787 ui.status(_('removing %s\n') % m.rel(f))
4789 ui.status(_('removing %s\n') % m.rel(f))
4788
4790
4789 wlock = repo.wlock()
4791 wlock = repo.wlock()
4790 try:
4792 try:
4791 if not after:
4793 if not after:
4792 for f in list:
4794 for f in list:
4793 if f in added:
4795 if f in added:
4794 continue # we never unlink added files on remove
4796 continue # we never unlink added files on remove
4795 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4797 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4796 repo[None].forget(list)
4798 repo[None].forget(list)
4797 finally:
4799 finally:
4798 wlock.release()
4800 wlock.release()
4799
4801
4800 return ret
4802 return ret
4801
4803
4802 @command('rename|move|mv',
4804 @command('rename|move|mv',
4803 [('A', 'after', None, _('record a rename that has already occurred')),
4805 [('A', 'after', None, _('record a rename that has already occurred')),
4804 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4806 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4805 ] + walkopts + dryrunopts,
4807 ] + walkopts + dryrunopts,
4806 _('[OPTION]... SOURCE... DEST'))
4808 _('[OPTION]... SOURCE... DEST'))
4807 def rename(ui, repo, *pats, **opts):
4809 def rename(ui, repo, *pats, **opts):
4808 """rename files; equivalent of copy + remove
4810 """rename files; equivalent of copy + remove
4809
4811
4810 Mark dest as copies of sources; mark sources for deletion. If dest
4812 Mark dest as copies of sources; mark sources for deletion. If dest
4811 is a directory, copies are put in that directory. If dest is a
4813 is a directory, copies are put in that directory. If dest is a
4812 file, there can only be one source.
4814 file, there can only be one source.
4813
4815
4814 By default, this command copies the contents of files as they
4816 By default, this command copies the contents of files as they
4815 exist in the working directory. If invoked with -A/--after, the
4817 exist in the working directory. If invoked with -A/--after, the
4816 operation is recorded, but no copying is performed.
4818 operation is recorded, but no copying is performed.
4817
4819
4818 This command takes effect at the next commit. To undo a rename
4820 This command takes effect at the next commit. To undo a rename
4819 before that, see :hg:`revert`.
4821 before that, see :hg:`revert`.
4820
4822
4821 Returns 0 on success, 1 if errors are encountered.
4823 Returns 0 on success, 1 if errors are encountered.
4822 """
4824 """
4823 wlock = repo.wlock(False)
4825 wlock = repo.wlock(False)
4824 try:
4826 try:
4825 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4827 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4826 finally:
4828 finally:
4827 wlock.release()
4829 wlock.release()
4828
4830
4829 @command('resolve',
4831 @command('resolve',
4830 [('a', 'all', None, _('select all unresolved files')),
4832 [('a', 'all', None, _('select all unresolved files')),
4831 ('l', 'list', None, _('list state of files needing merge')),
4833 ('l', 'list', None, _('list state of files needing merge')),
4832 ('m', 'mark', None, _('mark files as resolved')),
4834 ('m', 'mark', None, _('mark files as resolved')),
4833 ('u', 'unmark', None, _('mark files as unresolved')),
4835 ('u', 'unmark', None, _('mark files as unresolved')),
4834 ('n', 'no-status', None, _('hide status prefix'))]
4836 ('n', 'no-status', None, _('hide status prefix'))]
4835 + mergetoolopts + walkopts,
4837 + mergetoolopts + walkopts,
4836 _('[OPTION]... [FILE]...'))
4838 _('[OPTION]... [FILE]...'))
4837 def resolve(ui, repo, *pats, **opts):
4839 def resolve(ui, repo, *pats, **opts):
4838 """redo merges or set/view the merge status of files
4840 """redo merges or set/view the merge status of files
4839
4841
4840 Merges with unresolved conflicts are often the result of
4842 Merges with unresolved conflicts are often the result of
4841 non-interactive merging using the ``internal:merge`` configuration
4843 non-interactive merging using the ``internal:merge`` configuration
4842 setting, or a command-line merge tool like ``diff3``. The resolve
4844 setting, or a command-line merge tool like ``diff3``. The resolve
4843 command is used to manage the files involved in a merge, after
4845 command is used to manage the files involved in a merge, after
4844 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4846 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4845 working directory must have two parents). See :hg:`help
4847 working directory must have two parents). See :hg:`help
4846 merge-tools` for information on configuring merge tools.
4848 merge-tools` for information on configuring merge tools.
4847
4849
4848 The resolve command can be used in the following ways:
4850 The resolve command can be used in the following ways:
4849
4851
4850 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4852 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4851 files, discarding any previous merge attempts. Re-merging is not
4853 files, discarding any previous merge attempts. Re-merging is not
4852 performed for files already marked as resolved. Use ``--all/-a``
4854 performed for files already marked as resolved. Use ``--all/-a``
4853 to select all unresolved files. ``--tool`` can be used to specify
4855 to select all unresolved files. ``--tool`` can be used to specify
4854 the merge tool used for the given files. It overrides the HGMERGE
4856 the merge tool used for the given files. It overrides the HGMERGE
4855 environment variable and your configuration files. Previous file
4857 environment variable and your configuration files. Previous file
4856 contents are saved with a ``.orig`` suffix.
4858 contents are saved with a ``.orig`` suffix.
4857
4859
4858 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4860 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4859 (e.g. after having manually fixed-up the files). The default is
4861 (e.g. after having manually fixed-up the files). The default is
4860 to mark all unresolved files.
4862 to mark all unresolved files.
4861
4863
4862 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4864 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4863 default is to mark all resolved files.
4865 default is to mark all resolved files.
4864
4866
4865 - :hg:`resolve -l`: list files which had or still have conflicts.
4867 - :hg:`resolve -l`: list files which had or still have conflicts.
4866 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4868 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4867
4869
4868 Note that Mercurial will not let you commit files with unresolved
4870 Note that Mercurial will not let you commit files with unresolved
4869 merge conflicts. You must use :hg:`resolve -m ...` before you can
4871 merge conflicts. You must use :hg:`resolve -m ...` before you can
4870 commit after a conflicting merge.
4872 commit after a conflicting merge.
4871
4873
4872 Returns 0 on success, 1 if any files fail a resolve attempt.
4874 Returns 0 on success, 1 if any files fail a resolve attempt.
4873 """
4875 """
4874
4876
4875 all, mark, unmark, show, nostatus = \
4877 all, mark, unmark, show, nostatus = \
4876 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4878 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4877
4879
4878 if (show and (mark or unmark)) or (mark and unmark):
4880 if (show and (mark or unmark)) or (mark and unmark):
4879 raise util.Abort(_("too many options specified"))
4881 raise util.Abort(_("too many options specified"))
4880 if pats and all:
4882 if pats and all:
4881 raise util.Abort(_("can't specify --all and patterns"))
4883 raise util.Abort(_("can't specify --all and patterns"))
4882 if not (all or pats or show or mark or unmark):
4884 if not (all or pats or show or mark or unmark):
4883 raise util.Abort(_('no files or directories specified; '
4885 raise util.Abort(_('no files or directories specified; '
4884 'use --all to remerge all files'))
4886 'use --all to remerge all files'))
4885
4887
4886 ms = mergemod.mergestate(repo)
4888 ms = mergemod.mergestate(repo)
4887 m = scmutil.match(repo[None], pats, opts)
4889 m = scmutil.match(repo[None], pats, opts)
4888 ret = 0
4890 ret = 0
4889
4891
4890 for f in ms:
4892 for f in ms:
4891 if m(f):
4893 if m(f):
4892 if show:
4894 if show:
4893 if nostatus:
4895 if nostatus:
4894 ui.write("%s\n" % f)
4896 ui.write("%s\n" % f)
4895 else:
4897 else:
4896 ui.write("%s %s\n" % (ms[f].upper(), f),
4898 ui.write("%s %s\n" % (ms[f].upper(), f),
4897 label='resolve.' +
4899 label='resolve.' +
4898 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4900 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4899 elif mark:
4901 elif mark:
4900 ms.mark(f, "r")
4902 ms.mark(f, "r")
4901 elif unmark:
4903 elif unmark:
4902 ms.mark(f, "u")
4904 ms.mark(f, "u")
4903 else:
4905 else:
4904 wctx = repo[None]
4906 wctx = repo[None]
4905 mctx = wctx.parents()[-1]
4907 mctx = wctx.parents()[-1]
4906
4908
4907 # backup pre-resolve (merge uses .orig for its own purposes)
4909 # backup pre-resolve (merge uses .orig for its own purposes)
4908 a = repo.wjoin(f)
4910 a = repo.wjoin(f)
4909 util.copyfile(a, a + ".resolve")
4911 util.copyfile(a, a + ".resolve")
4910
4912
4911 try:
4913 try:
4912 # resolve file
4914 # resolve file
4913 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4915 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4914 if ms.resolve(f, wctx, mctx):
4916 if ms.resolve(f, wctx, mctx):
4915 ret = 1
4917 ret = 1
4916 finally:
4918 finally:
4917 ui.setconfig('ui', 'forcemerge', '')
4919 ui.setconfig('ui', 'forcemerge', '')
4918 ms.commit()
4920 ms.commit()
4919
4921
4920 # replace filemerge's .orig file with our resolve file
4922 # replace filemerge's .orig file with our resolve file
4921 util.rename(a + ".resolve", a + ".orig")
4923 util.rename(a + ".resolve", a + ".orig")
4922
4924
4923 ms.commit()
4925 ms.commit()
4924 return ret
4926 return ret
4925
4927
4926 @command('revert',
4928 @command('revert',
4927 [('a', 'all', None, _('revert all changes when no arguments given')),
4929 [('a', 'all', None, _('revert all changes when no arguments given')),
4928 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4930 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4929 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4931 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4930 ('C', 'no-backup', None, _('do not save backup copies of files')),
4932 ('C', 'no-backup', None, _('do not save backup copies of files')),
4931 ] + walkopts + dryrunopts,
4933 ] + walkopts + dryrunopts,
4932 _('[OPTION]... [-r REV] [NAME]...'))
4934 _('[OPTION]... [-r REV] [NAME]...'))
4933 def revert(ui, repo, *pats, **opts):
4935 def revert(ui, repo, *pats, **opts):
4934 """restore files to their checkout state
4936 """restore files to their checkout state
4935
4937
4936 .. note::
4938 .. note::
4937 To check out earlier revisions, you should use :hg:`update REV`.
4939 To check out earlier revisions, you should use :hg:`update REV`.
4938 To cancel an uncommitted merge (and lose your changes),
4940 To cancel an uncommitted merge (and lose your changes),
4939 use :hg:`update --clean .`.
4941 use :hg:`update --clean .`.
4940
4942
4941 With no revision specified, revert the specified files or directories
4943 With no revision specified, revert the specified files or directories
4942 to the contents they had in the parent of the working directory.
4944 to the contents they had in the parent of the working directory.
4943 This restores the contents of files to an unmodified
4945 This restores the contents of files to an unmodified
4944 state and unschedules adds, removes, copies, and renames. If the
4946 state and unschedules adds, removes, copies, and renames. If the
4945 working directory has two parents, you must explicitly specify a
4947 working directory has two parents, you must explicitly specify a
4946 revision.
4948 revision.
4947
4949
4948 Using the -r/--rev or -d/--date options, revert the given files or
4950 Using the -r/--rev or -d/--date options, revert the given files or
4949 directories to their states as of a specific revision. Because
4951 directories to their states as of a specific revision. Because
4950 revert does not change the working directory parents, this will
4952 revert does not change the working directory parents, this will
4951 cause these files to appear modified. This can be helpful to "back
4953 cause these files to appear modified. This can be helpful to "back
4952 out" some or all of an earlier change. See :hg:`backout` for a
4954 out" some or all of an earlier change. See :hg:`backout` for a
4953 related method.
4955 related method.
4954
4956
4955 Modified files are saved with a .orig suffix before reverting.
4957 Modified files are saved with a .orig suffix before reverting.
4956 To disable these backups, use --no-backup.
4958 To disable these backups, use --no-backup.
4957
4959
4958 See :hg:`help dates` for a list of formats valid for -d/--date.
4960 See :hg:`help dates` for a list of formats valid for -d/--date.
4959
4961
4960 Returns 0 on success.
4962 Returns 0 on success.
4961 """
4963 """
4962
4964
4963 if opts.get("date"):
4965 if opts.get("date"):
4964 if opts.get("rev"):
4966 if opts.get("rev"):
4965 raise util.Abort(_("you can't specify a revision and a date"))
4967 raise util.Abort(_("you can't specify a revision and a date"))
4966 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4968 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4967
4969
4968 parent, p2 = repo.dirstate.parents()
4970 parent, p2 = repo.dirstate.parents()
4969 if not opts.get('rev') and p2 != nullid:
4971 if not opts.get('rev') and p2 != nullid:
4970 # revert after merge is a trap for new users (issue2915)
4972 # revert after merge is a trap for new users (issue2915)
4971 raise util.Abort(_('uncommitted merge with no revision specified'),
4973 raise util.Abort(_('uncommitted merge with no revision specified'),
4972 hint=_('use "hg update" or see "hg help revert"'))
4974 hint=_('use "hg update" or see "hg help revert"'))
4973
4975
4974 ctx = scmutil.revsingle(repo, opts.get('rev'))
4976 ctx = scmutil.revsingle(repo, opts.get('rev'))
4975
4977
4976 if not pats and not opts.get('all'):
4978 if not pats and not opts.get('all'):
4977 msg = _("no files or directories specified")
4979 msg = _("no files or directories specified")
4978 if p2 != nullid:
4980 if p2 != nullid:
4979 hint = _("uncommitted merge, use --all to discard all changes,"
4981 hint = _("uncommitted merge, use --all to discard all changes,"
4980 " or 'hg update -C .' to abort the merge")
4982 " or 'hg update -C .' to abort the merge")
4981 raise util.Abort(msg, hint=hint)
4983 raise util.Abort(msg, hint=hint)
4982 dirty = util.any(repo.status())
4984 dirty = util.any(repo.status())
4983 node = ctx.node()
4985 node = ctx.node()
4984 if node != parent:
4986 if node != parent:
4985 if dirty:
4987 if dirty:
4986 hint = _("uncommitted changes, use --all to discard all"
4988 hint = _("uncommitted changes, use --all to discard all"
4987 " changes, or 'hg update %s' to update") % ctx.rev()
4989 " changes, or 'hg update %s' to update") % ctx.rev()
4988 else:
4990 else:
4989 hint = _("use --all to revert all files,"
4991 hint = _("use --all to revert all files,"
4990 " or 'hg update %s' to update") % ctx.rev()
4992 " or 'hg update %s' to update") % ctx.rev()
4991 elif dirty:
4993 elif dirty:
4992 hint = _("uncommitted changes, use --all to discard all changes")
4994 hint = _("uncommitted changes, use --all to discard all changes")
4993 else:
4995 else:
4994 hint = _("use --all to revert all files")
4996 hint = _("use --all to revert all files")
4995 raise util.Abort(msg, hint=hint)
4997 raise util.Abort(msg, hint=hint)
4996
4998
4997 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4999 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4998
5000
4999 @command('rollback', dryrunopts +
5001 @command('rollback', dryrunopts +
5000 [('f', 'force', False, _('ignore safety measures'))])
5002 [('f', 'force', False, _('ignore safety measures'))])
5001 def rollback(ui, repo, **opts):
5003 def rollback(ui, repo, **opts):
5002 """roll back the last transaction (dangerous)
5004 """roll back the last transaction (dangerous)
5003
5005
5004 This command should be used with care. There is only one level of
5006 This command should be used with care. There is only one level of
5005 rollback, and there is no way to undo a rollback. It will also
5007 rollback, and there is no way to undo a rollback. It will also
5006 restore the dirstate at the time of the last transaction, losing
5008 restore the dirstate at the time of the last transaction, losing
5007 any dirstate changes since that time. This command does not alter
5009 any dirstate changes since that time. This command does not alter
5008 the working directory.
5010 the working directory.
5009
5011
5010 Transactions are used to encapsulate the effects of all commands
5012 Transactions are used to encapsulate the effects of all commands
5011 that create new changesets or propagate existing changesets into a
5013 that create new changesets or propagate existing changesets into a
5012 repository.
5014 repository.
5013
5015
5014 .. container:: verbose
5016 .. container:: verbose
5015
5017
5016 For example, the following commands are transactional, and their
5018 For example, the following commands are transactional, and their
5017 effects can be rolled back:
5019 effects can be rolled back:
5018
5020
5019 - commit
5021 - commit
5020 - import
5022 - import
5021 - pull
5023 - pull
5022 - push (with this repository as the destination)
5024 - push (with this repository as the destination)
5023 - unbundle
5025 - unbundle
5024
5026
5025 To avoid permanent data loss, rollback will refuse to rollback a
5027 To avoid permanent data loss, rollback will refuse to rollback a
5026 commit transaction if it isn't checked out. Use --force to
5028 commit transaction if it isn't checked out. Use --force to
5027 override this protection.
5029 override this protection.
5028
5030
5029 This command is not intended for use on public repositories. Once
5031 This command is not intended for use on public repositories. Once
5030 changes are visible for pull by other users, rolling a transaction
5032 changes are visible for pull by other users, rolling a transaction
5031 back locally is ineffective (someone else may already have pulled
5033 back locally is ineffective (someone else may already have pulled
5032 the changes). Furthermore, a race is possible with readers of the
5034 the changes). Furthermore, a race is possible with readers of the
5033 repository; for example an in-progress pull from the repository
5035 repository; for example an in-progress pull from the repository
5034 may fail if a rollback is performed.
5036 may fail if a rollback is performed.
5035
5037
5036 Returns 0 on success, 1 if no rollback data is available.
5038 Returns 0 on success, 1 if no rollback data is available.
5037 """
5039 """
5038 return repo.rollback(dryrun=opts.get('dry_run'),
5040 return repo.rollback(dryrun=opts.get('dry_run'),
5039 force=opts.get('force'))
5041 force=opts.get('force'))
5040
5042
5041 @command('root', [])
5043 @command('root', [])
5042 def root(ui, repo):
5044 def root(ui, repo):
5043 """print the root (top) of the current working directory
5045 """print the root (top) of the current working directory
5044
5046
5045 Print the root directory of the current repository.
5047 Print the root directory of the current repository.
5046
5048
5047 Returns 0 on success.
5049 Returns 0 on success.
5048 """
5050 """
5049 ui.write(repo.root + "\n")
5051 ui.write(repo.root + "\n")
5050
5052
5051 @command('^serve',
5053 @command('^serve',
5052 [('A', 'accesslog', '', _('name of access log file to write to'),
5054 [('A', 'accesslog', '', _('name of access log file to write to'),
5053 _('FILE')),
5055 _('FILE')),
5054 ('d', 'daemon', None, _('run server in background')),
5056 ('d', 'daemon', None, _('run server in background')),
5055 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5057 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5056 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5058 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5057 # use string type, then we can check if something was passed
5059 # use string type, then we can check if something was passed
5058 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5060 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5059 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5061 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5060 _('ADDR')),
5062 _('ADDR')),
5061 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5063 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5062 _('PREFIX')),
5064 _('PREFIX')),
5063 ('n', 'name', '',
5065 ('n', 'name', '',
5064 _('name to show in web pages (default: working directory)'), _('NAME')),
5066 _('name to show in web pages (default: working directory)'), _('NAME')),
5065 ('', 'web-conf', '',
5067 ('', 'web-conf', '',
5066 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5068 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5067 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5069 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5068 _('FILE')),
5070 _('FILE')),
5069 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5071 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5070 ('', 'stdio', None, _('for remote clients')),
5072 ('', 'stdio', None, _('for remote clients')),
5071 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5073 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5072 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5074 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5073 ('', 'style', '', _('template style to use'), _('STYLE')),
5075 ('', 'style', '', _('template style to use'), _('STYLE')),
5074 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5076 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5075 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5077 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5076 _('[OPTION]...'))
5078 _('[OPTION]...'))
5077 def serve(ui, repo, **opts):
5079 def serve(ui, repo, **opts):
5078 """start stand-alone webserver
5080 """start stand-alone webserver
5079
5081
5080 Start a local HTTP repository browser and pull server. You can use
5082 Start a local HTTP repository browser and pull server. You can use
5081 this for ad-hoc sharing and browsing of repositories. It is
5083 this for ad-hoc sharing and browsing of repositories. It is
5082 recommended to use a real web server to serve a repository for
5084 recommended to use a real web server to serve a repository for
5083 longer periods of time.
5085 longer periods of time.
5084
5086
5085 Please note that the server does not implement access control.
5087 Please note that the server does not implement access control.
5086 This means that, by default, anybody can read from the server and
5088 This means that, by default, anybody can read from the server and
5087 nobody can write to it by default. Set the ``web.allow_push``
5089 nobody can write to it by default. Set the ``web.allow_push``
5088 option to ``*`` to allow everybody to push to the server. You
5090 option to ``*`` to allow everybody to push to the server. You
5089 should use a real web server if you need to authenticate users.
5091 should use a real web server if you need to authenticate users.
5090
5092
5091 By default, the server logs accesses to stdout and errors to
5093 By default, the server logs accesses to stdout and errors to
5092 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5094 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5093 files.
5095 files.
5094
5096
5095 To have the server choose a free port number to listen on, specify
5097 To have the server choose a free port number to listen on, specify
5096 a port number of 0; in this case, the server will print the port
5098 a port number of 0; in this case, the server will print the port
5097 number it uses.
5099 number it uses.
5098
5100
5099 Returns 0 on success.
5101 Returns 0 on success.
5100 """
5102 """
5101
5103
5102 if opts["stdio"] and opts["cmdserver"]:
5104 if opts["stdio"] and opts["cmdserver"]:
5103 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5105 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5104
5106
5105 def checkrepo():
5107 def checkrepo():
5106 if repo is None:
5108 if repo is None:
5107 raise error.RepoError(_("there is no Mercurial repository here"
5109 raise error.RepoError(_("there is no Mercurial repository here"
5108 " (.hg not found)"))
5110 " (.hg not found)"))
5109
5111
5110 if opts["stdio"]:
5112 if opts["stdio"]:
5111 checkrepo()
5113 checkrepo()
5112 s = sshserver.sshserver(ui, repo)
5114 s = sshserver.sshserver(ui, repo)
5113 s.serve_forever()
5115 s.serve_forever()
5114
5116
5115 if opts["cmdserver"]:
5117 if opts["cmdserver"]:
5116 checkrepo()
5118 checkrepo()
5117 s = commandserver.server(ui, repo, opts["cmdserver"])
5119 s = commandserver.server(ui, repo, opts["cmdserver"])
5118 return s.serve()
5120 return s.serve()
5119
5121
5120 # this way we can check if something was given in the command-line
5122 # this way we can check if something was given in the command-line
5121 if opts.get('port'):
5123 if opts.get('port'):
5122 opts['port'] = util.getport(opts.get('port'))
5124 opts['port'] = util.getport(opts.get('port'))
5123
5125
5124 baseui = repo and repo.baseui or ui
5126 baseui = repo and repo.baseui or ui
5125 optlist = ("name templates style address port prefix ipv6"
5127 optlist = ("name templates style address port prefix ipv6"
5126 " accesslog errorlog certificate encoding")
5128 " accesslog errorlog certificate encoding")
5127 for o in optlist.split():
5129 for o in optlist.split():
5128 val = opts.get(o, '')
5130 val = opts.get(o, '')
5129 if val in (None, ''): # should check against default options instead
5131 if val in (None, ''): # should check against default options instead
5130 continue
5132 continue
5131 baseui.setconfig("web", o, val)
5133 baseui.setconfig("web", o, val)
5132 if repo and repo.ui != baseui:
5134 if repo and repo.ui != baseui:
5133 repo.ui.setconfig("web", o, val)
5135 repo.ui.setconfig("web", o, val)
5134
5136
5135 o = opts.get('web_conf') or opts.get('webdir_conf')
5137 o = opts.get('web_conf') or opts.get('webdir_conf')
5136 if not o:
5138 if not o:
5137 if not repo:
5139 if not repo:
5138 raise error.RepoError(_("there is no Mercurial repository"
5140 raise error.RepoError(_("there is no Mercurial repository"
5139 " here (.hg not found)"))
5141 " here (.hg not found)"))
5140 o = repo
5142 o = repo
5141
5143
5142 app = hgweb.hgweb(o, baseui=baseui)
5144 app = hgweb.hgweb(o, baseui=baseui)
5143
5145
5144 class service(object):
5146 class service(object):
5145 def init(self):
5147 def init(self):
5146 util.setsignalhandler()
5148 util.setsignalhandler()
5147 self.httpd = hgweb.server.create_server(ui, app)
5149 self.httpd = hgweb.server.create_server(ui, app)
5148
5150
5149 if opts['port'] and not ui.verbose:
5151 if opts['port'] and not ui.verbose:
5150 return
5152 return
5151
5153
5152 if self.httpd.prefix:
5154 if self.httpd.prefix:
5153 prefix = self.httpd.prefix.strip('/') + '/'
5155 prefix = self.httpd.prefix.strip('/') + '/'
5154 else:
5156 else:
5155 prefix = ''
5157 prefix = ''
5156
5158
5157 port = ':%d' % self.httpd.port
5159 port = ':%d' % self.httpd.port
5158 if port == ':80':
5160 if port == ':80':
5159 port = ''
5161 port = ''
5160
5162
5161 bindaddr = self.httpd.addr
5163 bindaddr = self.httpd.addr
5162 if bindaddr == '0.0.0.0':
5164 if bindaddr == '0.0.0.0':
5163 bindaddr = '*'
5165 bindaddr = '*'
5164 elif ':' in bindaddr: # IPv6
5166 elif ':' in bindaddr: # IPv6
5165 bindaddr = '[%s]' % bindaddr
5167 bindaddr = '[%s]' % bindaddr
5166
5168
5167 fqaddr = self.httpd.fqaddr
5169 fqaddr = self.httpd.fqaddr
5168 if ':' in fqaddr:
5170 if ':' in fqaddr:
5169 fqaddr = '[%s]' % fqaddr
5171 fqaddr = '[%s]' % fqaddr
5170 if opts['port']:
5172 if opts['port']:
5171 write = ui.status
5173 write = ui.status
5172 else:
5174 else:
5173 write = ui.write
5175 write = ui.write
5174 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5176 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5175 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5177 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5176
5178
5177 def run(self):
5179 def run(self):
5178 self.httpd.serve_forever()
5180 self.httpd.serve_forever()
5179
5181
5180 service = service()
5182 service = service()
5181
5183
5182 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5184 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5183
5185
5184 @command('showconfig|debugconfig',
5186 @command('showconfig|debugconfig',
5185 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5187 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5186 _('[-u] [NAME]...'))
5188 _('[-u] [NAME]...'))
5187 def showconfig(ui, repo, *values, **opts):
5189 def showconfig(ui, repo, *values, **opts):
5188 """show combined config settings from all hgrc files
5190 """show combined config settings from all hgrc files
5189
5191
5190 With no arguments, print names and values of all config items.
5192 With no arguments, print names and values of all config items.
5191
5193
5192 With one argument of the form section.name, print just the value
5194 With one argument of the form section.name, print just the value
5193 of that config item.
5195 of that config item.
5194
5196
5195 With multiple arguments, print names and values of all config
5197 With multiple arguments, print names and values of all config
5196 items with matching section names.
5198 items with matching section names.
5197
5199
5198 With --debug, the source (filename and line number) is printed
5200 With --debug, the source (filename and line number) is printed
5199 for each config item.
5201 for each config item.
5200
5202
5201 Returns 0 on success.
5203 Returns 0 on success.
5202 """
5204 """
5203
5205
5204 for f in scmutil.rcpath():
5206 for f in scmutil.rcpath():
5205 ui.debug('read config from: %s\n' % f)
5207 ui.debug('read config from: %s\n' % f)
5206 untrusted = bool(opts.get('untrusted'))
5208 untrusted = bool(opts.get('untrusted'))
5207 if values:
5209 if values:
5208 sections = [v for v in values if '.' not in v]
5210 sections = [v for v in values if '.' not in v]
5209 items = [v for v in values if '.' in v]
5211 items = [v for v in values if '.' in v]
5210 if len(items) > 1 or items and sections:
5212 if len(items) > 1 or items and sections:
5211 raise util.Abort(_('only one config item permitted'))
5213 raise util.Abort(_('only one config item permitted'))
5212 for section, name, value in ui.walkconfig(untrusted=untrusted):
5214 for section, name, value in ui.walkconfig(untrusted=untrusted):
5213 value = str(value).replace('\n', '\\n')
5215 value = str(value).replace('\n', '\\n')
5214 sectname = section + '.' + name
5216 sectname = section + '.' + name
5215 if values:
5217 if values:
5216 for v in values:
5218 for v in values:
5217 if v == section:
5219 if v == section:
5218 ui.debug('%s: ' %
5220 ui.debug('%s: ' %
5219 ui.configsource(section, name, untrusted))
5221 ui.configsource(section, name, untrusted))
5220 ui.write('%s=%s\n' % (sectname, value))
5222 ui.write('%s=%s\n' % (sectname, value))
5221 elif v == sectname:
5223 elif v == sectname:
5222 ui.debug('%s: ' %
5224 ui.debug('%s: ' %
5223 ui.configsource(section, name, untrusted))
5225 ui.configsource(section, name, untrusted))
5224 ui.write(value, '\n')
5226 ui.write(value, '\n')
5225 else:
5227 else:
5226 ui.debug('%s: ' %
5228 ui.debug('%s: ' %
5227 ui.configsource(section, name, untrusted))
5229 ui.configsource(section, name, untrusted))
5228 ui.write('%s=%s\n' % (sectname, value))
5230 ui.write('%s=%s\n' % (sectname, value))
5229
5231
5230 @command('^status|st',
5232 @command('^status|st',
5231 [('A', 'all', None, _('show status of all files')),
5233 [('A', 'all', None, _('show status of all files')),
5232 ('m', 'modified', None, _('show only modified files')),
5234 ('m', 'modified', None, _('show only modified files')),
5233 ('a', 'added', None, _('show only added files')),
5235 ('a', 'added', None, _('show only added files')),
5234 ('r', 'removed', None, _('show only removed files')),
5236 ('r', 'removed', None, _('show only removed files')),
5235 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5237 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5236 ('c', 'clean', None, _('show only files without changes')),
5238 ('c', 'clean', None, _('show only files without changes')),
5237 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5239 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5238 ('i', 'ignored', None, _('show only ignored files')),
5240 ('i', 'ignored', None, _('show only ignored files')),
5239 ('n', 'no-status', None, _('hide status prefix')),
5241 ('n', 'no-status', None, _('hide status prefix')),
5240 ('C', 'copies', None, _('show source of copied files')),
5242 ('C', 'copies', None, _('show source of copied files')),
5241 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5243 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5242 ('', 'rev', [], _('show difference from revision'), _('REV')),
5244 ('', 'rev', [], _('show difference from revision'), _('REV')),
5243 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5245 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5244 ] + walkopts + subrepoopts,
5246 ] + walkopts + subrepoopts,
5245 _('[OPTION]... [FILE]...'))
5247 _('[OPTION]... [FILE]...'))
5246 def status(ui, repo, *pats, **opts):
5248 def status(ui, repo, *pats, **opts):
5247 """show changed files in the working directory
5249 """show changed files in the working directory
5248
5250
5249 Show status of files in the repository. If names are given, only
5251 Show status of files in the repository. If names are given, only
5250 files that match are shown. Files that are clean or ignored or
5252 files that match are shown. Files that are clean or ignored or
5251 the source of a copy/move operation, are not listed unless
5253 the source of a copy/move operation, are not listed unless
5252 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5254 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5253 Unless options described with "show only ..." are given, the
5255 Unless options described with "show only ..." are given, the
5254 options -mardu are used.
5256 options -mardu are used.
5255
5257
5256 Option -q/--quiet hides untracked (unknown and ignored) files
5258 Option -q/--quiet hides untracked (unknown and ignored) files
5257 unless explicitly requested with -u/--unknown or -i/--ignored.
5259 unless explicitly requested with -u/--unknown or -i/--ignored.
5258
5260
5259 .. note::
5261 .. note::
5260 status may appear to disagree with diff if permissions have
5262 status may appear to disagree with diff if permissions have
5261 changed or a merge has occurred. The standard diff format does
5263 changed or a merge has occurred. The standard diff format does
5262 not report permission changes and diff only reports changes
5264 not report permission changes and diff only reports changes
5263 relative to one merge parent.
5265 relative to one merge parent.
5264
5266
5265 If one revision is given, it is used as the base revision.
5267 If one revision is given, it is used as the base revision.
5266 If two revisions are given, the differences between them are
5268 If two revisions are given, the differences between them are
5267 shown. The --change option can also be used as a shortcut to list
5269 shown. The --change option can also be used as a shortcut to list
5268 the changed files of a revision from its first parent.
5270 the changed files of a revision from its first parent.
5269
5271
5270 The codes used to show the status of files are::
5272 The codes used to show the status of files are::
5271
5273
5272 M = modified
5274 M = modified
5273 A = added
5275 A = added
5274 R = removed
5276 R = removed
5275 C = clean
5277 C = clean
5276 ! = missing (deleted by non-hg command, but still tracked)
5278 ! = missing (deleted by non-hg command, but still tracked)
5277 ? = not tracked
5279 ? = not tracked
5278 I = ignored
5280 I = ignored
5279 = origin of the previous file listed as A (added)
5281 = origin of the previous file listed as A (added)
5280
5282
5281 .. container:: verbose
5283 .. container:: verbose
5282
5284
5283 Examples:
5285 Examples:
5284
5286
5285 - show changes in the working directory relative to a
5287 - show changes in the working directory relative to a
5286 changeset::
5288 changeset::
5287
5289
5288 hg status --rev 9353
5290 hg status --rev 9353
5289
5291
5290 - show all changes including copies in an existing changeset::
5292 - show all changes including copies in an existing changeset::
5291
5293
5292 hg status --copies --change 9353
5294 hg status --copies --change 9353
5293
5295
5294 - get a NUL separated list of added files, suitable for xargs::
5296 - get a NUL separated list of added files, suitable for xargs::
5295
5297
5296 hg status -an0
5298 hg status -an0
5297
5299
5298 Returns 0 on success.
5300 Returns 0 on success.
5299 """
5301 """
5300
5302
5301 revs = opts.get('rev')
5303 revs = opts.get('rev')
5302 change = opts.get('change')
5304 change = opts.get('change')
5303
5305
5304 if revs and change:
5306 if revs and change:
5305 msg = _('cannot specify --rev and --change at the same time')
5307 msg = _('cannot specify --rev and --change at the same time')
5306 raise util.Abort(msg)
5308 raise util.Abort(msg)
5307 elif change:
5309 elif change:
5308 node2 = scmutil.revsingle(repo, change, None).node()
5310 node2 = scmutil.revsingle(repo, change, None).node()
5309 node1 = repo[node2].p1().node()
5311 node1 = repo[node2].p1().node()
5310 else:
5312 else:
5311 node1, node2 = scmutil.revpair(repo, revs)
5313 node1, node2 = scmutil.revpair(repo, revs)
5312
5314
5313 cwd = (pats and repo.getcwd()) or ''
5315 cwd = (pats and repo.getcwd()) or ''
5314 end = opts.get('print0') and '\0' or '\n'
5316 end = opts.get('print0') and '\0' or '\n'
5315 copy = {}
5317 copy = {}
5316 states = 'modified added removed deleted unknown ignored clean'.split()
5318 states = 'modified added removed deleted unknown ignored clean'.split()
5317 show = [k for k in states if opts.get(k)]
5319 show = [k for k in states if opts.get(k)]
5318 if opts.get('all'):
5320 if opts.get('all'):
5319 show += ui.quiet and (states[:4] + ['clean']) or states
5321 show += ui.quiet and (states[:4] + ['clean']) or states
5320 if not show:
5322 if not show:
5321 show = ui.quiet and states[:4] or states[:5]
5323 show = ui.quiet and states[:4] or states[:5]
5322
5324
5323 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5325 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5324 'ignored' in show, 'clean' in show, 'unknown' in show,
5326 'ignored' in show, 'clean' in show, 'unknown' in show,
5325 opts.get('subrepos'))
5327 opts.get('subrepos'))
5326 changestates = zip(states, 'MAR!?IC', stat)
5328 changestates = zip(states, 'MAR!?IC', stat)
5327
5329
5328 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5330 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5329 copy = copies.pathcopies(repo[node1], repo[node2])
5331 copy = copies.pathcopies(repo[node1], repo[node2])
5330
5332
5331 fm = ui.formatter('status', opts)
5333 fm = ui.formatter('status', opts)
5332 fmt = '%s' + end
5334 fmt = '%s' + end
5333 showchar = not opts.get('no_status')
5335 showchar = not opts.get('no_status')
5334
5336
5335 for state, char, files in changestates:
5337 for state, char, files in changestates:
5336 if state in show:
5338 if state in show:
5337 label = 'status.' + state
5339 label = 'status.' + state
5338 for f in files:
5340 for f in files:
5339 fm.startitem()
5341 fm.startitem()
5340 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5342 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5341 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5343 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5342 if f in copy:
5344 if f in copy:
5343 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5345 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5344 label='status.copied')
5346 label='status.copied')
5345 fm.end()
5347 fm.end()
5346
5348
5347 @command('^summary|sum',
5349 @command('^summary|sum',
5348 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5350 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5349 def summary(ui, repo, **opts):
5351 def summary(ui, repo, **opts):
5350 """summarize working directory state
5352 """summarize working directory state
5351
5353
5352 This generates a brief summary of the working directory state,
5354 This generates a brief summary of the working directory state,
5353 including parents, branch, commit status, and available updates.
5355 including parents, branch, commit status, and available updates.
5354
5356
5355 With the --remote option, this will check the default paths for
5357 With the --remote option, this will check the default paths for
5356 incoming and outgoing changes. This can be time-consuming.
5358 incoming and outgoing changes. This can be time-consuming.
5357
5359
5358 Returns 0 on success.
5360 Returns 0 on success.
5359 """
5361 """
5360
5362
5361 ctx = repo[None]
5363 ctx = repo[None]
5362 parents = ctx.parents()
5364 parents = ctx.parents()
5363 pnode = parents[0].node()
5365 pnode = parents[0].node()
5364 marks = []
5366 marks = []
5365
5367
5366 for p in parents:
5368 for p in parents:
5367 # label with log.changeset (instead of log.parent) since this
5369 # label with log.changeset (instead of log.parent) since this
5368 # shows a working directory parent *changeset*:
5370 # shows a working directory parent *changeset*:
5369 # i18n: column positioning for "hg summary"
5371 # i18n: column positioning for "hg summary"
5370 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5372 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5371 label='log.changeset changeset.%s' % p.phasestr())
5373 label='log.changeset changeset.%s' % p.phasestr())
5372 ui.write(' '.join(p.tags()), label='log.tag')
5374 ui.write(' '.join(p.tags()), label='log.tag')
5373 if p.bookmarks():
5375 if p.bookmarks():
5374 marks.extend(p.bookmarks())
5376 marks.extend(p.bookmarks())
5375 if p.rev() == -1:
5377 if p.rev() == -1:
5376 if not len(repo):
5378 if not len(repo):
5377 ui.write(_(' (empty repository)'))
5379 ui.write(_(' (empty repository)'))
5378 else:
5380 else:
5379 ui.write(_(' (no revision checked out)'))
5381 ui.write(_(' (no revision checked out)'))
5380 ui.write('\n')
5382 ui.write('\n')
5381 if p.description():
5383 if p.description():
5382 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5384 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5383 label='log.summary')
5385 label='log.summary')
5384
5386
5385 branch = ctx.branch()
5387 branch = ctx.branch()
5386 bheads = repo.branchheads(branch)
5388 bheads = repo.branchheads(branch)
5387 # i18n: column positioning for "hg summary"
5389 # i18n: column positioning for "hg summary"
5388 m = _('branch: %s\n') % branch
5390 m = _('branch: %s\n') % branch
5389 if branch != 'default':
5391 if branch != 'default':
5390 ui.write(m, label='log.branch')
5392 ui.write(m, label='log.branch')
5391 else:
5393 else:
5392 ui.status(m, label='log.branch')
5394 ui.status(m, label='log.branch')
5393
5395
5394 if marks:
5396 if marks:
5395 current = repo._bookmarkcurrent
5397 current = repo._bookmarkcurrent
5396 # i18n: column positioning for "hg summary"
5398 # i18n: column positioning for "hg summary"
5397 ui.write(_('bookmarks:'), label='log.bookmark')
5399 ui.write(_('bookmarks:'), label='log.bookmark')
5398 if current is not None:
5400 if current is not None:
5399 if current in marks:
5401 if current in marks:
5400 ui.write(' *' + current, label='bookmarks.current')
5402 ui.write(' *' + current, label='bookmarks.current')
5401 marks.remove(current)
5403 marks.remove(current)
5402 else:
5404 else:
5403 ui.write(' [%s]' % current, label='bookmarks.current')
5405 ui.write(' [%s]' % current, label='bookmarks.current')
5404 for m in marks:
5406 for m in marks:
5405 ui.write(' ' + m, label='log.bookmark')
5407 ui.write(' ' + m, label='log.bookmark')
5406 ui.write('\n', label='log.bookmark')
5408 ui.write('\n', label='log.bookmark')
5407
5409
5408 st = list(repo.status(unknown=True))[:6]
5410 st = list(repo.status(unknown=True))[:6]
5409
5411
5410 c = repo.dirstate.copies()
5412 c = repo.dirstate.copies()
5411 copied, renamed = [], []
5413 copied, renamed = [], []
5412 for d, s in c.iteritems():
5414 for d, s in c.iteritems():
5413 if s in st[2]:
5415 if s in st[2]:
5414 st[2].remove(s)
5416 st[2].remove(s)
5415 renamed.append(d)
5417 renamed.append(d)
5416 else:
5418 else:
5417 copied.append(d)
5419 copied.append(d)
5418 if d in st[1]:
5420 if d in st[1]:
5419 st[1].remove(d)
5421 st[1].remove(d)
5420 st.insert(3, renamed)
5422 st.insert(3, renamed)
5421 st.insert(4, copied)
5423 st.insert(4, copied)
5422
5424
5423 ms = mergemod.mergestate(repo)
5425 ms = mergemod.mergestate(repo)
5424 st.append([f for f in ms if ms[f] == 'u'])
5426 st.append([f for f in ms if ms[f] == 'u'])
5425
5427
5426 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5428 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5427 st.append(subs)
5429 st.append(subs)
5428
5430
5429 labels = [ui.label(_('%d modified'), 'status.modified'),
5431 labels = [ui.label(_('%d modified'), 'status.modified'),
5430 ui.label(_('%d added'), 'status.added'),
5432 ui.label(_('%d added'), 'status.added'),
5431 ui.label(_('%d removed'), 'status.removed'),
5433 ui.label(_('%d removed'), 'status.removed'),
5432 ui.label(_('%d renamed'), 'status.copied'),
5434 ui.label(_('%d renamed'), 'status.copied'),
5433 ui.label(_('%d copied'), 'status.copied'),
5435 ui.label(_('%d copied'), 'status.copied'),
5434 ui.label(_('%d deleted'), 'status.deleted'),
5436 ui.label(_('%d deleted'), 'status.deleted'),
5435 ui.label(_('%d unknown'), 'status.unknown'),
5437 ui.label(_('%d unknown'), 'status.unknown'),
5436 ui.label(_('%d ignored'), 'status.ignored'),
5438 ui.label(_('%d ignored'), 'status.ignored'),
5437 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5439 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5438 ui.label(_('%d subrepos'), 'status.modified')]
5440 ui.label(_('%d subrepos'), 'status.modified')]
5439 t = []
5441 t = []
5440 for s, l in zip(st, labels):
5442 for s, l in zip(st, labels):
5441 if s:
5443 if s:
5442 t.append(l % len(s))
5444 t.append(l % len(s))
5443
5445
5444 t = ', '.join(t)
5446 t = ', '.join(t)
5445 cleanworkdir = False
5447 cleanworkdir = False
5446
5448
5447 if len(parents) > 1:
5449 if len(parents) > 1:
5448 t += _(' (merge)')
5450 t += _(' (merge)')
5449 elif branch != parents[0].branch():
5451 elif branch != parents[0].branch():
5450 t += _(' (new branch)')
5452 t += _(' (new branch)')
5451 elif (parents[0].closesbranch() and
5453 elif (parents[0].closesbranch() and
5452 pnode in repo.branchheads(branch, closed=True)):
5454 pnode in repo.branchheads(branch, closed=True)):
5453 t += _(' (head closed)')
5455 t += _(' (head closed)')
5454 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5456 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5455 t += _(' (clean)')
5457 t += _(' (clean)')
5456 cleanworkdir = True
5458 cleanworkdir = True
5457 elif pnode not in bheads:
5459 elif pnode not in bheads:
5458 t += _(' (new branch head)')
5460 t += _(' (new branch head)')
5459
5461
5460 if cleanworkdir:
5462 if cleanworkdir:
5461 # i18n: column positioning for "hg summary"
5463 # i18n: column positioning for "hg summary"
5462 ui.status(_('commit: %s\n') % t.strip())
5464 ui.status(_('commit: %s\n') % t.strip())
5463 else:
5465 else:
5464 # i18n: column positioning for "hg summary"
5466 # i18n: column positioning for "hg summary"
5465 ui.write(_('commit: %s\n') % t.strip())
5467 ui.write(_('commit: %s\n') % t.strip())
5466
5468
5467 # all ancestors of branch heads - all ancestors of parent = new csets
5469 # all ancestors of branch heads - all ancestors of parent = new csets
5468 new = [0] * len(repo)
5470 new = [0] * len(repo)
5469 cl = repo.changelog
5471 cl = repo.changelog
5470 for a in [cl.rev(n) for n in bheads]:
5472 for a in [cl.rev(n) for n in bheads]:
5471 new[a] = 1
5473 new[a] = 1
5472 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5474 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5473 new[a] = 1
5475 new[a] = 1
5474 for a in [p.rev() for p in parents]:
5476 for a in [p.rev() for p in parents]:
5475 if a >= 0:
5477 if a >= 0:
5476 new[a] = 0
5478 new[a] = 0
5477 for a in cl.ancestors([p.rev() for p in parents]):
5479 for a in cl.ancestors([p.rev() for p in parents]):
5478 new[a] = 0
5480 new[a] = 0
5479 new = sum(new)
5481 new = sum(new)
5480
5482
5481 if new == 0:
5483 if new == 0:
5482 # i18n: column positioning for "hg summary"
5484 # i18n: column positioning for "hg summary"
5483 ui.status(_('update: (current)\n'))
5485 ui.status(_('update: (current)\n'))
5484 elif pnode not in bheads:
5486 elif pnode not in bheads:
5485 # i18n: column positioning for "hg summary"
5487 # i18n: column positioning for "hg summary"
5486 ui.write(_('update: %d new changesets (update)\n') % new)
5488 ui.write(_('update: %d new changesets (update)\n') % new)
5487 else:
5489 else:
5488 # i18n: column positioning for "hg summary"
5490 # i18n: column positioning for "hg summary"
5489 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5491 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5490 (new, len(bheads)))
5492 (new, len(bheads)))
5491
5493
5492 cmdutil.summaryhooks(ui, repo)
5494 cmdutil.summaryhooks(ui, repo)
5493
5495
5494 if opts.get('remote'):
5496 if opts.get('remote'):
5495 t = []
5497 t = []
5496 source, branches = hg.parseurl(ui.expandpath('default'))
5498 source, branches = hg.parseurl(ui.expandpath('default'))
5497 sbranch = branches[0]
5499 sbranch = branches[0]
5498 other = hg.peer(repo, {}, source)
5500 other = hg.peer(repo, {}, source)
5499 revs, checkout = hg.addbranchrevs(repo, other, branches,
5501 revs, checkout = hg.addbranchrevs(repo, other, branches,
5500 opts.get('rev'))
5502 opts.get('rev'))
5501 if revs:
5503 if revs:
5502 revs = [other.lookup(rev) for rev in revs]
5504 revs = [other.lookup(rev) for rev in revs]
5503 ui.debug('comparing with %s\n' % util.hidepassword(source))
5505 ui.debug('comparing with %s\n' % util.hidepassword(source))
5504 repo.ui.pushbuffer()
5506 repo.ui.pushbuffer()
5505 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5507 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5506 _common, incoming, _rheads = commoninc
5508 _common, incoming, _rheads = commoninc
5507 repo.ui.popbuffer()
5509 repo.ui.popbuffer()
5508 if incoming:
5510 if incoming:
5509 t.append(_('1 or more incoming'))
5511 t.append(_('1 or more incoming'))
5510
5512
5511 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5513 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5512 dbranch = branches[0]
5514 dbranch = branches[0]
5513 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5515 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5514 if source != dest:
5516 if source != dest:
5515 other = hg.peer(repo, {}, dest)
5517 other = hg.peer(repo, {}, dest)
5516 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5518 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5517 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5519 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5518 commoninc = None
5520 commoninc = None
5519 if revs:
5521 if revs:
5520 revs = [repo.lookup(rev) for rev in revs]
5522 revs = [repo.lookup(rev) for rev in revs]
5521 repo.ui.pushbuffer()
5523 repo.ui.pushbuffer()
5522 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5524 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5523 commoninc=commoninc)
5525 commoninc=commoninc)
5524 repo.ui.popbuffer()
5526 repo.ui.popbuffer()
5525 o = outgoing.missing
5527 o = outgoing.missing
5526 if o:
5528 if o:
5527 t.append(_('%d outgoing') % len(o))
5529 t.append(_('%d outgoing') % len(o))
5528 if 'bookmarks' in other.listkeys('namespaces'):
5530 if 'bookmarks' in other.listkeys('namespaces'):
5529 lmarks = repo.listkeys('bookmarks')
5531 lmarks = repo.listkeys('bookmarks')
5530 rmarks = other.listkeys('bookmarks')
5532 rmarks = other.listkeys('bookmarks')
5531 diff = set(rmarks) - set(lmarks)
5533 diff = set(rmarks) - set(lmarks)
5532 if len(diff) > 0:
5534 if len(diff) > 0:
5533 t.append(_('%d incoming bookmarks') % len(diff))
5535 t.append(_('%d incoming bookmarks') % len(diff))
5534 diff = set(lmarks) - set(rmarks)
5536 diff = set(lmarks) - set(rmarks)
5535 if len(diff) > 0:
5537 if len(diff) > 0:
5536 t.append(_('%d outgoing bookmarks') % len(diff))
5538 t.append(_('%d outgoing bookmarks') % len(diff))
5537
5539
5538 if t:
5540 if t:
5539 # i18n: column positioning for "hg summary"
5541 # i18n: column positioning for "hg summary"
5540 ui.write(_('remote: %s\n') % (', '.join(t)))
5542 ui.write(_('remote: %s\n') % (', '.join(t)))
5541 else:
5543 else:
5542 # i18n: column positioning for "hg summary"
5544 # i18n: column positioning for "hg summary"
5543 ui.status(_('remote: (synced)\n'))
5545 ui.status(_('remote: (synced)\n'))
5544
5546
5545 @command('tag',
5547 @command('tag',
5546 [('f', 'force', None, _('force tag')),
5548 [('f', 'force', None, _('force tag')),
5547 ('l', 'local', None, _('make the tag local')),
5549 ('l', 'local', None, _('make the tag local')),
5548 ('r', 'rev', '', _('revision to tag'), _('REV')),
5550 ('r', 'rev', '', _('revision to tag'), _('REV')),
5549 ('', 'remove', None, _('remove a tag')),
5551 ('', 'remove', None, _('remove a tag')),
5550 # -l/--local is already there, commitopts cannot be used
5552 # -l/--local is already there, commitopts cannot be used
5551 ('e', 'edit', None, _('edit commit message')),
5553 ('e', 'edit', None, _('edit commit message')),
5552 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5554 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5553 ] + commitopts2,
5555 ] + commitopts2,
5554 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5556 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5555 def tag(ui, repo, name1, *names, **opts):
5557 def tag(ui, repo, name1, *names, **opts):
5556 """add one or more tags for the current or given revision
5558 """add one or more tags for the current or given revision
5557
5559
5558 Name a particular revision using <name>.
5560 Name a particular revision using <name>.
5559
5561
5560 Tags are used to name particular revisions of the repository and are
5562 Tags are used to name particular revisions of the repository and are
5561 very useful to compare different revisions, to go back to significant
5563 very useful to compare different revisions, to go back to significant
5562 earlier versions or to mark branch points as releases, etc. Changing
5564 earlier versions or to mark branch points as releases, etc. Changing
5563 an existing tag is normally disallowed; use -f/--force to override.
5565 an existing tag is normally disallowed; use -f/--force to override.
5564
5566
5565 If no revision is given, the parent of the working directory is
5567 If no revision is given, the parent of the working directory is
5566 used, or tip if no revision is checked out.
5568 used, or tip if no revision is checked out.
5567
5569
5568 To facilitate version control, distribution, and merging of tags,
5570 To facilitate version control, distribution, and merging of tags,
5569 they are stored as a file named ".hgtags" which is managed similarly
5571 they are stored as a file named ".hgtags" which is managed similarly
5570 to other project files and can be hand-edited if necessary. This
5572 to other project files and can be hand-edited if necessary. This
5571 also means that tagging creates a new commit. The file
5573 also means that tagging creates a new commit. The file
5572 ".hg/localtags" is used for local tags (not shared among
5574 ".hg/localtags" is used for local tags (not shared among
5573 repositories).
5575 repositories).
5574
5576
5575 Tag commits are usually made at the head of a branch. If the parent
5577 Tag commits are usually made at the head of a branch. If the parent
5576 of the working directory is not a branch head, :hg:`tag` aborts; use
5578 of the working directory is not a branch head, :hg:`tag` aborts; use
5577 -f/--force to force the tag commit to be based on a non-head
5579 -f/--force to force the tag commit to be based on a non-head
5578 changeset.
5580 changeset.
5579
5581
5580 See :hg:`help dates` for a list of formats valid for -d/--date.
5582 See :hg:`help dates` for a list of formats valid for -d/--date.
5581
5583
5582 Since tag names have priority over branch names during revision
5584 Since tag names have priority over branch names during revision
5583 lookup, using an existing branch name as a tag name is discouraged.
5585 lookup, using an existing branch name as a tag name is discouraged.
5584
5586
5585 Returns 0 on success.
5587 Returns 0 on success.
5586 """
5588 """
5587 wlock = lock = None
5589 wlock = lock = None
5588 try:
5590 try:
5589 wlock = repo.wlock()
5591 wlock = repo.wlock()
5590 lock = repo.lock()
5592 lock = repo.lock()
5591 rev_ = "."
5593 rev_ = "."
5592 names = [t.strip() for t in (name1,) + names]
5594 names = [t.strip() for t in (name1,) + names]
5593 if len(names) != len(set(names)):
5595 if len(names) != len(set(names)):
5594 raise util.Abort(_('tag names must be unique'))
5596 raise util.Abort(_('tag names must be unique'))
5595 for n in names:
5597 for n in names:
5596 scmutil.checknewlabel(repo, n, 'tag')
5598 scmutil.checknewlabel(repo, n, 'tag')
5597 if not n:
5599 if not n:
5598 raise util.Abort(_('tag names cannot consist entirely of '
5600 raise util.Abort(_('tag names cannot consist entirely of '
5599 'whitespace'))
5601 'whitespace'))
5600 if opts.get('rev') and opts.get('remove'):
5602 if opts.get('rev') and opts.get('remove'):
5601 raise util.Abort(_("--rev and --remove are incompatible"))
5603 raise util.Abort(_("--rev and --remove are incompatible"))
5602 if opts.get('rev'):
5604 if opts.get('rev'):
5603 rev_ = opts['rev']
5605 rev_ = opts['rev']
5604 message = opts.get('message')
5606 message = opts.get('message')
5605 if opts.get('remove'):
5607 if opts.get('remove'):
5606 expectedtype = opts.get('local') and 'local' or 'global'
5608 expectedtype = opts.get('local') and 'local' or 'global'
5607 for n in names:
5609 for n in names:
5608 if not repo.tagtype(n):
5610 if not repo.tagtype(n):
5609 raise util.Abort(_("tag '%s' does not exist") % n)
5611 raise util.Abort(_("tag '%s' does not exist") % n)
5610 if repo.tagtype(n) != expectedtype:
5612 if repo.tagtype(n) != expectedtype:
5611 if expectedtype == 'global':
5613 if expectedtype == 'global':
5612 raise util.Abort(_("tag '%s' is not a global tag") % n)
5614 raise util.Abort(_("tag '%s' is not a global tag") % n)
5613 else:
5615 else:
5614 raise util.Abort(_("tag '%s' is not a local tag") % n)
5616 raise util.Abort(_("tag '%s' is not a local tag") % n)
5615 rev_ = nullid
5617 rev_ = nullid
5616 if not message:
5618 if not message:
5617 # we don't translate commit messages
5619 # we don't translate commit messages
5618 message = 'Removed tag %s' % ', '.join(names)
5620 message = 'Removed tag %s' % ', '.join(names)
5619 elif not opts.get('force'):
5621 elif not opts.get('force'):
5620 for n in names:
5622 for n in names:
5621 if n in repo.tags():
5623 if n in repo.tags():
5622 raise util.Abort(_("tag '%s' already exists "
5624 raise util.Abort(_("tag '%s' already exists "
5623 "(use -f to force)") % n)
5625 "(use -f to force)") % n)
5624 if not opts.get('local'):
5626 if not opts.get('local'):
5625 p1, p2 = repo.dirstate.parents()
5627 p1, p2 = repo.dirstate.parents()
5626 if p2 != nullid:
5628 if p2 != nullid:
5627 raise util.Abort(_('uncommitted merge'))
5629 raise util.Abort(_('uncommitted merge'))
5628 bheads = repo.branchheads()
5630 bheads = repo.branchheads()
5629 if not opts.get('force') and bheads and p1 not in bheads:
5631 if not opts.get('force') and bheads and p1 not in bheads:
5630 raise util.Abort(_('not at a branch head (use -f to force)'))
5632 raise util.Abort(_('not at a branch head (use -f to force)'))
5631 r = scmutil.revsingle(repo, rev_).node()
5633 r = scmutil.revsingle(repo, rev_).node()
5632
5634
5633 if not message:
5635 if not message:
5634 # we don't translate commit messages
5636 # we don't translate commit messages
5635 message = ('Added tag %s for changeset %s' %
5637 message = ('Added tag %s for changeset %s' %
5636 (', '.join(names), short(r)))
5638 (', '.join(names), short(r)))
5637
5639
5638 date = opts.get('date')
5640 date = opts.get('date')
5639 if date:
5641 if date:
5640 date = util.parsedate(date)
5642 date = util.parsedate(date)
5641
5643
5642 if opts.get('edit'):
5644 if opts.get('edit'):
5643 message = ui.edit(message, ui.username())
5645 message = ui.edit(message, ui.username())
5644
5646
5645 # don't allow tagging the null rev
5647 # don't allow tagging the null rev
5646 if (not opts.get('remove') and
5648 if (not opts.get('remove') and
5647 scmutil.revsingle(repo, rev_).rev() == nullrev):
5649 scmutil.revsingle(repo, rev_).rev() == nullrev):
5648 raise util.Abort(_("cannot tag null revision"))
5650 raise util.Abort(_("cannot tag null revision"))
5649
5651
5650 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5652 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5651 finally:
5653 finally:
5652 release(lock, wlock)
5654 release(lock, wlock)
5653
5655
5654 @command('tags', [], '')
5656 @command('tags', [], '')
5655 def tags(ui, repo, **opts):
5657 def tags(ui, repo, **opts):
5656 """list repository tags
5658 """list repository tags
5657
5659
5658 This lists both regular and local tags. When the -v/--verbose
5660 This lists both regular and local tags. When the -v/--verbose
5659 switch is used, a third column "local" is printed for local tags.
5661 switch is used, a third column "local" is printed for local tags.
5660
5662
5661 Returns 0 on success.
5663 Returns 0 on success.
5662 """
5664 """
5663
5665
5664 fm = ui.formatter('tags', opts)
5666 fm = ui.formatter('tags', opts)
5665 hexfunc = ui.debugflag and hex or short
5667 hexfunc = ui.debugflag and hex or short
5666 tagtype = ""
5668 tagtype = ""
5667
5669
5668 for t, n in reversed(repo.tagslist()):
5670 for t, n in reversed(repo.tagslist()):
5669 hn = hexfunc(n)
5671 hn = hexfunc(n)
5670 label = 'tags.normal'
5672 label = 'tags.normal'
5671 tagtype = ''
5673 tagtype = ''
5672 if repo.tagtype(t) == 'local':
5674 if repo.tagtype(t) == 'local':
5673 label = 'tags.local'
5675 label = 'tags.local'
5674 tagtype = 'local'
5676 tagtype = 'local'
5675
5677
5676 fm.startitem()
5678 fm.startitem()
5677 fm.write('tag', '%s', t, label=label)
5679 fm.write('tag', '%s', t, label=label)
5678 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5680 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5679 fm.condwrite(not ui.quiet, 'rev id', fmt,
5681 fm.condwrite(not ui.quiet, 'rev id', fmt,
5680 repo.changelog.rev(n), hn, label=label)
5682 repo.changelog.rev(n), hn, label=label)
5681 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5683 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5682 tagtype, label=label)
5684 tagtype, label=label)
5683 fm.plain('\n')
5685 fm.plain('\n')
5684 fm.end()
5686 fm.end()
5685
5687
5686 @command('tip',
5688 @command('tip',
5687 [('p', 'patch', None, _('show patch')),
5689 [('p', 'patch', None, _('show patch')),
5688 ('g', 'git', None, _('use git extended diff format')),
5690 ('g', 'git', None, _('use git extended diff format')),
5689 ] + templateopts,
5691 ] + templateopts,
5690 _('[-p] [-g]'))
5692 _('[-p] [-g]'))
5691 def tip(ui, repo, **opts):
5693 def tip(ui, repo, **opts):
5692 """show the tip revision
5694 """show the tip revision
5693
5695
5694 The tip revision (usually just called the tip) is the changeset
5696 The tip revision (usually just called the tip) is the changeset
5695 most recently added to the repository (and therefore the most
5697 most recently added to the repository (and therefore the most
5696 recently changed head).
5698 recently changed head).
5697
5699
5698 If you have just made a commit, that commit will be the tip. If
5700 If you have just made a commit, that commit will be the tip. If
5699 you have just pulled changes from another repository, the tip of
5701 you have just pulled changes from another repository, the tip of
5700 that repository becomes the current tip. The "tip" tag is special
5702 that repository becomes the current tip. The "tip" tag is special
5701 and cannot be renamed or assigned to a different changeset.
5703 and cannot be renamed or assigned to a different changeset.
5702
5704
5703 Returns 0 on success.
5705 Returns 0 on success.
5704 """
5706 """
5705 displayer = cmdutil.show_changeset(ui, repo, opts)
5707 displayer = cmdutil.show_changeset(ui, repo, opts)
5706 displayer.show(repo['tip'])
5708 displayer.show(repo['tip'])
5707 displayer.close()
5709 displayer.close()
5708
5710
5709 @command('unbundle',
5711 @command('unbundle',
5710 [('u', 'update', None,
5712 [('u', 'update', None,
5711 _('update to new branch head if changesets were unbundled'))],
5713 _('update to new branch head if changesets were unbundled'))],
5712 _('[-u] FILE...'))
5714 _('[-u] FILE...'))
5713 def unbundle(ui, repo, fname1, *fnames, **opts):
5715 def unbundle(ui, repo, fname1, *fnames, **opts):
5714 """apply one or more changegroup files
5716 """apply one or more changegroup files
5715
5717
5716 Apply one or more compressed changegroup files generated by the
5718 Apply one or more compressed changegroup files generated by the
5717 bundle command.
5719 bundle command.
5718
5720
5719 Returns 0 on success, 1 if an update has unresolved files.
5721 Returns 0 on success, 1 if an update has unresolved files.
5720 """
5722 """
5721 fnames = (fname1,) + fnames
5723 fnames = (fname1,) + fnames
5722
5724
5723 lock = repo.lock()
5725 lock = repo.lock()
5724 wc = repo['.']
5726 wc = repo['.']
5725 try:
5727 try:
5726 for fname in fnames:
5728 for fname in fnames:
5727 f = hg.openpath(ui, fname)
5729 f = hg.openpath(ui, fname)
5728 gen = changegroup.readbundle(f, fname)
5730 gen = changegroup.readbundle(f, fname)
5729 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5731 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5730 finally:
5732 finally:
5731 lock.release()
5733 lock.release()
5732 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5734 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5733 return postincoming(ui, repo, modheads, opts.get('update'), None)
5735 return postincoming(ui, repo, modheads, opts.get('update'), None)
5734
5736
5735 @command('^update|up|checkout|co',
5737 @command('^update|up|checkout|co',
5736 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5738 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5737 ('c', 'check', None,
5739 ('c', 'check', None,
5738 _('update across branches if no uncommitted changes')),
5740 _('update across branches if no uncommitted changes')),
5739 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5741 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5740 ('r', 'rev', '', _('revision'), _('REV'))],
5742 ('r', 'rev', '', _('revision'), _('REV'))],
5741 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5743 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5742 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5744 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5743 """update working directory (or switch revisions)
5745 """update working directory (or switch revisions)
5744
5746
5745 Update the repository's working directory to the specified
5747 Update the repository's working directory to the specified
5746 changeset. If no changeset is specified, update to the tip of the
5748 changeset. If no changeset is specified, update to the tip of the
5747 current named branch and move the current bookmark (see :hg:`help
5749 current named branch and move the current bookmark (see :hg:`help
5748 bookmarks`).
5750 bookmarks`).
5749
5751
5750 Update sets the working directory's parent revision to the specified
5752 Update sets the working directory's parent revision to the specified
5751 changeset (see :hg:`help parents`).
5753 changeset (see :hg:`help parents`).
5752
5754
5753 If the changeset is not a descendant or ancestor of the working
5755 If the changeset is not a descendant or ancestor of the working
5754 directory's parent, the update is aborted. With the -c/--check
5756 directory's parent, the update is aborted. With the -c/--check
5755 option, the working directory is checked for uncommitted changes; if
5757 option, the working directory is checked for uncommitted changes; if
5756 none are found, the working directory is updated to the specified
5758 none are found, the working directory is updated to the specified
5757 changeset.
5759 changeset.
5758
5760
5759 .. container:: verbose
5761 .. container:: verbose
5760
5762
5761 The following rules apply when the working directory contains
5763 The following rules apply when the working directory contains
5762 uncommitted changes:
5764 uncommitted changes:
5763
5765
5764 1. If neither -c/--check nor -C/--clean is specified, and if
5766 1. If neither -c/--check nor -C/--clean is specified, and if
5765 the requested changeset is an ancestor or descendant of
5767 the requested changeset is an ancestor or descendant of
5766 the working directory's parent, the uncommitted changes
5768 the working directory's parent, the uncommitted changes
5767 are merged into the requested changeset and the merged
5769 are merged into the requested changeset and the merged
5768 result is left uncommitted. If the requested changeset is
5770 result is left uncommitted. If the requested changeset is
5769 not an ancestor or descendant (that is, it is on another
5771 not an ancestor or descendant (that is, it is on another
5770 branch), the update is aborted and the uncommitted changes
5772 branch), the update is aborted and the uncommitted changes
5771 are preserved.
5773 are preserved.
5772
5774
5773 2. With the -c/--check option, the update is aborted and the
5775 2. With the -c/--check option, the update is aborted and the
5774 uncommitted changes are preserved.
5776 uncommitted changes are preserved.
5775
5777
5776 3. With the -C/--clean option, uncommitted changes are discarded and
5778 3. With the -C/--clean option, uncommitted changes are discarded and
5777 the working directory is updated to the requested changeset.
5779 the working directory is updated to the requested changeset.
5778
5780
5779 To cancel an uncommitted merge (and lose your changes), use
5781 To cancel an uncommitted merge (and lose your changes), use
5780 :hg:`update --clean .`.
5782 :hg:`update --clean .`.
5781
5783
5782 Use null as the changeset to remove the working directory (like
5784 Use null as the changeset to remove the working directory (like
5783 :hg:`clone -U`).
5785 :hg:`clone -U`).
5784
5786
5785 If you want to revert just one file to an older revision, use
5787 If you want to revert just one file to an older revision, use
5786 :hg:`revert [-r REV] NAME`.
5788 :hg:`revert [-r REV] NAME`.
5787
5789
5788 See :hg:`help dates` for a list of formats valid for -d/--date.
5790 See :hg:`help dates` for a list of formats valid for -d/--date.
5789
5791
5790 Returns 0 on success, 1 if there are unresolved files.
5792 Returns 0 on success, 1 if there are unresolved files.
5791 """
5793 """
5792 if rev and node:
5794 if rev and node:
5793 raise util.Abort(_("please specify just one revision"))
5795 raise util.Abort(_("please specify just one revision"))
5794
5796
5795 if rev is None or rev == '':
5797 if rev is None or rev == '':
5796 rev = node
5798 rev = node
5797
5799
5798 # with no argument, we also move the current bookmark, if any
5800 # with no argument, we also move the current bookmark, if any
5799 movemarkfrom = None
5801 movemarkfrom = None
5800 if rev is None:
5802 if rev is None:
5801 curmark = repo._bookmarkcurrent
5803 curmark = repo._bookmarkcurrent
5802 if bookmarks.iscurrent(repo):
5804 if bookmarks.iscurrent(repo):
5803 movemarkfrom = repo['.'].node()
5805 movemarkfrom = repo['.'].node()
5804 elif curmark:
5806 elif curmark:
5805 ui.status(_("updating to active bookmark %s\n") % curmark)
5807 ui.status(_("updating to active bookmark %s\n") % curmark)
5806 rev = curmark
5808 rev = curmark
5807
5809
5808 # if we defined a bookmark, we have to remember the original bookmark name
5810 # if we defined a bookmark, we have to remember the original bookmark name
5809 brev = rev
5811 brev = rev
5810 rev = scmutil.revsingle(repo, rev, rev).rev()
5812 rev = scmutil.revsingle(repo, rev, rev).rev()
5811
5813
5812 if check and clean:
5814 if check and clean:
5813 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5815 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5814
5816
5815 if date:
5817 if date:
5816 if rev is not None:
5818 if rev is not None:
5817 raise util.Abort(_("you can't specify a revision and a date"))
5819 raise util.Abort(_("you can't specify a revision and a date"))
5818 rev = cmdutil.finddate(ui, repo, date)
5820 rev = cmdutil.finddate(ui, repo, date)
5819
5821
5820 if check:
5822 if check:
5821 c = repo[None]
5823 c = repo[None]
5822 if c.dirty(merge=False, branch=False, missing=True):
5824 if c.dirty(merge=False, branch=False, missing=True):
5823 raise util.Abort(_("uncommitted local changes"))
5825 raise util.Abort(_("uncommitted local changes"))
5824 if rev is None:
5826 if rev is None:
5825 rev = repo[repo[None].branch()].rev()
5827 rev = repo[repo[None].branch()].rev()
5826 mergemod._checkunknown(repo, repo[None], repo[rev])
5828 mergemod._checkunknown(repo, repo[None], repo[rev])
5827
5829
5828 if clean:
5830 if clean:
5829 ret = hg.clean(repo, rev)
5831 ret = hg.clean(repo, rev)
5830 else:
5832 else:
5831 ret = hg.update(repo, rev)
5833 ret = hg.update(repo, rev)
5832
5834
5833 if not ret and movemarkfrom:
5835 if not ret and movemarkfrom:
5834 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5836 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5835 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5837 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5836 elif brev in repo._bookmarks:
5838 elif brev in repo._bookmarks:
5837 bookmarks.setcurrent(repo, brev)
5839 bookmarks.setcurrent(repo, brev)
5838 elif brev:
5840 elif brev:
5839 bookmarks.unsetcurrent(repo)
5841 bookmarks.unsetcurrent(repo)
5840
5842
5841 return ret
5843 return ret
5842
5844
5843 @command('verify', [])
5845 @command('verify', [])
5844 def verify(ui, repo):
5846 def verify(ui, repo):
5845 """verify the integrity of the repository
5847 """verify the integrity of the repository
5846
5848
5847 Verify the integrity of the current repository.
5849 Verify the integrity of the current repository.
5848
5850
5849 This will perform an extensive check of the repository's
5851 This will perform an extensive check of the repository's
5850 integrity, validating the hashes and checksums of each entry in
5852 integrity, validating the hashes and checksums of each entry in
5851 the changelog, manifest, and tracked files, as well as the
5853 the changelog, manifest, and tracked files, as well as the
5852 integrity of their crosslinks and indices.
5854 integrity of their crosslinks and indices.
5853
5855
5854 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5856 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5855 for more information about recovery from corruption of the
5857 for more information about recovery from corruption of the
5856 repository.
5858 repository.
5857
5859
5858 Returns 0 on success, 1 if errors are encountered.
5860 Returns 0 on success, 1 if errors are encountered.
5859 """
5861 """
5860 return hg.verify(repo)
5862 return hg.verify(repo)
5861
5863
5862 @command('version', [])
5864 @command('version', [])
5863 def version_(ui):
5865 def version_(ui):
5864 """output version and copyright information"""
5866 """output version and copyright information"""
5865 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5867 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5866 % util.version())
5868 % util.version())
5867 ui.status(_(
5869 ui.status(_(
5868 "(see http://mercurial.selenic.com for more information)\n"
5870 "(see http://mercurial.selenic.com for more information)\n"
5869 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5871 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5870 "This is free software; see the source for copying conditions. "
5872 "This is free software; see the source for copying conditions. "
5871 "There is NO\nwarranty; "
5873 "There is NO\nwarranty; "
5872 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5874 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5873 ))
5875 ))
5874
5876
5875 norepo = ("clone init version help debugcommands debugcomplete"
5877 norepo = ("clone init version help debugcommands debugcomplete"
5876 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5878 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5877 " debugknown debuggetbundle debugbundle")
5879 " debugknown debuggetbundle debugbundle")
5878 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5880 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5879 " debugdata debugindex debugindexdot debugrevlog")
5881 " debugdata debugindex debugindexdot debugrevlog")
5880 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5882 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5881 " remove resolve status debugwalk")
5883 " remove resolve status debugwalk")
@@ -1,866 +1,869 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching 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 i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 class request(object):
14 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 ferr=None):
16 ferr=None):
17 self.args = args
17 self.args = args
18 self.ui = ui
18 self.ui = ui
19 self.repo = repo
19 self.repo = repo
20
20
21 # input/output/error streams
21 # input/output/error streams
22 self.fin = fin
22 self.fin = fin
23 self.fout = fout
23 self.fout = fout
24 self.ferr = ferr
24 self.ferr = ferr
25
25
26 def run():
26 def run():
27 "run the command in sys.argv"
27 "run the command in sys.argv"
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29
29
30 def dispatch(req):
30 def dispatch(req):
31 "run the command specified in req.args"
31 "run the command specified in req.args"
32 if req.ferr:
32 if req.ferr:
33 ferr = req.ferr
33 ferr = req.ferr
34 elif req.ui:
34 elif req.ui:
35 ferr = req.ui.ferr
35 ferr = req.ui.ferr
36 else:
36 else:
37 ferr = sys.stderr
37 ferr = sys.stderr
38
38
39 try:
39 try:
40 if not req.ui:
40 if not req.ui:
41 req.ui = uimod.ui()
41 req.ui = uimod.ui()
42 if '--traceback' in req.args:
42 if '--traceback' in req.args:
43 req.ui.setconfig('ui', 'traceback', 'on')
43 req.ui.setconfig('ui', 'traceback', 'on')
44
44
45 # set ui streams from the request
45 # set ui streams from the request
46 if req.fin:
46 if req.fin:
47 req.ui.fin = req.fin
47 req.ui.fin = req.fin
48 if req.fout:
48 if req.fout:
49 req.ui.fout = req.fout
49 req.ui.fout = req.fout
50 if req.ferr:
50 if req.ferr:
51 req.ui.ferr = req.ferr
51 req.ui.ferr = req.ferr
52 except util.Abort, inst:
52 except util.Abort, inst:
53 ferr.write(_("abort: %s\n") % inst)
53 ferr.write(_("abort: %s\n") % inst)
54 if inst.hint:
54 if inst.hint:
55 ferr.write(_("(%s)\n") % inst.hint)
55 ferr.write(_("(%s)\n") % inst.hint)
56 return -1
56 return -1
57 except error.ParseError, inst:
57 except error.ParseError, inst:
58 if len(inst.args) > 1:
58 if len(inst.args) > 1:
59 ferr.write(_("hg: parse error at %s: %s\n") %
59 ferr.write(_("hg: parse error at %s: %s\n") %
60 (inst.args[1], inst.args[0]))
60 (inst.args[1], inst.args[0]))
61 else:
61 else:
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 return -1
63 return -1
64
64
65 return _runcatch(req)
65 msg = ' '.join(' ' in a and repr(a) or a for a in req.args)
66 starttime = time.time()
67 ret = None
68 try:
69 ret = _runcatch(req)
70 return ret
71 finally:
72 duration = time.time() - starttime
73 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
74 msg, ret or 0, duration)
66
75
67 def _runcatch(req):
76 def _runcatch(req):
68 def catchterm(*args):
77 def catchterm(*args):
69 raise error.SignalInterrupt
78 raise error.SignalInterrupt
70
79
71 ui = req.ui
80 ui = req.ui
72 try:
81 try:
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
82 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
74 num = getattr(signal, name, None)
83 num = getattr(signal, name, None)
75 if num:
84 if num:
76 signal.signal(num, catchterm)
85 signal.signal(num, catchterm)
77 except ValueError:
86 except ValueError:
78 pass # happens if called in a thread
87 pass # happens if called in a thread
79
88
80 try:
89 try:
81 try:
90 try:
82 # enter the debugger before command execution
91 # enter the debugger before command execution
83 if '--debugger' in req.args:
92 if '--debugger' in req.args:
84 ui.warn(_("entering debugger - "
93 ui.warn(_("entering debugger - "
85 "type c to continue starting hg or h for help\n"))
94 "type c to continue starting hg or h for help\n"))
86 pdb.set_trace()
95 pdb.set_trace()
87 try:
96 try:
88 return _dispatch(req)
97 return _dispatch(req)
89 finally:
98 finally:
90 ui.flush()
99 ui.flush()
91 except: # re-raises
100 except: # re-raises
92 # enter the debugger when we hit an exception
101 # enter the debugger when we hit an exception
93 if '--debugger' in req.args:
102 if '--debugger' in req.args:
94 traceback.print_exc()
103 traceback.print_exc()
95 pdb.post_mortem(sys.exc_info()[2])
104 pdb.post_mortem(sys.exc_info()[2])
96 ui.traceback()
105 ui.traceback()
97 raise
106 raise
98
107
99 # Global exception handling, alphabetically
108 # Global exception handling, alphabetically
100 # Mercurial-specific first, followed by built-in and library exceptions
109 # Mercurial-specific first, followed by built-in and library exceptions
101 except error.AmbiguousCommand, inst:
110 except error.AmbiguousCommand, inst:
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
111 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
103 (inst.args[0], " ".join(inst.args[1])))
112 (inst.args[0], " ".join(inst.args[1])))
104 except error.ParseError, inst:
113 except error.ParseError, inst:
105 if len(inst.args) > 1:
114 if len(inst.args) > 1:
106 ui.warn(_("hg: parse error at %s: %s\n") %
115 ui.warn(_("hg: parse error at %s: %s\n") %
107 (inst.args[1], inst.args[0]))
116 (inst.args[1], inst.args[0]))
108 else:
117 else:
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
118 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
110 return -1
119 return -1
111 except error.LockHeld, inst:
120 except error.LockHeld, inst:
112 if inst.errno == errno.ETIMEDOUT:
121 if inst.errno == errno.ETIMEDOUT:
113 reason = _('timed out waiting for lock held by %s') % inst.locker
122 reason = _('timed out waiting for lock held by %s') % inst.locker
114 else:
123 else:
115 reason = _('lock held by %s') % inst.locker
124 reason = _('lock held by %s') % inst.locker
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
125 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
117 except error.LockUnavailable, inst:
126 except error.LockUnavailable, inst:
118 ui.warn(_("abort: could not lock %s: %s\n") %
127 ui.warn(_("abort: could not lock %s: %s\n") %
119 (inst.desc or inst.filename, inst.strerror))
128 (inst.desc or inst.filename, inst.strerror))
120 except error.CommandError, inst:
129 except error.CommandError, inst:
121 if inst.args[0]:
130 if inst.args[0]:
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
131 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
123 commands.help_(ui, inst.args[0], full=False, command=True)
132 commands.help_(ui, inst.args[0], full=False, command=True)
124 else:
133 else:
125 ui.warn(_("hg: %s\n") % inst.args[1])
134 ui.warn(_("hg: %s\n") % inst.args[1])
126 commands.help_(ui, 'shortlist')
135 commands.help_(ui, 'shortlist')
127 except error.OutOfBandError, inst:
136 except error.OutOfBandError, inst:
128 ui.warn(_("abort: remote error:\n"))
137 ui.warn(_("abort: remote error:\n"))
129 ui.warn(''.join(inst.args))
138 ui.warn(''.join(inst.args))
130 except error.RepoError, inst:
139 except error.RepoError, inst:
131 ui.warn(_("abort: %s!\n") % inst)
140 ui.warn(_("abort: %s!\n") % inst)
132 if inst.hint:
141 if inst.hint:
133 ui.warn(_("(%s)\n") % inst.hint)
142 ui.warn(_("(%s)\n") % inst.hint)
134 except error.ResponseError, inst:
143 except error.ResponseError, inst:
135 ui.warn(_("abort: %s") % inst.args[0])
144 ui.warn(_("abort: %s") % inst.args[0])
136 if not isinstance(inst.args[1], basestring):
145 if not isinstance(inst.args[1], basestring):
137 ui.warn(" %r\n" % (inst.args[1],))
146 ui.warn(" %r\n" % (inst.args[1],))
138 elif not inst.args[1]:
147 elif not inst.args[1]:
139 ui.warn(_(" empty string\n"))
148 ui.warn(_(" empty string\n"))
140 else:
149 else:
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
150 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
142 except error.RevlogError, inst:
151 except error.RevlogError, inst:
143 ui.warn(_("abort: %s!\n") % inst)
152 ui.warn(_("abort: %s!\n") % inst)
144 except error.SignalInterrupt:
153 except error.SignalInterrupt:
145 ui.warn(_("killed!\n"))
154 ui.warn(_("killed!\n"))
146 except error.UnknownCommand, inst:
155 except error.UnknownCommand, inst:
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
156 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
148 try:
157 try:
149 # check if the command is in a disabled extension
158 # check if the command is in a disabled extension
150 # (but don't check for extensions themselves)
159 # (but don't check for extensions themselves)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
160 commands.help_(ui, inst.args[0], unknowncmd=True)
152 except error.UnknownCommand:
161 except error.UnknownCommand:
153 commands.help_(ui, 'shortlist')
162 commands.help_(ui, 'shortlist')
154 except error.InterventionRequired, inst:
163 except error.InterventionRequired, inst:
155 ui.warn("%s\n" % inst)
164 ui.warn("%s\n" % inst)
156 return 1
165 return 1
157 except util.Abort, inst:
166 except util.Abort, inst:
158 ui.warn(_("abort: %s\n") % inst)
167 ui.warn(_("abort: %s\n") % inst)
159 if inst.hint:
168 if inst.hint:
160 ui.warn(_("(%s)\n") % inst.hint)
169 ui.warn(_("(%s)\n") % inst.hint)
161 except ImportError, inst:
170 except ImportError, inst:
162 ui.warn(_("abort: %s!\n") % inst)
171 ui.warn(_("abort: %s!\n") % inst)
163 m = str(inst).split()[-1]
172 m = str(inst).split()[-1]
164 if m in "mpatch bdiff".split():
173 if m in "mpatch bdiff".split():
165 ui.warn(_("(did you forget to compile extensions?)\n"))
174 ui.warn(_("(did you forget to compile extensions?)\n"))
166 elif m in "zlib".split():
175 elif m in "zlib".split():
167 ui.warn(_("(is your Python install correct?)\n"))
176 ui.warn(_("(is your Python install correct?)\n"))
168 except IOError, inst:
177 except IOError, inst:
169 if util.safehasattr(inst, "code"):
178 if util.safehasattr(inst, "code"):
170 ui.warn(_("abort: %s\n") % inst)
179 ui.warn(_("abort: %s\n") % inst)
171 elif util.safehasattr(inst, "reason"):
180 elif util.safehasattr(inst, "reason"):
172 try: # usually it is in the form (errno, strerror)
181 try: # usually it is in the form (errno, strerror)
173 reason = inst.reason.args[1]
182 reason = inst.reason.args[1]
174 except (AttributeError, IndexError):
183 except (AttributeError, IndexError):
175 # it might be anything, for example a string
184 # it might be anything, for example a string
176 reason = inst.reason
185 reason = inst.reason
177 ui.warn(_("abort: error: %s\n") % reason)
186 ui.warn(_("abort: error: %s\n") % reason)
178 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
187 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
179 if ui.debugflag:
188 if ui.debugflag:
180 ui.warn(_("broken pipe\n"))
189 ui.warn(_("broken pipe\n"))
181 elif getattr(inst, "strerror", None):
190 elif getattr(inst, "strerror", None):
182 if getattr(inst, "filename", None):
191 if getattr(inst, "filename", None):
183 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
192 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
184 else:
193 else:
185 ui.warn(_("abort: %s\n") % inst.strerror)
194 ui.warn(_("abort: %s\n") % inst.strerror)
186 else:
195 else:
187 raise
196 raise
188 except OSError, inst:
197 except OSError, inst:
189 if getattr(inst, "filename", None) is not None:
198 if getattr(inst, "filename", None) is not None:
190 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
199 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
191 else:
200 else:
192 ui.warn(_("abort: %s\n") % inst.strerror)
201 ui.warn(_("abort: %s\n") % inst.strerror)
193 except KeyboardInterrupt:
202 except KeyboardInterrupt:
194 try:
203 try:
195 ui.warn(_("interrupted!\n"))
204 ui.warn(_("interrupted!\n"))
196 except IOError, inst:
205 except IOError, inst:
197 if inst.errno == errno.EPIPE:
206 if inst.errno == errno.EPIPE:
198 if ui.debugflag:
207 if ui.debugflag:
199 ui.warn(_("\nbroken pipe\n"))
208 ui.warn(_("\nbroken pipe\n"))
200 else:
209 else:
201 raise
210 raise
202 except MemoryError:
211 except MemoryError:
203 ui.warn(_("abort: out of memory\n"))
212 ui.warn(_("abort: out of memory\n"))
204 except SystemExit, inst:
213 except SystemExit, inst:
205 # Commands shouldn't sys.exit directly, but give a return code.
214 # Commands shouldn't sys.exit directly, but give a return code.
206 # Just in case catch this and and pass exit code to caller.
215 # Just in case catch this and and pass exit code to caller.
207 return inst.code
216 return inst.code
208 except socket.error, inst:
217 except socket.error, inst:
209 ui.warn(_("abort: %s\n") % inst.args[-1])
218 ui.warn(_("abort: %s\n") % inst.args[-1])
210 except: # re-raises
219 except: # re-raises
211 myver = util.version()
220 myver = util.version()
212 # For compatibility checking, we discard the portion of the hg
221 # For compatibility checking, we discard the portion of the hg
213 # version after the + on the assumption that if a "normal
222 # version after the + on the assumption that if a "normal
214 # user" is running a build with a + in it the packager
223 # user" is running a build with a + in it the packager
215 # probably built from fairly close to a tag and anyone with a
224 # probably built from fairly close to a tag and anyone with a
216 # 'make local' copy of hg (where the version number can be out
225 # 'make local' copy of hg (where the version number can be out
217 # of date) will be clueful enough to notice the implausible
226 # of date) will be clueful enough to notice the implausible
218 # version number and try updating.
227 # version number and try updating.
219 compare = myver.split('+')[0]
228 compare = myver.split('+')[0]
220 ct = tuplever(compare)
229 ct = tuplever(compare)
221 worst = None, ct, ''
230 worst = None, ct, ''
222 for name, mod in extensions.extensions():
231 for name, mod in extensions.extensions():
223 testedwith = getattr(mod, 'testedwith', '')
232 testedwith = getattr(mod, 'testedwith', '')
224 report = getattr(mod, 'buglink', _('the extension author.'))
233 report = getattr(mod, 'buglink', _('the extension author.'))
225 if not testedwith.strip():
234 if not testedwith.strip():
226 # We found an untested extension. It's likely the culprit.
235 # We found an untested extension. It's likely the culprit.
227 worst = name, 'unknown', report
236 worst = name, 'unknown', report
228 break
237 break
229 if compare not in testedwith.split() and testedwith != 'internal':
238 if compare not in testedwith.split() and testedwith != 'internal':
230 tested = [tuplever(v) for v in testedwith.split()]
239 tested = [tuplever(v) for v in testedwith.split()]
231 lower = [t for t in tested if t < ct]
240 lower = [t for t in tested if t < ct]
232 nearest = max(lower or tested)
241 nearest = max(lower or tested)
233 if worst[0] is None or nearest < worst[1]:
242 if worst[0] is None or nearest < worst[1]:
234 worst = name, nearest, report
243 worst = name, nearest, report
235 if worst[0] is not None:
244 if worst[0] is not None:
236 name, testedwith, report = worst
245 name, testedwith, report = worst
237 if not isinstance(testedwith, str):
246 if not isinstance(testedwith, str):
238 testedwith = '.'.join([str(c) for c in testedwith])
247 testedwith = '.'.join([str(c) for c in testedwith])
239 warning = (_('** Unknown exception encountered with '
248 warning = (_('** Unknown exception encountered with '
240 'possibly-broken third-party extension %s\n'
249 'possibly-broken third-party extension %s\n'
241 '** which supports versions %s of Mercurial.\n'
250 '** which supports versions %s of Mercurial.\n'
242 '** Please disable %s and try your action again.\n'
251 '** Please disable %s and try your action again.\n'
243 '** If that fixes the bug please report it to %s\n')
252 '** If that fixes the bug please report it to %s\n')
244 % (name, testedwith, name, report))
253 % (name, testedwith, name, report))
245 else:
254 else:
246 warning = (_("** unknown exception encountered, "
255 warning = (_("** unknown exception encountered, "
247 "please report by visiting\n") +
256 "please report by visiting\n") +
248 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
257 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
249 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
258 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
250 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
259 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
251 (_("** Extensions loaded: %s\n") %
260 (_("** Extensions loaded: %s\n") %
252 ", ".join([x[0] for x in extensions.extensions()])))
261 ", ".join([x[0] for x in extensions.extensions()])))
253 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
262 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
254 ui.warn(warning)
263 ui.warn(warning)
255 raise
264 raise
256
265
257 return -1
266 return -1
258
267
259 def tuplever(v):
268 def tuplever(v):
260 try:
269 try:
261 return tuple([int(i) for i in v.split('.')])
270 return tuple([int(i) for i in v.split('.')])
262 except ValueError:
271 except ValueError:
263 return tuple()
272 return tuple()
264
273
265 def aliasargs(fn, givenargs):
274 def aliasargs(fn, givenargs):
266 args = getattr(fn, 'args', [])
275 args = getattr(fn, 'args', [])
267 if args:
276 if args:
268 cmd = ' '.join(map(util.shellquote, args))
277 cmd = ' '.join(map(util.shellquote, args))
269
278
270 nums = []
279 nums = []
271 def replacer(m):
280 def replacer(m):
272 num = int(m.group(1)) - 1
281 num = int(m.group(1)) - 1
273 nums.append(num)
282 nums.append(num)
274 if num < len(givenargs):
283 if num < len(givenargs):
275 return givenargs[num]
284 return givenargs[num]
276 raise util.Abort(_('too few arguments for command alias'))
285 raise util.Abort(_('too few arguments for command alias'))
277 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
286 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
278 givenargs = [x for i, x in enumerate(givenargs)
287 givenargs = [x for i, x in enumerate(givenargs)
279 if i not in nums]
288 if i not in nums]
280 args = shlex.split(cmd)
289 args = shlex.split(cmd)
281 return args + givenargs
290 return args + givenargs
282
291
283 class cmdalias(object):
292 class cmdalias(object):
284 def __init__(self, name, definition, cmdtable):
293 def __init__(self, name, definition, cmdtable):
285 self.name = self.cmd = name
294 self.name = self.cmd = name
286 self.cmdname = ''
295 self.cmdname = ''
287 self.definition = definition
296 self.definition = definition
288 self.args = []
297 self.args = []
289 self.opts = []
298 self.opts = []
290 self.help = ''
299 self.help = ''
291 self.norepo = True
300 self.norepo = True
292 self.optionalrepo = False
301 self.optionalrepo = False
293 self.badalias = False
302 self.badalias = False
294
303
295 try:
304 try:
296 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
305 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
297 for alias, e in cmdtable.iteritems():
306 for alias, e in cmdtable.iteritems():
298 if e is entry:
307 if e is entry:
299 self.cmd = alias
308 self.cmd = alias
300 break
309 break
301 self.shadows = True
310 self.shadows = True
302 except error.UnknownCommand:
311 except error.UnknownCommand:
303 self.shadows = False
312 self.shadows = False
304
313
305 if not self.definition:
314 if not self.definition:
306 def fn(ui, *args):
315 def fn(ui, *args):
307 ui.warn(_("no definition for alias '%s'\n") % self.name)
316 ui.warn(_("no definition for alias '%s'\n") % self.name)
308 return 1
317 return 1
309 self.fn = fn
318 self.fn = fn
310 self.badalias = True
319 self.badalias = True
311 return
320 return
312
321
313 if self.definition.startswith('!'):
322 if self.definition.startswith('!'):
314 self.shell = True
323 self.shell = True
315 def fn(ui, *args):
324 def fn(ui, *args):
316 env = {'HG_ARGS': ' '.join((self.name,) + args)}
325 env = {'HG_ARGS': ' '.join((self.name,) + args)}
317 def _checkvar(m):
326 def _checkvar(m):
318 if m.groups()[0] == '$':
327 if m.groups()[0] == '$':
319 return m.group()
328 return m.group()
320 elif int(m.groups()[0]) <= len(args):
329 elif int(m.groups()[0]) <= len(args):
321 return m.group()
330 return m.group()
322 else:
331 else:
323 ui.debug("No argument found for substitution "
332 ui.debug("No argument found for substitution "
324 "of %i variable in alias '%s' definition."
333 "of %i variable in alias '%s' definition."
325 % (int(m.groups()[0]), self.name))
334 % (int(m.groups()[0]), self.name))
326 return ''
335 return ''
327 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
336 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
328 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
337 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
329 replace['0'] = self.name
338 replace['0'] = self.name
330 replace['@'] = ' '.join(args)
339 replace['@'] = ' '.join(args)
331 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
340 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
332 return util.system(cmd, environ=env, out=ui.fout)
341 return util.system(cmd, environ=env, out=ui.fout)
333 self.fn = fn
342 self.fn = fn
334 return
343 return
335
344
336 args = shlex.split(self.definition)
345 args = shlex.split(self.definition)
337 self.cmdname = cmd = args.pop(0)
346 self.cmdname = cmd = args.pop(0)
338 args = map(util.expandpath, args)
347 args = map(util.expandpath, args)
339
348
340 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
349 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
341 if _earlygetopt([invalidarg], args):
350 if _earlygetopt([invalidarg], args):
342 def fn(ui, *args):
351 def fn(ui, *args):
343 ui.warn(_("error in definition for alias '%s': %s may only "
352 ui.warn(_("error in definition for alias '%s': %s may only "
344 "be given on the command line\n")
353 "be given on the command line\n")
345 % (self.name, invalidarg))
354 % (self.name, invalidarg))
346 return 1
355 return 1
347
356
348 self.fn = fn
357 self.fn = fn
349 self.badalias = True
358 self.badalias = True
350 return
359 return
351
360
352 try:
361 try:
353 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
362 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
354 if len(tableentry) > 2:
363 if len(tableentry) > 2:
355 self.fn, self.opts, self.help = tableentry
364 self.fn, self.opts, self.help = tableentry
356 else:
365 else:
357 self.fn, self.opts = tableentry
366 self.fn, self.opts = tableentry
358
367
359 self.args = aliasargs(self.fn, args)
368 self.args = aliasargs(self.fn, args)
360 if cmd not in commands.norepo.split(' '):
369 if cmd not in commands.norepo.split(' '):
361 self.norepo = False
370 self.norepo = False
362 if cmd in commands.optionalrepo.split(' '):
371 if cmd in commands.optionalrepo.split(' '):
363 self.optionalrepo = True
372 self.optionalrepo = True
364 if self.help.startswith("hg " + cmd):
373 if self.help.startswith("hg " + cmd):
365 # drop prefix in old-style help lines so hg shows the alias
374 # drop prefix in old-style help lines so hg shows the alias
366 self.help = self.help[4 + len(cmd):]
375 self.help = self.help[4 + len(cmd):]
367 self.__doc__ = self.fn.__doc__
376 self.__doc__ = self.fn.__doc__
368
377
369 except error.UnknownCommand:
378 except error.UnknownCommand:
370 def fn(ui, *args):
379 def fn(ui, *args):
371 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
380 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
372 % (self.name, cmd))
381 % (self.name, cmd))
373 try:
382 try:
374 # check if the command is in a disabled extension
383 # check if the command is in a disabled extension
375 commands.help_(ui, cmd, unknowncmd=True)
384 commands.help_(ui, cmd, unknowncmd=True)
376 except error.UnknownCommand:
385 except error.UnknownCommand:
377 pass
386 pass
378 return 1
387 return 1
379 self.fn = fn
388 self.fn = fn
380 self.badalias = True
389 self.badalias = True
381 except error.AmbiguousCommand:
390 except error.AmbiguousCommand:
382 def fn(ui, *args):
391 def fn(ui, *args):
383 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
392 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
384 % (self.name, cmd))
393 % (self.name, cmd))
385 return 1
394 return 1
386 self.fn = fn
395 self.fn = fn
387 self.badalias = True
396 self.badalias = True
388
397
389 def __call__(self, ui, *args, **opts):
398 def __call__(self, ui, *args, **opts):
390 if self.shadows:
399 if self.shadows:
391 ui.debug("alias '%s' shadows command '%s'\n" %
400 ui.debug("alias '%s' shadows command '%s'\n" %
392 (self.name, self.cmdname))
401 (self.name, self.cmdname))
393
402
394 if util.safehasattr(self, 'shell'):
403 if util.safehasattr(self, 'shell'):
395 return self.fn(ui, *args, **opts)
404 return self.fn(ui, *args, **opts)
396 else:
405 else:
397 try:
406 try:
398 util.checksignature(self.fn)(ui, *args, **opts)
407 util.checksignature(self.fn)(ui, *args, **opts)
399 except error.SignatureError:
408 except error.SignatureError:
400 args = ' '.join([self.cmdname] + self.args)
409 args = ' '.join([self.cmdname] + self.args)
401 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
410 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
402 raise
411 raise
403
412
404 def addaliases(ui, cmdtable):
413 def addaliases(ui, cmdtable):
405 # aliases are processed after extensions have been loaded, so they
414 # aliases are processed after extensions have been loaded, so they
406 # may use extension commands. Aliases can also use other alias definitions,
415 # may use extension commands. Aliases can also use other alias definitions,
407 # but only if they have been defined prior to the current definition.
416 # but only if they have been defined prior to the current definition.
408 for alias, definition in ui.configitems('alias'):
417 for alias, definition in ui.configitems('alias'):
409 aliasdef = cmdalias(alias, definition, cmdtable)
418 aliasdef = cmdalias(alias, definition, cmdtable)
410
419
411 try:
420 try:
412 olddef = cmdtable[aliasdef.cmd][0]
421 olddef = cmdtable[aliasdef.cmd][0]
413 if olddef.definition == aliasdef.definition:
422 if olddef.definition == aliasdef.definition:
414 continue
423 continue
415 except (KeyError, AttributeError):
424 except (KeyError, AttributeError):
416 # definition might not exist or it might not be a cmdalias
425 # definition might not exist or it might not be a cmdalias
417 pass
426 pass
418
427
419 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
428 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
420 if aliasdef.norepo:
429 if aliasdef.norepo:
421 commands.norepo += ' %s' % alias
430 commands.norepo += ' %s' % alias
422 if aliasdef.optionalrepo:
431 if aliasdef.optionalrepo:
423 commands.optionalrepo += ' %s' % alias
432 commands.optionalrepo += ' %s' % alias
424
433
425 def _parse(ui, args):
434 def _parse(ui, args):
426 options = {}
435 options = {}
427 cmdoptions = {}
436 cmdoptions = {}
428
437
429 try:
438 try:
430 args = fancyopts.fancyopts(args, commands.globalopts, options)
439 args = fancyopts.fancyopts(args, commands.globalopts, options)
431 except fancyopts.getopt.GetoptError, inst:
440 except fancyopts.getopt.GetoptError, inst:
432 raise error.CommandError(None, inst)
441 raise error.CommandError(None, inst)
433
442
434 if args:
443 if args:
435 cmd, args = args[0], args[1:]
444 cmd, args = args[0], args[1:]
436 aliases, entry = cmdutil.findcmd(cmd, commands.table,
445 aliases, entry = cmdutil.findcmd(cmd, commands.table,
437 ui.configbool("ui", "strict"))
446 ui.configbool("ui", "strict"))
438 cmd = aliases[0]
447 cmd = aliases[0]
439 args = aliasargs(entry[0], args)
448 args = aliasargs(entry[0], args)
440 defaults = ui.config("defaults", cmd)
449 defaults = ui.config("defaults", cmd)
441 if defaults:
450 if defaults:
442 args = map(util.expandpath, shlex.split(defaults)) + args
451 args = map(util.expandpath, shlex.split(defaults)) + args
443 c = list(entry[1])
452 c = list(entry[1])
444 else:
453 else:
445 cmd = None
454 cmd = None
446 c = []
455 c = []
447
456
448 # combine global options into local
457 # combine global options into local
449 for o in commands.globalopts:
458 for o in commands.globalopts:
450 c.append((o[0], o[1], options[o[1]], o[3]))
459 c.append((o[0], o[1], options[o[1]], o[3]))
451
460
452 try:
461 try:
453 args = fancyopts.fancyopts(args, c, cmdoptions, True)
462 args = fancyopts.fancyopts(args, c, cmdoptions, True)
454 except fancyopts.getopt.GetoptError, inst:
463 except fancyopts.getopt.GetoptError, inst:
455 raise error.CommandError(cmd, inst)
464 raise error.CommandError(cmd, inst)
456
465
457 # separate global options back out
466 # separate global options back out
458 for o in commands.globalopts:
467 for o in commands.globalopts:
459 n = o[1]
468 n = o[1]
460 options[n] = cmdoptions[n]
469 options[n] = cmdoptions[n]
461 del cmdoptions[n]
470 del cmdoptions[n]
462
471
463 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
472 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
464
473
465 def _parseconfig(ui, config):
474 def _parseconfig(ui, config):
466 """parse the --config options from the command line"""
475 """parse the --config options from the command line"""
467 configs = []
476 configs = []
468
477
469 for cfg in config:
478 for cfg in config:
470 try:
479 try:
471 name, value = cfg.split('=', 1)
480 name, value = cfg.split('=', 1)
472 section, name = name.split('.', 1)
481 section, name = name.split('.', 1)
473 if not section or not name:
482 if not section or not name:
474 raise IndexError
483 raise IndexError
475 ui.setconfig(section, name, value)
484 ui.setconfig(section, name, value)
476 configs.append((section, name, value))
485 configs.append((section, name, value))
477 except (IndexError, ValueError):
486 except (IndexError, ValueError):
478 raise util.Abort(_('malformed --config option: %r '
487 raise util.Abort(_('malformed --config option: %r '
479 '(use --config section.name=value)') % cfg)
488 '(use --config section.name=value)') % cfg)
480
489
481 return configs
490 return configs
482
491
483 def _earlygetopt(aliases, args):
492 def _earlygetopt(aliases, args):
484 """Return list of values for an option (or aliases).
493 """Return list of values for an option (or aliases).
485
494
486 The values are listed in the order they appear in args.
495 The values are listed in the order they appear in args.
487 The options and values are removed from args.
496 The options and values are removed from args.
488
497
489 >>> args = ['x', '--cwd', 'foo', 'y']
498 >>> args = ['x', '--cwd', 'foo', 'y']
490 >>> _earlygetopt(['--cwd'], args), args
499 >>> _earlygetopt(['--cwd'], args), args
491 (['foo'], ['x', 'y'])
500 (['foo'], ['x', 'y'])
492
501
493 >>> args = ['x', '--cwd=bar', 'y']
502 >>> args = ['x', '--cwd=bar', 'y']
494 >>> _earlygetopt(['--cwd'], args), args
503 >>> _earlygetopt(['--cwd'], args), args
495 (['bar'], ['x', 'y'])
504 (['bar'], ['x', 'y'])
496
505
497 >>> args = ['x', '-R', 'foo', 'y']
506 >>> args = ['x', '-R', 'foo', 'y']
498 >>> _earlygetopt(['-R'], args), args
507 >>> _earlygetopt(['-R'], args), args
499 (['foo'], ['x', 'y'])
508 (['foo'], ['x', 'y'])
500
509
501 >>> args = ['x', '-Rbar', 'y']
510 >>> args = ['x', '-Rbar', 'y']
502 >>> _earlygetopt(['-R'], args), args
511 >>> _earlygetopt(['-R'], args), args
503 (['bar'], ['x', 'y'])
512 (['bar'], ['x', 'y'])
504 """
513 """
505 try:
514 try:
506 argcount = args.index("--")
515 argcount = args.index("--")
507 except ValueError:
516 except ValueError:
508 argcount = len(args)
517 argcount = len(args)
509 shortopts = [opt for opt in aliases if len(opt) == 2]
518 shortopts = [opt for opt in aliases if len(opt) == 2]
510 values = []
519 values = []
511 pos = 0
520 pos = 0
512 while pos < argcount:
521 while pos < argcount:
513 fullarg = arg = args[pos]
522 fullarg = arg = args[pos]
514 equals = arg.find('=')
523 equals = arg.find('=')
515 if equals > -1:
524 if equals > -1:
516 arg = arg[:equals]
525 arg = arg[:equals]
517 if arg in aliases:
526 if arg in aliases:
518 del args[pos]
527 del args[pos]
519 if equals > -1:
528 if equals > -1:
520 values.append(fullarg[equals + 1:])
529 values.append(fullarg[equals + 1:])
521 argcount -= 1
530 argcount -= 1
522 else:
531 else:
523 if pos + 1 >= argcount:
532 if pos + 1 >= argcount:
524 # ignore and let getopt report an error if there is no value
533 # ignore and let getopt report an error if there is no value
525 break
534 break
526 values.append(args.pop(pos))
535 values.append(args.pop(pos))
527 argcount -= 2
536 argcount -= 2
528 elif arg[:2] in shortopts:
537 elif arg[:2] in shortopts:
529 # short option can have no following space, e.g. hg log -Rfoo
538 # short option can have no following space, e.g. hg log -Rfoo
530 values.append(args.pop(pos)[2:])
539 values.append(args.pop(pos)[2:])
531 argcount -= 1
540 argcount -= 1
532 else:
541 else:
533 pos += 1
542 pos += 1
534 return values
543 return values
535
544
536 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
545 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
537 # run pre-hook, and abort if it fails
546 # run pre-hook, and abort if it fails
538 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
547 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
539 pats=cmdpats, opts=cmdoptions)
548 pats=cmdpats, opts=cmdoptions)
540 ret = _runcommand(ui, options, cmd, d)
549 ret = _runcommand(ui, options, cmd, d)
541 # run post-hook, passing command result
550 # run post-hook, passing command result
542 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
551 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
543 result=ret, pats=cmdpats, opts=cmdoptions)
552 result=ret, pats=cmdpats, opts=cmdoptions)
544 return ret
553 return ret
545
554
546 def _getlocal(ui, rpath):
555 def _getlocal(ui, rpath):
547 """Return (path, local ui object) for the given target path.
556 """Return (path, local ui object) for the given target path.
548
557
549 Takes paths in [cwd]/.hg/hgrc into account."
558 Takes paths in [cwd]/.hg/hgrc into account."
550 """
559 """
551 try:
560 try:
552 wd = os.getcwd()
561 wd = os.getcwd()
553 except OSError, e:
562 except OSError, e:
554 raise util.Abort(_("error getting current working directory: %s") %
563 raise util.Abort(_("error getting current working directory: %s") %
555 e.strerror)
564 e.strerror)
556 path = cmdutil.findrepo(wd) or ""
565 path = cmdutil.findrepo(wd) or ""
557 if not path:
566 if not path:
558 lui = ui
567 lui = ui
559 else:
568 else:
560 lui = ui.copy()
569 lui = ui.copy()
561 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
570 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
562
571
563 if rpath and rpath[-1]:
572 if rpath and rpath[-1]:
564 path = lui.expandpath(rpath[-1])
573 path = lui.expandpath(rpath[-1])
565 lui = ui.copy()
574 lui = ui.copy()
566 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
575 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
567
576
568 return path, lui
577 return path, lui
569
578
570 def _checkshellalias(lui, ui, args):
579 def _checkshellalias(lui, ui, args):
571 options = {}
580 options = {}
572
581
573 try:
582 try:
574 args = fancyopts.fancyopts(args, commands.globalopts, options)
583 args = fancyopts.fancyopts(args, commands.globalopts, options)
575 except fancyopts.getopt.GetoptError:
584 except fancyopts.getopt.GetoptError:
576 return
585 return
577
586
578 if not args:
587 if not args:
579 return
588 return
580
589
581 norepo = commands.norepo
590 norepo = commands.norepo
582 optionalrepo = commands.optionalrepo
591 optionalrepo = commands.optionalrepo
583 def restorecommands():
592 def restorecommands():
584 commands.norepo = norepo
593 commands.norepo = norepo
585 commands.optionalrepo = optionalrepo
594 commands.optionalrepo = optionalrepo
586
595
587 cmdtable = commands.table.copy()
596 cmdtable = commands.table.copy()
588 addaliases(lui, cmdtable)
597 addaliases(lui, cmdtable)
589
598
590 cmd = args[0]
599 cmd = args[0]
591 try:
600 try:
592 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
601 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
593 lui.configbool("ui", "strict"))
602 lui.configbool("ui", "strict"))
594 except (error.AmbiguousCommand, error.UnknownCommand):
603 except (error.AmbiguousCommand, error.UnknownCommand):
595 restorecommands()
604 restorecommands()
596 return
605 return
597
606
598 cmd = aliases[0]
607 cmd = aliases[0]
599 fn = entry[0]
608 fn = entry[0]
600
609
601 if cmd and util.safehasattr(fn, 'shell'):
610 if cmd and util.safehasattr(fn, 'shell'):
602 d = lambda: fn(ui, *args[1:])
611 d = lambda: fn(ui, *args[1:])
603 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
612 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
604 [], {})
613 [], {})
605
614
606 restorecommands()
615 restorecommands()
607
616
608 _loaded = set()
617 _loaded = set()
609 def _dispatch(req):
618 def _dispatch(req):
610 args = req.args
619 args = req.args
611 ui = req.ui
620 ui = req.ui
612
621
613 # read --config before doing anything else
622 # read --config before doing anything else
614 # (e.g. to change trust settings for reading .hg/hgrc)
623 # (e.g. to change trust settings for reading .hg/hgrc)
615 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
624 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
616
625
617 # check for cwd
626 # check for cwd
618 cwd = _earlygetopt(['--cwd'], args)
627 cwd = _earlygetopt(['--cwd'], args)
619 if cwd:
628 if cwd:
620 os.chdir(cwd[-1])
629 os.chdir(cwd[-1])
621
630
622 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
631 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
623 path, lui = _getlocal(ui, rpath)
632 path, lui = _getlocal(ui, rpath)
624
633
625 # Now that we're operating in the right directory/repository with
634 # Now that we're operating in the right directory/repository with
626 # the right config settings, check for shell aliases
635 # the right config settings, check for shell aliases
627 shellaliasfn = _checkshellalias(lui, ui, args)
636 shellaliasfn = _checkshellalias(lui, ui, args)
628 if shellaliasfn:
637 if shellaliasfn:
629 return shellaliasfn()
638 return shellaliasfn()
630
639
631 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
640 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
632 # reposetup. Programs like TortoiseHg will call _dispatch several
641 # reposetup. Programs like TortoiseHg will call _dispatch several
633 # times so we keep track of configured extensions in _loaded.
642 # times so we keep track of configured extensions in _loaded.
634 extensions.loadall(lui)
643 extensions.loadall(lui)
635 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
644 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
636 # Propagate any changes to lui.__class__ by extensions
645 # Propagate any changes to lui.__class__ by extensions
637 ui.__class__ = lui.__class__
646 ui.__class__ = lui.__class__
638
647
639 # (uisetup and extsetup are handled in extensions.loadall)
648 # (uisetup and extsetup are handled in extensions.loadall)
640
649
641 for name, module in exts:
650 for name, module in exts:
642 cmdtable = getattr(module, 'cmdtable', {})
651 cmdtable = getattr(module, 'cmdtable', {})
643 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
652 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
644 if overrides:
653 if overrides:
645 ui.warn(_("extension '%s' overrides commands: %s\n")
654 ui.warn(_("extension '%s' overrides commands: %s\n")
646 % (name, " ".join(overrides)))
655 % (name, " ".join(overrides)))
647 commands.table.update(cmdtable)
656 commands.table.update(cmdtable)
648 _loaded.add(name)
657 _loaded.add(name)
649
658
650 # (reposetup is handled in hg.repository)
659 # (reposetup is handled in hg.repository)
651
660
652 addaliases(lui, commands.table)
661 addaliases(lui, commands.table)
653
662
654 # check for fallback encoding
663 # check for fallback encoding
655 fallback = lui.config('ui', 'fallbackencoding')
664 fallback = lui.config('ui', 'fallbackencoding')
656 if fallback:
665 if fallback:
657 encoding.fallbackencoding = fallback
666 encoding.fallbackencoding = fallback
658
667
659 fullargs = args
668 fullargs = args
660 cmd, func, args, options, cmdoptions = _parse(lui, args)
669 cmd, func, args, options, cmdoptions = _parse(lui, args)
661
670
662 if options["config"]:
671 if options["config"]:
663 raise util.Abort(_("option --config may not be abbreviated!"))
672 raise util.Abort(_("option --config may not be abbreviated!"))
664 if options["cwd"]:
673 if options["cwd"]:
665 raise util.Abort(_("option --cwd may not be abbreviated!"))
674 raise util.Abort(_("option --cwd may not be abbreviated!"))
666 if options["repository"]:
675 if options["repository"]:
667 raise util.Abort(_(
676 raise util.Abort(_(
668 "option -R has to be separated from other options (e.g. not -qR) "
677 "option -R has to be separated from other options (e.g. not -qR) "
669 "and --repository may only be abbreviated as --repo!"))
678 "and --repository may only be abbreviated as --repo!"))
670
679
671 if options["encoding"]:
680 if options["encoding"]:
672 encoding.encoding = options["encoding"]
681 encoding.encoding = options["encoding"]
673 if options["encodingmode"]:
682 if options["encodingmode"]:
674 encoding.encodingmode = options["encodingmode"]
683 encoding.encodingmode = options["encodingmode"]
675 if options["time"]:
684 if options["time"]:
676 def get_times():
685 def get_times():
677 t = os.times()
686 t = os.times()
678 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
687 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
679 t = (t[0], t[1], t[2], t[3], time.clock())
688 t = (t[0], t[1], t[2], t[3], time.clock())
680 return t
689 return t
681 s = get_times()
690 s = get_times()
682 def print_time():
691 def print_time():
683 t = get_times()
692 t = get_times()
684 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
693 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
685 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
694 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
686 atexit.register(print_time)
695 atexit.register(print_time)
687
696
688 uis = set([ui, lui])
697 uis = set([ui, lui])
689
698
690 if req.repo:
699 if req.repo:
691 uis.add(req.repo.ui)
700 uis.add(req.repo.ui)
692
701
693 # copy configs that were passed on the cmdline (--config) to the repo ui
702 # copy configs that were passed on the cmdline (--config) to the repo ui
694 for cfg in cfgs:
703 for cfg in cfgs:
695 req.repo.ui.setconfig(*cfg)
704 req.repo.ui.setconfig(*cfg)
696
705
697 if options['verbose'] or options['debug'] or options['quiet']:
706 if options['verbose'] or options['debug'] or options['quiet']:
698 for opt in ('verbose', 'debug', 'quiet'):
707 for opt in ('verbose', 'debug', 'quiet'):
699 val = str(bool(options[opt]))
708 val = str(bool(options[opt]))
700 for ui_ in uis:
709 for ui_ in uis:
701 ui_.setconfig('ui', opt, val)
710 ui_.setconfig('ui', opt, val)
702
711
703 if options['traceback']:
712 if options['traceback']:
704 for ui_ in uis:
713 for ui_ in uis:
705 ui_.setconfig('ui', 'traceback', 'on')
714 ui_.setconfig('ui', 'traceback', 'on')
706
715
707 if options['noninteractive']:
716 if options['noninteractive']:
708 for ui_ in uis:
717 for ui_ in uis:
709 ui_.setconfig('ui', 'interactive', 'off')
718 ui_.setconfig('ui', 'interactive', 'off')
710
719
711 if cmdoptions.get('insecure', False):
720 if cmdoptions.get('insecure', False):
712 for ui_ in uis:
721 for ui_ in uis:
713 ui_.setconfig('web', 'cacerts', '')
722 ui_.setconfig('web', 'cacerts', '')
714
723
715 if options['version']:
724 if options['version']:
716 return commands.version_(ui)
725 return commands.version_(ui)
717 if options['help']:
726 if options['help']:
718 return commands.help_(ui, cmd)
727 return commands.help_(ui, cmd)
719 elif not cmd:
728 elif not cmd:
720 return commands.help_(ui, 'shortlist')
729 return commands.help_(ui, 'shortlist')
721
730
722 repo = None
731 repo = None
723 cmdpats = args[:]
732 cmdpats = args[:]
724 if cmd not in commands.norepo.split():
733 if cmd not in commands.norepo.split():
725 # use the repo from the request only if we don't have -R
734 # use the repo from the request only if we don't have -R
726 if not rpath and not cwd:
735 if not rpath and not cwd:
727 repo = req.repo
736 repo = req.repo
728
737
729 if repo:
738 if repo:
730 # set the descriptors of the repo ui to those of ui
739 # set the descriptors of the repo ui to those of ui
731 repo.ui.fin = ui.fin
740 repo.ui.fin = ui.fin
732 repo.ui.fout = ui.fout
741 repo.ui.fout = ui.fout
733 repo.ui.ferr = ui.ferr
742 repo.ui.ferr = ui.ferr
734 else:
743 else:
735 try:
744 try:
736 repo = hg.repository(ui, path=path)
745 repo = hg.repository(ui, path=path)
737 if not repo.local():
746 if not repo.local():
738 raise util.Abort(_("repository '%s' is not local") % path)
747 raise util.Abort(_("repository '%s' is not local") % path)
739 if options['hidden']:
748 if options['hidden']:
740 repo = repo.unfiltered()
749 repo = repo.unfiltered()
741 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
750 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
742 except error.RequirementError:
751 except error.RequirementError:
743 raise
752 raise
744 except error.RepoError:
753 except error.RepoError:
745 if cmd not in commands.optionalrepo.split():
754 if cmd not in commands.optionalrepo.split():
746 if (cmd in commands.inferrepo.split() and
755 if (cmd in commands.inferrepo.split() and
747 args and not path): # try to infer -R from command args
756 args and not path): # try to infer -R from command args
748 repos = map(cmdutil.findrepo, args)
757 repos = map(cmdutil.findrepo, args)
749 guess = repos[0]
758 guess = repos[0]
750 if guess and repos.count(guess) == len(repos):
759 if guess and repos.count(guess) == len(repos):
751 req.args = ['--repository', guess] + fullargs
760 req.args = ['--repository', guess] + fullargs
752 return _dispatch(req)
761 return _dispatch(req)
753 if not path:
762 if not path:
754 raise error.RepoError(_("no repository found in '%s'"
763 raise error.RepoError(_("no repository found in '%s'"
755 " (.hg not found)")
764 " (.hg not found)")
756 % os.getcwd())
765 % os.getcwd())
757 raise
766 raise
758 if repo:
767 if repo:
759 ui = repo.ui
768 ui = repo.ui
760 args.insert(0, repo)
769 args.insert(0, repo)
761 elif rpath:
770 elif rpath:
762 ui.warn(_("warning: --repository ignored\n"))
771 ui.warn(_("warning: --repository ignored\n"))
763
772
764 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
773 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
765 ui.log("command", '%s\n', msg)
774 ui.log("command", '%s\n', msg)
766 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
775 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
767 starttime = time.time()
768 ret = None
769 try:
776 try:
770 ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
777 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
771 cmdpats, cmdoptions)
778 cmdpats, cmdoptions)
772 return ret
773 finally:
779 finally:
774 duration = time.time() - starttime
775 ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
776 cmd, ret, duration)
777 if repo and repo != req.repo:
780 if repo and repo != req.repo:
778 repo.close()
781 repo.close()
779
782
780 def lsprofile(ui, func, fp):
783 def lsprofile(ui, func, fp):
781 format = ui.config('profiling', 'format', default='text')
784 format = ui.config('profiling', 'format', default='text')
782 field = ui.config('profiling', 'sort', default='inlinetime')
785 field = ui.config('profiling', 'sort', default='inlinetime')
783 limit = ui.configint('profiling', 'limit', default=30)
786 limit = ui.configint('profiling', 'limit', default=30)
784 climit = ui.configint('profiling', 'nested', default=5)
787 climit = ui.configint('profiling', 'nested', default=5)
785
788
786 if format not in ['text', 'kcachegrind']:
789 if format not in ['text', 'kcachegrind']:
787 ui.warn(_("unrecognized profiling format '%s'"
790 ui.warn(_("unrecognized profiling format '%s'"
788 " - Ignored\n") % format)
791 " - Ignored\n") % format)
789 format = 'text'
792 format = 'text'
790
793
791 try:
794 try:
792 from mercurial import lsprof
795 from mercurial import lsprof
793 except ImportError:
796 except ImportError:
794 raise util.Abort(_(
797 raise util.Abort(_(
795 'lsprof not available - install from '
798 'lsprof not available - install from '
796 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
799 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
797 p = lsprof.Profiler()
800 p = lsprof.Profiler()
798 p.enable(subcalls=True)
801 p.enable(subcalls=True)
799 try:
802 try:
800 return func()
803 return func()
801 finally:
804 finally:
802 p.disable()
805 p.disable()
803
806
804 if format == 'kcachegrind':
807 if format == 'kcachegrind':
805 import lsprofcalltree
808 import lsprofcalltree
806 calltree = lsprofcalltree.KCacheGrind(p)
809 calltree = lsprofcalltree.KCacheGrind(p)
807 calltree.output(fp)
810 calltree.output(fp)
808 else:
811 else:
809 # format == 'text'
812 # format == 'text'
810 stats = lsprof.Stats(p.getstats())
813 stats = lsprof.Stats(p.getstats())
811 stats.sort(field)
814 stats.sort(field)
812 stats.pprint(limit=limit, file=fp, climit=climit)
815 stats.pprint(limit=limit, file=fp, climit=climit)
813
816
814 def statprofile(ui, func, fp):
817 def statprofile(ui, func, fp):
815 try:
818 try:
816 import statprof
819 import statprof
817 except ImportError:
820 except ImportError:
818 raise util.Abort(_(
821 raise util.Abort(_(
819 'statprof not available - install using "easy_install statprof"'))
822 'statprof not available - install using "easy_install statprof"'))
820
823
821 freq = ui.configint('profiling', 'freq', default=1000)
824 freq = ui.configint('profiling', 'freq', default=1000)
822 if freq > 0:
825 if freq > 0:
823 statprof.reset(freq)
826 statprof.reset(freq)
824 else:
827 else:
825 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
828 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
826
829
827 statprof.start()
830 statprof.start()
828 try:
831 try:
829 return func()
832 return func()
830 finally:
833 finally:
831 statprof.stop()
834 statprof.stop()
832 statprof.display(fp)
835 statprof.display(fp)
833
836
834 def _runcommand(ui, options, cmd, cmdfunc):
837 def _runcommand(ui, options, cmd, cmdfunc):
835 def checkargs():
838 def checkargs():
836 try:
839 try:
837 return cmdfunc()
840 return cmdfunc()
838 except error.SignatureError:
841 except error.SignatureError:
839 raise error.CommandError(cmd, _("invalid arguments"))
842 raise error.CommandError(cmd, _("invalid arguments"))
840
843
841 if options['profile']:
844 if options['profile']:
842 profiler = os.getenv('HGPROF')
845 profiler = os.getenv('HGPROF')
843 if profiler is None:
846 if profiler is None:
844 profiler = ui.config('profiling', 'type', default='ls')
847 profiler = ui.config('profiling', 'type', default='ls')
845 if profiler not in ('ls', 'stat'):
848 if profiler not in ('ls', 'stat'):
846 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
849 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
847 profiler = 'ls'
850 profiler = 'ls'
848
851
849 output = ui.config('profiling', 'output')
852 output = ui.config('profiling', 'output')
850
853
851 if output:
854 if output:
852 path = ui.expandpath(output)
855 path = ui.expandpath(output)
853 fp = open(path, 'wb')
856 fp = open(path, 'wb')
854 else:
857 else:
855 fp = sys.stderr
858 fp = sys.stderr
856
859
857 try:
860 try:
858 if profiler == 'ls':
861 if profiler == 'ls':
859 return lsprofile(ui, checkargs, fp)
862 return lsprofile(ui, checkargs, fp)
860 else:
863 else:
861 return statprofile(ui, checkargs, fp)
864 return statprofile(ui, checkargs, fp)
862 finally:
865 finally:
863 if output:
866 if output:
864 fp.close()
867 fp.close()
865 else:
868 else:
866 return checkargs()
869 return checkargs()
@@ -1,154 +1,154 b''
1 setup
1 setup
2 $ cat > mock.py <<EOF
2 $ cat > mock.py <<EOF
3 > from mercurial import util
3 > from mercurial import util
4 >
4 >
5 > def makedate():
5 > def makedate():
6 > return 0, 0
6 > return 0, 0
7 > def getuser():
7 > def getuser():
8 > return 'bob'
8 > return 'bob'
9 > # mock the date and user apis so the output is always the same
9 > # mock the date and user apis so the output is always the same
10 > def uisetup(ui):
10 > def uisetup(ui):
11 > util.makedate = makedate
11 > util.makedate = makedate
12 > util.getuser = getuser
12 > util.getuser = getuser
13 > EOF
13 > EOF
14 $ cat >> $HGRCPATH <<EOF
14 $ cat >> $HGRCPATH <<EOF
15 > [extensions]
15 > [extensions]
16 > blackbox=
16 > blackbox=
17 > mock=`pwd`/mock.py
17 > mock=`pwd`/mock.py
18 > mq=
18 > mq=
19 > EOF
19 > EOF
20 $ hg init blackboxtest
20 $ hg init blackboxtest
21 $ cd blackboxtest
21 $ cd blackboxtest
22
22
23 command, exit codes, and duration
23 command, exit codes, and duration
24
24
25 $ echo a > a
25 $ echo a > a
26 $ hg add a
26 $ hg add a
27 $ hg blackbox
27 $ hg blackbox
28 1970/01/01 00:00:00 bob> add a
28 1970/01/01 00:00:00 bob> add a
29 1970/01/01 00:00:00 bob> add exited 0 after * seconds (glob)
29 1970/01/01 00:00:00 bob> add a exited 0 after * seconds (glob)
30
30
31 incoming change tracking
31 incoming change tracking
32
32
33 create two heads to verify that we only see one change in the log later
33 create two heads to verify that we only see one change in the log later
34 $ hg commit -ma
34 $ hg commit -ma
35 $ hg up null
35 $ hg up null
36 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
36 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
37 $ echo b > b
37 $ echo b > b
38 $ hg commit -Amb
38 $ hg commit -Amb
39 adding b
39 adding b
40 created new head
40 created new head
41
41
42 clone, commit, pull
42 clone, commit, pull
43 $ hg clone . ../blackboxtest2
43 $ hg clone . ../blackboxtest2
44 updating to branch default
44 updating to branch default
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 $ echo c > c
46 $ echo c > c
47 $ hg commit -Amc
47 $ hg commit -Amc
48 adding c
48 adding c
49 $ cd ../blackboxtest2
49 $ cd ../blackboxtest2
50 $ hg pull
50 $ hg pull
51 pulling from $TESTTMP/blackboxtest (glob)
51 pulling from $TESTTMP/blackboxtest (glob)
52 searching for changes
52 searching for changes
53 adding changesets
53 adding changesets
54 adding manifests
54 adding manifests
55 adding file changes
55 adding file changes
56 added 1 changesets with 1 changes to 1 files
56 added 1 changesets with 1 changes to 1 files
57 (run 'hg update' to get a working copy)
57 (run 'hg update' to get a working copy)
58 $ hg blackbox -l 3
58 $ hg blackbox -l 3
59 1970/01/01 00:00:00 bob> pull
59 1970/01/01 00:00:00 bob> pull
60 1970/01/01 00:00:00 bob> 1 incoming changes - new heads: d02f48003e62
60 1970/01/01 00:00:00 bob> 1 incoming changes - new heads: d02f48003e62
61 1970/01/01 00:00:00 bob> pull exited None after * seconds (glob)
61 1970/01/01 00:00:00 bob> pull exited 0 after * seconds (glob)
62
62
63 we must not cause a failure if we cannot write to the log
63 we must not cause a failure if we cannot write to the log
64
64
65 $ hg rollback
65 $ hg rollback
66 repository tip rolled back to revision 1 (undo pull)
66 repository tip rolled back to revision 1 (undo pull)
67
67
68 #if unix-permissions
68 #if unix-permissions
69 $ chmod 000 .hg/blackbox.log
69 $ chmod 000 .hg/blackbox.log
70 $ hg --debug incoming
70 $ hg --debug incoming
71 warning: cannot write to blackbox.log: Permission denied
71 warning: cannot write to blackbox.log: Permission denied
72 comparing with $TESTTMP/blackboxtest (glob)
72 comparing with $TESTTMP/blackboxtest (glob)
73 query 1; heads
73 query 1; heads
74 searching for changes
74 searching for changes
75 all local heads known remotely
75 all local heads known remotely
76 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
76 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
77 tag: tip
77 tag: tip
78 phase: draft
78 phase: draft
79 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
79 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
80 parent: -1:0000000000000000000000000000000000000000
80 parent: -1:0000000000000000000000000000000000000000
81 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
81 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
82 user: test
82 user: test
83 date: Thu Jan 01 00:00:00 1970 +0000
83 date: Thu Jan 01 00:00:00 1970 +0000
84 files+: c
84 files+: c
85 extra: branch=default
85 extra: branch=default
86 description:
86 description:
87 c
87 c
88
88
89
89
90 #endif
90 #endif
91 $ hg pull
91 $ hg pull
92 pulling from $TESTTMP/blackboxtest (glob)
92 pulling from $TESTTMP/blackboxtest (glob)
93 searching for changes
93 searching for changes
94 adding changesets
94 adding changesets
95 adding manifests
95 adding manifests
96 adding file changes
96 adding file changes
97 added 1 changesets with 1 changes to 1 files
97 added 1 changesets with 1 changes to 1 files
98 (run 'hg update' to get a working copy)
98 (run 'hg update' to get a working copy)
99
99
100 a failure reading from the log is fine
100 a failure reading from the log is fine
101 #if unix-permissions
101 #if unix-permissions
102 $ hg blackbox -l 3
102 $ hg blackbox -l 3
103 abort: Permission denied: $TESTTMP/blackboxtest2/.hg/blackbox.log
103 abort: Permission denied: $TESTTMP/blackboxtest2/.hg/blackbox.log
104 [255]
104 [255]
105
105
106 $ chmod 600 .hg/blackbox.log
106 $ chmod 600 .hg/blackbox.log
107 #endif
107 #endif
108
108
109 backup bundles get logged
109 backup bundles get logged
110
110
111 $ touch d
111 $ touch d
112 $ hg commit -Amd
112 $ hg commit -Amd
113 adding d
113 adding d
114 created new head
114 created new head
115 $ hg strip tip
115 $ hg strip tip
116 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
116 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
117 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
117 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
118 $ hg blackbox -l 3
118 $ hg blackbox -l 3
119 1970/01/01 00:00:00 bob> strip tip
119 1970/01/01 00:00:00 bob> strip tip
120 1970/01/01 00:00:00 bob> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
120 1970/01/01 00:00:00 bob> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
121 1970/01/01 00:00:00 bob> strip exited 0 after * seconds (glob)
121 1970/01/01 00:00:00 bob> strip tip exited 0 after * seconds (glob)
122
122
123 extension and python hooks - use the eol extension for a pythonhook
123 extension and python hooks - use the eol extension for a pythonhook
124
124
125 $ echo '[extensions]' >> .hg/hgrc
125 $ echo '[extensions]' >> .hg/hgrc
126 $ echo 'eol=' >> .hg/hgrc
126 $ echo 'eol=' >> .hg/hgrc
127 $ echo '[hooks]' >> .hg/hgrc
127 $ echo '[hooks]' >> .hg/hgrc
128 $ echo 'update = echo hooked' >> .hg/hgrc
128 $ echo 'update = echo hooked' >> .hg/hgrc
129 $ hg update
129 $ hg update
130 hooked
130 hooked
131 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
131 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 $ hg blackbox -l 4
132 $ hg blackbox -l 4
133 1970/01/01 00:00:00 bob> update
133 1970/01/01 00:00:00 bob> update
134 1970/01/01 00:00:00 bob> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
134 1970/01/01 00:00:00 bob> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
135 1970/01/01 00:00:00 bob> exthook-update: echo hooked finished in * seconds (glob)
135 1970/01/01 00:00:00 bob> exthook-update: echo hooked finished in * seconds (glob)
136 1970/01/01 00:00:00 bob> update exited False after * seconds (glob)
136 1970/01/01 00:00:00 bob> update exited 0 after * seconds (glob)
137
137
138 log rotation
138 log rotation
139
139
140 $ echo '[blackbox]' >> .hg/hgrc
140 $ echo '[blackbox]' >> .hg/hgrc
141 $ echo 'maxsize = 20 b' >> .hg/hgrc
141 $ echo 'maxsize = 20 b' >> .hg/hgrc
142 $ echo 'maxfiles = 3' >> .hg/hgrc
142 $ echo 'maxfiles = 3' >> .hg/hgrc
143 $ hg status
143 $ hg status
144 $ hg status
144 $ hg status
145 $ hg status
145 $ hg status
146 $ hg tip -q
146 $ hg tip -q
147 2:d02f48003e62
147 2:d02f48003e62
148 $ ls .hg/blackbox.log*
148 $ ls .hg/blackbox.log*
149 .hg/blackbox.log
149 .hg/blackbox.log
150 .hg/blackbox.log.1
150 .hg/blackbox.log.1
151 .hg/blackbox.log.2
151 .hg/blackbox.log.2
152
152
153 cleanup
153 cleanup
154 $ cd ..
154 $ cd ..
@@ -1,210 +1,208 b''
1
1
2 $ cat > loop.py <<EOF
2 $ cat > loop.py <<EOF
3 > from mercurial import commands
3 > from mercurial import commands
4 >
4 >
5 > def loop(ui, loops, **opts):
5 > def loop(ui, loops, **opts):
6 > loops = int(loops)
6 > loops = int(loops)
7 > total = None
7 > total = None
8 > if loops >= 0:
8 > if loops >= 0:
9 > total = loops
9 > total = loops
10 > if opts.get('total', None):
10 > if opts.get('total', None):
11 > total = int(opts.get('total'))
11 > total = int(opts.get('total'))
12 > nested = False
12 > nested = False
13 > if opts.get('nested', None):
13 > if opts.get('nested', None):
14 > nested = True
14 > nested = True
15 > loops = abs(loops)
15 > loops = abs(loops)
16 >
16 >
17 > for i in range(loops):
17 > for i in range(loops):
18 > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
18 > ui.progress('loop', i, 'loop.%d' % i, 'loopnum', total)
19 > if opts.get('parallel'):
19 > if opts.get('parallel'):
20 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
20 > ui.progress('other', i, 'other.%d' % i, 'othernum', total)
21 > if nested:
21 > if nested:
22 > for j in range(2):
22 > for j in range(2):
23 > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
23 > ui.progress('nested', j, 'nested.%d' % j, 'nestnum', 2)
24 > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
24 > ui.progress('nested', None, 'nested.done', 'nestnum', 2)
25 > ui.progress('loop', None, 'loop.done', 'loopnum', total)
25 > ui.progress('loop', None, 'loop.done', 'loopnum', total)
26 >
26 >
27 > commands.norepo += " loop"
27 > commands.norepo += " loop"
28 >
28 >
29 > cmdtable = {
29 > cmdtable = {
30 > "loop": (loop, [('', 'total', '', 'override for total'),
30 > "loop": (loop, [('', 'total', '', 'override for total'),
31 > ('', 'nested', False, 'show nested results'),
31 > ('', 'nested', False, 'show nested results'),
32 > ('', 'parallel', False, 'show parallel sets of results'),
32 > ('', 'parallel', False, 'show parallel sets of results'),
33 > ],
33 > ],
34 > 'hg loop LOOPS'),
34 > 'hg loop LOOPS'),
35 > }
35 > }
36 > EOF
36 > EOF
37
37
38 $ cp $HGRCPATH $HGRCPATH.orig
38 $ cp $HGRCPATH $HGRCPATH.orig
39 $ echo "[extensions]" >> $HGRCPATH
39 $ echo "[extensions]" >> $HGRCPATH
40 $ echo "progress=" >> $HGRCPATH
40 $ echo "progress=" >> $HGRCPATH
41 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
41 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
42 $ echo "[progress]" >> $HGRCPATH
42 $ echo "[progress]" >> $HGRCPATH
43 $ echo "format = topic bar number" >> $HGRCPATH
43 $ echo "format = topic bar number" >> $HGRCPATH
44 $ echo "assume-tty=1" >> $HGRCPATH
44 $ echo "assume-tty=1" >> $HGRCPATH
45 $ echo "width=60" >> $HGRCPATH
45 $ echo "width=60" >> $HGRCPATH
46
46
47 test default params, display nothing because of delay
47 test default params, display nothing because of delay
48
48
49 $ hg -y loop 3
49 $ hg -y loop 3
50 $ echo "delay=0" >> $HGRCPATH
50 $ echo "delay=0" >> $HGRCPATH
51 $ echo "refresh=0" >> $HGRCPATH
51 $ echo "refresh=0" >> $HGRCPATH
52
52
53 test with delay=0, refresh=0
53 test with delay=0, refresh=0
54
54
55 $ hg -y loop 3
55 $ hg -y loop 3
56 \r (no-eol) (esc)
56 \r (no-eol) (esc)
57 loop [ ] 0/3\r (no-eol) (esc)
57 loop [ ] 0/3\r (no-eol) (esc)
58 loop [===============> ] 1/3\r (no-eol) (esc)
58 loop [===============> ] 1/3\r (no-eol) (esc)
59 loop [===============================> ] 2/3\r (no-eol) (esc)
59 loop [===============================> ] 2/3\r (no-eol) (esc)
60 \r (no-eol) (esc)
60 \r (no-eol) (esc)
61
61
62
62
63 test nested short-lived topics (which shouldn't display with nestdelay):
63 test nested short-lived topics (which shouldn't display with nestdelay):
64
64
65 $ hg -y loop 3 --nested
65 $ hg -y loop 3 --nested
66 \r (no-eol) (esc)
66 \r (no-eol) (esc)
67 loop [ ] 0/3\r (no-eol) (esc)
67 loop [ ] 0/3\r (no-eol) (esc)
68 loop [===============> ] 1/3\r (no-eol) (esc)
68 loop [===============> ] 1/3\r (no-eol) (esc)
69 loop [===============================> ] 2/3\r (no-eol) (esc)
69 loop [===============================> ] 2/3\r (no-eol) (esc)
70 \r (no-eol) (esc)
70 \r (no-eol) (esc)
71
71
72
72
73 $ hg --config progress.changedelay=0 -y loop 3 --nested
73 $ hg --config progress.changedelay=0 -y loop 3 --nested
74 \r (no-eol) (esc)
74 \r (no-eol) (esc)
75 loop [ ] 0/3\r (no-eol) (esc)
75 loop [ ] 0/3\r (no-eol) (esc)
76 nested [ ] 0/2\r (no-eol) (esc)
76 nested [ ] 0/2\r (no-eol) (esc)
77 nested [======================> ] 1/2\r (no-eol) (esc)
77 nested [======================> ] 1/2\r (no-eol) (esc)
78 loop [===============> ] 1/3\r (no-eol) (esc)
78 loop [===============> ] 1/3\r (no-eol) (esc)
79 nested [ ] 0/2\r (no-eol) (esc)
79 nested [ ] 0/2\r (no-eol) (esc)
80 nested [======================> ] 1/2\r (no-eol) (esc)
80 nested [======================> ] 1/2\r (no-eol) (esc)
81 loop [===============================> ] 2/3\r (no-eol) (esc)
81 loop [===============================> ] 2/3\r (no-eol) (esc)
82 nested [ ] 0/2\r (no-eol) (esc)
82 nested [ ] 0/2\r (no-eol) (esc)
83 nested [======================> ] 1/2\r (no-eol) (esc)
83 nested [======================> ] 1/2\r (no-eol) (esc)
84 \r (no-eol) (esc)
84 \r (no-eol) (esc)
85
85
86
86
87 test two topics being printed in parallel (as when we're doing a local
87 test two topics being printed in parallel (as when we're doing a local
88 --pull clone, where you get the unbundle and bundle progress at the
88 --pull clone, where you get the unbundle and bundle progress at the
89 same time):
89 same time):
90 $ hg loop 3 --parallel
90 $ hg loop 3 --parallel
91 \r (no-eol) (esc)
91 \r (no-eol) (esc)
92 loop [ ] 0/3\r (no-eol) (esc)
92 loop [ ] 0/3\r (no-eol) (esc)
93 loop [===============> ] 1/3\r (no-eol) (esc)
93 loop [===============> ] 1/3\r (no-eol) (esc)
94 loop [===============================> ] 2/3\r (no-eol) (esc)
94 loop [===============================> ] 2/3\r (no-eol) (esc)
95 \r (no-eol) (esc)
95 \r (no-eol) (esc)
96 test refresh is taken in account
96 test refresh is taken in account
97
97
98 $ hg -y --config progress.refresh=100 loop 3
98 $ hg -y --config progress.refresh=100 loop 3
99
99
100 test format options 1
100 test format options 1
101
101
102 $ hg -y --config 'progress.format=number topic item+2' loop 2
102 $ hg -y --config 'progress.format=number topic item+2' loop 2
103 \r (no-eol) (esc)
103 \r (no-eol) (esc)
104 0/2 loop lo\r (no-eol) (esc)
104 0/2 loop lo\r (no-eol) (esc)
105 1/2 loop lo\r (no-eol) (esc)
105 1/2 loop lo\r (no-eol) (esc)
106 \r (no-eol) (esc)
106 \r (no-eol) (esc)
107
107
108 test format options 2
108 test format options 2
109
109
110 $ hg -y --config 'progress.format=number item-3 bar' loop 2
110 $ hg -y --config 'progress.format=number item-3 bar' loop 2
111 \r (no-eol) (esc)
111 \r (no-eol) (esc)
112 0/2 p.0 [ ]\r (no-eol) (esc)
112 0/2 p.0 [ ]\r (no-eol) (esc)
113 1/2 p.1 [=======================> ]\r (no-eol) (esc)
113 1/2 p.1 [=======================> ]\r (no-eol) (esc)
114 \r (no-eol) (esc)
114 \r (no-eol) (esc)
115
115
116 test format options and indeterminate progress
116 test format options and indeterminate progress
117
117
118 $ hg -y --config 'progress.format=number item bar' loop -- -2
118 $ hg -y --config 'progress.format=number item bar' loop -- -2
119 \r (no-eol) (esc)
119 \r (no-eol) (esc)
120 0 loop.0 [ <=> ]\r (no-eol) (esc)
120 0 loop.0 [ <=> ]\r (no-eol) (esc)
121 1 loop.1 [ <=> ]\r (no-eol) (esc)
121 1 loop.1 [ <=> ]\r (no-eol) (esc)
122 \r (no-eol) (esc)
122 \r (no-eol) (esc)
123
123
124 make sure things don't fall over if count > total
124 make sure things don't fall over if count > total
125
125
126 $ hg -y loop --total 4 6
126 $ hg -y loop --total 4 6
127 \r (no-eol) (esc)
127 \r (no-eol) (esc)
128 loop [ ] 0/4\r (no-eol) (esc)
128 loop [ ] 0/4\r (no-eol) (esc)
129 loop [===========> ] 1/4\r (no-eol) (esc)
129 loop [===========> ] 1/4\r (no-eol) (esc)
130 loop [=======================> ] 2/4\r (no-eol) (esc)
130 loop [=======================> ] 2/4\r (no-eol) (esc)
131 loop [===================================> ] 3/4\r (no-eol) (esc)
131 loop [===================================> ] 3/4\r (no-eol) (esc)
132 loop [===============================================>] 4/4\r (no-eol) (esc)
132 loop [===============================================>] 4/4\r (no-eol) (esc)
133 loop [ <=> ] 5/4\r (no-eol) (esc)
133 loop [ <=> ] 5/4\r (no-eol) (esc)
134 \r (no-eol) (esc)
134 \r (no-eol) (esc)
135
135
136 test immediate progress completion
136 test immediate progress completion
137
137
138 $ hg -y loop 0
138 $ hg -y loop 0
139
139
140 test delay time estimates
140 test delay time estimates
141
141
142 $ cat > mocktime.py <<EOF
142 $ cat > mocktime.py <<EOF
143 > import os
143 > import os
144 > import time
144 > import time
145 >
145 >
146 > class mocktime(object):
146 > class mocktime(object):
147 > def __init__(self, increment):
147 > def __init__(self, increment):
148 > self.time = 0
148 > self.time = 0
149 > self.increment = increment
149 > self.increment = increment
150 > def __call__(self):
150 > def __call__(self):
151 > self.time += self.increment
151 > self.time += self.increment
152 > return self.time
152 > return self.time
153 >
153 >
154 > def uisetup(ui):
154 > def uisetup(ui):
155 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
155 > time.time = mocktime(int(os.environ.get('MOCKTIME', '11')))
156 > EOF
156 > EOF
157
157
158 $ cp $HGRCPATH.orig $HGRCPATH
158 $ cp $HGRCPATH.orig $HGRCPATH
159 $ echo "[extensions]" >> $HGRCPATH
159 $ echo "[extensions]" >> $HGRCPATH
160 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
160 $ echo "mocktime=`pwd`/mocktime.py" >> $HGRCPATH
161 $ echo "progress=" >> $HGRCPATH
161 $ echo "progress=" >> $HGRCPATH
162 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
162 $ echo "loop=`pwd`/loop.py" >> $HGRCPATH
163 $ echo "[progress]" >> $HGRCPATH
163 $ echo "[progress]" >> $HGRCPATH
164 $ echo "assume-tty=1" >> $HGRCPATH
164 $ echo "assume-tty=1" >> $HGRCPATH
165 $ echo "delay=25" >> $HGRCPATH
165 $ echo "delay=25" >> $HGRCPATH
166 $ echo "width=60" >> $HGRCPATH
166 $ echo "width=60" >> $HGRCPATH
167
167
168 $ hg -y loop 8
168 $ hg -y loop 8
169 \r (no-eol) (esc)
169 \r (no-eol) (esc)
170 loop [====> ] 1/8 1m18s\r (no-eol) (esc)
171 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
170 loop [=========> ] 2/8 1m07s\r (no-eol) (esc)
172 loop [===============> ] 3/8 56s\r (no-eol) (esc)
171 loop [===============> ] 3/8 56s\r (no-eol) (esc)
173 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
172 loop [=====================> ] 4/8 45s\r (no-eol) (esc)
174 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
173 loop [==========================> ] 5/8 34s\r (no-eol) (esc)
175 loop [================================> ] 6/8 23s\r (no-eol) (esc)
174 loop [================================> ] 6/8 23s\r (no-eol) (esc)
176 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
175 loop [=====================================> ] 7/8 12s\r (no-eol) (esc)
177 \r (no-eol) (esc)
176 \r (no-eol) (esc)
178
177
179 $ MOCKTIME=10000 hg -y loop 4
178 $ MOCKTIME=10000 hg -y loop 4
180 \r (no-eol) (esc)
179 \r (no-eol) (esc)
181 loop [ ] 0/4\r (no-eol) (esc)
180 loop [ ] 0/4\r (no-eol) (esc)
182 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
181 loop [=========> ] 1/4 8h21m\r (no-eol) (esc)
183 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
182 loop [====================> ] 2/4 5h34m\r (no-eol) (esc)
184 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
183 loop [==============================> ] 3/4 2h47m\r (no-eol) (esc)
185 \r (no-eol) (esc)
184 \r (no-eol) (esc)
186
185
187 $ MOCKTIME=1000000 hg -y loop 4
186 $ MOCKTIME=1000000 hg -y loop 4
188 \r (no-eol) (esc)
187 \r (no-eol) (esc)
189 loop [ ] 0/4\r (no-eol) (esc)
188 loop [ ] 0/4\r (no-eol) (esc)
190 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
189 loop [=========> ] 1/4 5w00d\r (no-eol) (esc)
191 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
190 loop [====================> ] 2/4 3w03d\r (no-eol) (esc)
192 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
191 loop [=============================> ] 3/4 11d14h\r (no-eol) (esc)
193 \r (no-eol) (esc)
192 \r (no-eol) (esc)
194
193
195
194
196 $ MOCKTIME=14000000 hg -y loop 4
195 $ MOCKTIME=14000000 hg -y loop 4
197 \r (no-eol) (esc)
196 \r (no-eol) (esc)
198 loop [ ] 0/4\r (no-eol) (esc)
197 loop [ ] 0/4\r (no-eol) (esc)
199 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
198 loop [=========> ] 1/4 1y18w\r (no-eol) (esc)
200 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
199 loop [===================> ] 2/4 46w03d\r (no-eol) (esc)
201 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
200 loop [=============================> ] 3/4 23w02d\r (no-eol) (esc)
202 \r (no-eol) (esc)
201 \r (no-eol) (esc)
203
202
204 Time estimates should not fail when there's no end point:
203 Time estimates should not fail when there's no end point:
205 $ hg -y loop -- -4
204 $ hg -y loop -- -4
206 \r (no-eol) (esc)
205 \r (no-eol) (esc)
207 loop [ <=> ] 1\r (no-eol) (esc)
206 loop [ <=> ] 2\r (no-eol) (esc)
208 loop [ <=> ] 2\r (no-eol) (esc)
207 loop [ <=> ] 3\r (no-eol) (esc)
209 loop [ <=> ] 3\r (no-eol) (esc)
210 \r (no-eol) (esc)
208 \r (no-eol) (esc)
General Comments 0
You need to be logged in to leave comments. Login now