##// END OF EJS Templates
i18n: merge with main
Martin Geisler -
r12834:b814f67d merge stable
parent child Browse files
Show More
@@ -1,110 +1,110 b''
1 # If you want to change PREFIX, do not just edit it below. The changed
1 # If you want to change PREFIX, do not just edit it below. The changed
2 # value wont get passed on to recursive make calls. You should instead
2 # value wont get passed on to recursive make calls. You should instead
3 # override the variable on the command like:
3 # override the variable on the command like:
4 #
4 #
5 # % make PREFIX=/opt/ install
5 # % make PREFIX=/opt/ install
6
6
7 PREFIX=/usr/local
7 PREFIX=/usr/local
8 export PREFIX
8 export PREFIX
9 PYTHON=python
9 PYTHON=python
10 PURE=
10 PURE=
11 PYTHON_FILES:=$(shell find mercurial hgext doc -name '*.py')
11 PYTHON_FILES:=$(shell find mercurial hgext doc -name '*.py')
12
12
13 help:
13 help:
14 @echo 'Commonly used make targets:'
14 @echo 'Commonly used make targets:'
15 @echo ' all - build program and documentation'
15 @echo ' all - build program and documentation'
16 @echo ' install - install program and man pages to PREFIX ($(PREFIX))'
16 @echo ' install - install program and man pages to PREFIX ($(PREFIX))'
17 @echo ' install-home - install with setup.py install --home=HOME ($(HOME))'
17 @echo ' install-home - install with setup.py install --home=HOME ($(HOME))'
18 @echo ' local - build for inplace usage'
18 @echo ' local - build for inplace usage'
19 @echo ' tests - run all tests in the automatic test suite'
19 @echo ' tests - run all tests in the automatic test suite'
20 @echo ' test-foo - run only specified tests (e.g. test-merge1)'
20 @echo ' test-foo - run only specified tests (e.g. test-merge1)'
21 @echo ' dist - run all tests and create a source tarball in dist/'
21 @echo ' dist - run all tests and create a source tarball in dist/'
22 @echo ' clean - remove files created by other targets'
22 @echo ' clean - remove files created by other targets'
23 @echo ' (except installed files or dist source tarball)'
23 @echo ' (except installed files or dist source tarball)'
24 @echo ' update-pot - update i18n/hg.pot'
24 @echo ' update-pot - update i18n/hg.pot'
25 @echo
25 @echo
26 @echo 'Example for a system-wide installation under /usr/local:'
26 @echo 'Example for a system-wide installation under /usr/local:'
27 @echo ' make all && su -c "make install" && hg version'
27 @echo ' make all && su -c "make install" && hg version'
28 @echo
28 @echo
29 @echo 'Example for a local installation (usable in this directory):'
29 @echo 'Example for a local installation (usable in this directory):'
30 @echo ' make local && ./hg version'
30 @echo ' make local && ./hg version'
31
31
32 all: build doc
32 all: build doc
33
33
34 local:
34 local:
35 $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_mo
35 $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_mo
36 $(PYTHON) hg version
36 $(PYTHON) hg version
37
37
38 build:
38 build:
39 $(PYTHON) setup.py $(PURE) build
39 $(PYTHON) setup.py $(PURE) build
40
40
41 doc:
41 doc:
42 $(MAKE) -C doc
42 $(MAKE) -C doc
43
43
44 clean:
44 clean:
45 -$(PYTHON) setup.py clean --all # ignore errors from this command
45 -$(PYTHON) setup.py clean --all # ignore errors from this command
46 find . \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
46 find . \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
47 rm -f MANIFEST mercurial/__version__.py tests/*.err
47 rm -f MANIFEST mercurial/__version__.py tests/*.err
48 rm -rf build mercurial/locale
48 rm -rf build mercurial/locale
49 $(MAKE) -C doc clean
49 $(MAKE) -C doc clean
50
50
51 install: install-bin install-doc
51 install: install-bin install-doc
52
52
53 install-bin: build
53 install-bin: build
54 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
54 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
55
55
56 install-doc: doc
56 install-doc: doc
57 cd doc && $(MAKE) $(MFLAGS) install
57 cd doc && $(MAKE) $(MFLAGS) install
58
58
59 install-home: install-home-bin install-home-doc
59 install-home: install-home-bin install-home-doc
60
60
61 install-home-bin: build
61 install-home-bin: build
62 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --force
62 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --force
63
63
64 install-home-doc: doc
64 install-home-doc: doc
65 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
65 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
66
66
67 MANIFEST-doc:
67 MANIFEST-doc:
68 $(MAKE) -C doc MANIFEST
68 $(MAKE) -C doc MANIFEST
69
69
70 MANIFEST: MANIFEST-doc
70 MANIFEST: MANIFEST-doc
71 hg manifest > MANIFEST
71 hg manifest > MANIFEST
72 echo mercurial/__version__.py >> MANIFEST
72 echo mercurial/__version__.py >> MANIFEST
73 cat doc/MANIFEST >> MANIFEST
73 cat doc/MANIFEST >> MANIFEST
74
74
75 dist: tests dist-notests
75 dist: tests dist-notests
76
76
77 dist-notests: doc MANIFEST
77 dist-notests: doc MANIFEST
78 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
78 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
79
79
80 tests:
80 tests:
81 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
81 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
82
82
83 test-%:
83 test-%:
84 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
84 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
85
85
86 update-pot: i18n/hg.pot
86 update-pot: i18n/hg.pot
87
87
88 i18n/hg.pot: $(PYTHON_FILES) mercurial/help/*.txt
88 i18n/hg.pot: $(PYTHON_FILES) mercurial/help/*.txt
89 $(PYTHON) i18n/hggettext mercurial/commands.py \
89 $(PYTHON) i18n/hggettext mercurial/commands.py \
90 hgext/*.py hgext/*/__init__.py mercurial/help/*.txt > i18n/hg.pot
90 hgext/*.py hgext/*/__init__.py mercurial/help/*.txt > i18n/hg.pot
91 # All strings marked for translation in Mercurial contain
91 # All strings marked for translation in Mercurial contain
92 # ASCII characters only. But some files contain string
92 # ASCII characters only. But some files contain string
93 # literals like this '\037\213'. xgettext thinks it has to
93 # literals like this '\037\213'. xgettext thinks it has to
94 # parse them even though they are not marked for translation.
94 # parse them even though they are not marked for translation.
95 # Extracting with an explicit encoding of ISO-8859-1 will make
95 # Extracting with an explicit encoding of ISO-8859-1 will make
96 # xgettext "parse" and ignore them.
96 # xgettext "parse" and ignore them.
97 echo $(PYTHON_FILES) | xargs \
97 echo $(PYTHON_FILES) | xargs \
98 xgettext --package-name "Mercurial" \
98 xgettext --package-name "Mercurial" \
99 --msgid-bugs-address "<mercurial-devel@selenic.com>" \
99 --msgid-bugs-address "<mercurial-devel@selenic.com>" \
100 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
100 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
101 --from-code ISO-8859-1 --join --sort-by-file \
101 --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \
102 -d hg -p i18n -o hg.pot
102 -d hg -p i18n -o hg.pot
103 $(PYTHON) i18n/posplit i18n/hg.pot
103 $(PYTHON) i18n/posplit i18n/hg.pot
104
104
105 %.po: i18n/hg.pot
105 %.po: i18n/hg.pot
106 msgmerge --no-location --update $@ $^
106 msgmerge --no-location --update $@ $^
107
107
108 .PHONY: help all local build doc clean install install-bin install-doc \
108 .PHONY: help all local build doc clean install install-bin install-doc \
109 install-home install-home-bin install-home-doc dist dist-notests tests \
109 install-home install-home-bin install-home-doc dist dist-notests tests \
110 update-pot
110 update-pot
@@ -1,167 +1,172 b''
1 import os, sys, textwrap
1 import os, sys, textwrap
2 # import from the live mercurial repo
2 # import from the live mercurial repo
3 sys.path.insert(0, "..")
3 sys.path.insert(0, "..")
4 # fall back to pure modules if required C extensions are not available
4 # fall back to pure modules if required C extensions are not available
5 sys.path.append(os.path.join('..', 'mercurial', 'pure'))
5 sys.path.append(os.path.join('..', 'mercurial', 'pure'))
6 from mercurial import demandimport; demandimport.enable()
6 from mercurial import demandimport; demandimport.enable()
7 from mercurial import encoding
7 from mercurial import encoding
8 from mercurial.commands import table, globalopts
8 from mercurial.commands import table, globalopts
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial.help import helptable
10 from mercurial.help import helptable
11 from mercurial import extensions
11 from mercurial import extensions
12
12
13 def get_desc(docstr):
13 def get_desc(docstr):
14 if not docstr:
14 if not docstr:
15 return "", ""
15 return "", ""
16 # sanitize
16 # sanitize
17 docstr = docstr.strip("\n")
17 docstr = docstr.strip("\n")
18 docstr = docstr.rstrip()
18 docstr = docstr.rstrip()
19 shortdesc = docstr.splitlines()[0].strip()
19 shortdesc = docstr.splitlines()[0].strip()
20
20
21 i = docstr.find("\n")
21 i = docstr.find("\n")
22 if i != -1:
22 if i != -1:
23 desc = docstr[i + 2:]
23 desc = docstr[i + 2:]
24 else:
24 else:
25 desc = shortdesc
25 desc = shortdesc
26
26
27 desc = textwrap.dedent(desc)
27 desc = textwrap.dedent(desc)
28
28
29 return (shortdesc, desc)
29 return (shortdesc, desc)
30
30
31 def get_opts(opts):
31 def get_opts(opts):
32 for opt in opts:
32 for opt in opts:
33 if len(opt) == 5:
33 if len(opt) == 5:
34 shortopt, longopt, default, desc, optlabel = opt
34 shortopt, longopt, default, desc, optlabel = opt
35 else:
35 else:
36 shortopt, longopt, default, desc = opt
36 shortopt, longopt, default, desc = opt
37 allopts = []
37 allopts = []
38 if shortopt:
38 if shortopt:
39 allopts.append("-%s" % shortopt)
39 allopts.append("-%s" % shortopt)
40 if longopt:
40 if longopt:
41 allopts.append("--%s" % longopt)
41 allopts.append("--%s" % longopt)
42 desc += default and _(" (default: %s)") % default or ""
42 desc += default and _(" (default: %s)") % default or ""
43 yield(", ".join(allopts), desc)
43 yield(", ".join(allopts), desc)
44
44
45 def get_cmd(cmd, cmdtable):
45 def get_cmd(cmd, cmdtable):
46 d = {}
46 d = {}
47 attr = cmdtable[cmd]
47 attr = cmdtable[cmd]
48 cmds = cmd.lstrip("^").split("|")
48 cmds = cmd.lstrip("^").split("|")
49
49
50 d['cmd'] = cmds[0]
50 d['cmd'] = cmds[0]
51 d['aliases'] = cmd.split("|")[1:]
51 d['aliases'] = cmd.split("|")[1:]
52 d['desc'] = get_desc(attr[0].__doc__)
52 d['desc'] = get_desc(attr[0].__doc__)
53 d['opts'] = list(get_opts(attr[1]))
53 d['opts'] = list(get_opts(attr[1]))
54
54
55 s = 'hg ' + cmds[0]
55 s = 'hg ' + cmds[0]
56 if len(attr) > 2:
56 if len(attr) > 2:
57 if not attr[2].startswith('hg'):
57 if not attr[2].startswith('hg'):
58 s += ' ' + attr[2]
58 s += ' ' + attr[2]
59 else:
59 else:
60 s = attr[2]
60 s = attr[2]
61 d['synopsis'] = s.strip()
61 d['synopsis'] = s.strip()
62
62
63 return d
63 return d
64
64
65 def section(ui, s):
65 def section(ui, s):
66 ui.write("%s\n%s\n\n" % (s, "-" * encoding.colwidth(s)))
66 ui.write("%s\n%s\n\n" % (s, "-" * encoding.colwidth(s)))
67
67
68 def subsection(ui, s):
68 def subsection(ui, s):
69 ui.write("%s\n%s\n\n" % (s, '"' * encoding.colwidth(s)))
69 ui.write("%s\n%s\n\n" % (s, '"' * encoding.colwidth(s)))
70
70
71 def subsubsection(ui, s):
71 def subsubsection(ui, s):
72 ui.write("%s\n%s\n\n" % (s, "." * encoding.colwidth(s)))
72 ui.write("%s\n%s\n\n" % (s, "." * encoding.colwidth(s)))
73
73
74 def subsubsubsection(ui, s):
74 def subsubsubsection(ui, s):
75 ui.write("%s\n%s\n\n" % (s, "#" * encoding.colwidth(s)))
75 ui.write("%s\n%s\n\n" % (s, "#" * encoding.colwidth(s)))
76
76
77
77
78 def show_doc(ui):
78 def show_doc(ui):
79 # print options
79 # print options
80 section(ui, _("Options"))
80 section(ui, _("Options"))
81 for optstr, desc in get_opts(globalopts):
81 for optstr, desc in get_opts(globalopts):
82 ui.write("%s\n%s\n\n" % (optstr, desc))
82 ui.write("%s\n %s\n\n" % (optstr, desc))
83
83
84 # print cmds
84 # print cmds
85 section(ui, _("Commands"))
85 section(ui, _("Commands"))
86 commandprinter(ui, table, subsection)
86 commandprinter(ui, table, subsection)
87
87
88 # print topics
88 # print topics
89 for names, sec, doc in helptable:
89 for names, sec, doc in helptable:
90 for name in names:
90 for name in names:
91 ui.write(".. _%s:\n" % name)
91 ui.write(".. _%s:\n" % name)
92 ui.write("\n")
92 ui.write("\n")
93 section(ui, sec)
93 section(ui, sec)
94 if hasattr(doc, '__call__'):
94 if hasattr(doc, '__call__'):
95 doc = doc()
95 doc = doc()
96 ui.write(doc)
96 ui.write(doc)
97 ui.write("\n")
97 ui.write("\n")
98
98
99 section(ui, _("Extensions"))
99 section(ui, _("Extensions"))
100 ui.write(_("This section contains help for extensions that is distributed "
100 ui.write(_("This section contains help for extensions that are distributed "
101 "together with Mercurial. Help for other extensions is available "
101 "together with Mercurial. Help for other extensions is available "
102 "in the help system."))
102 "in the help system."))
103 ui.write("\n\n"
103 ui.write("\n\n"
104 ".. contents::\n"
104 ".. contents::\n"
105 " :class: htmlonly\n"
105 " :class: htmlonly\n"
106 " :local:\n"
106 " :local:\n"
107 " :depth: 1\n\n")
107 " :depth: 1\n\n")
108
108
109 for extensionname in sorted(allextensionnames()):
109 for extensionname in sorted(allextensionnames()):
110 mod = extensions.load(None, extensionname, None)
110 mod = extensions.load(None, extensionname, None)
111 subsection(ui, extensionname)
111 subsection(ui, extensionname)
112 ui.write("%s\n\n" % mod.__doc__)
112 ui.write("%s\n\n" % mod.__doc__)
113 cmdtable = getattr(mod, 'cmdtable', None)
113 cmdtable = getattr(mod, 'cmdtable', None)
114 if cmdtable:
114 if cmdtable:
115 subsubsection(ui, _('Commands'))
115 subsubsection(ui, _('Commands'))
116 commandprinter(ui, cmdtable, subsubsubsection)
116 commandprinter(ui, cmdtable, subsubsubsection)
117
117
118 def commandprinter(ui, cmdtable, sectionfunc):
118 def commandprinter(ui, cmdtable, sectionfunc):
119 h = {}
119 h = {}
120 for c, attr in cmdtable.items():
120 for c, attr in cmdtable.items():
121 f = c.split("|")[0]
121 f = c.split("|")[0]
122 f = f.lstrip("^")
122 f = f.lstrip("^")
123 h[f] = c
123 h[f] = c
124 cmds = h.keys()
124 cmds = h.keys()
125 cmds.sort()
125 cmds.sort()
126
126
127 for f in cmds:
127 for f in cmds:
128 if f.startswith("debug"):
128 if f.startswith("debug"):
129 continue
129 continue
130 d = get_cmd(h[f], cmdtable)
130 d = get_cmd(h[f], cmdtable)
131 sectionfunc(ui, d['cmd'])
131 sectionfunc(ui, d['cmd'])
132 # synopsis
132 # synopsis
133 ui.write("``%s``\n" % d['synopsis'].replace("hg ","", 1))
133 ui.write("::\n\n")
134 ui.write("\n")
134 synopsislines = d['synopsis'].splitlines()
135 for line in synopsislines:
136 # some commands (such as rebase) have a multi-line
137 # synopsis
138 ui.write(" %s\n" % line)
139 ui.write('\n')
135 # description
140 # description
136 ui.write("%s\n\n" % d['desc'][1])
141 ui.write("%s\n\n" % d['desc'][1])
137 # options
142 # options
138 opt_output = list(d['opts'])
143 opt_output = list(d['opts'])
139 if opt_output:
144 if opt_output:
140 opts_len = max([len(line[0]) for line in opt_output])
145 opts_len = max([len(line[0]) for line in opt_output])
141 ui.write(_("options:\n\n"))
146 ui.write(_("options:\n\n"))
142 for optstr, desc in opt_output:
147 for optstr, desc in opt_output:
143 if desc:
148 if desc:
144 s = "%-*s %s" % (opts_len, optstr, desc)
149 s = "%-*s %s" % (opts_len, optstr, desc)
145 else:
150 else:
146 s = optstr
151 s = optstr
147 ui.write("%s\n" % s)
152 ui.write("%s\n" % s)
148 ui.write("\n")
153 ui.write("\n")
149 # aliases
154 # aliases
150 if d['aliases']:
155 if d['aliases']:
151 ui.write(_(" aliases: %s\n\n") % " ".join(d['aliases']))
156 ui.write(_(" aliases: %s\n\n") % " ".join(d['aliases']))
152
157
153
158
154 def allextensionnames():
159 def allextensionnames():
155 extensionnames = []
160 extensionnames = []
156
161
157 extensionsdictionary = extensions.enabled()[0]
162 extensionsdictionary = extensions.enabled()[0]
158 extensionnames.extend(extensionsdictionary.keys())
163 extensionnames.extend(extensionsdictionary.keys())
159
164
160 extensionsdictionary = extensions.disabled()[0]
165 extensionsdictionary = extensions.disabled()[0]
161 extensionnames.extend(extensionsdictionary.keys())
166 extensionnames.extend(extensionsdictionary.keys())
162
167
163 return extensionnames
168 return extensionnames
164
169
165
170
166 if __name__ == "__main__":
171 if __name__ == "__main__":
167 show_doc(sys.stdout)
172 show_doc(sys.stdout)
@@ -1,37 +1,38 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # mercurial - scalable distributed SCM
3 # mercurial - scalable distributed SCM
4 #
4 #
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 import os
10 import os
11 import sys
11 import sys
12
12
13 libdir = '@LIBDIR@'
13 libdir = '@LIBDIR@'
14
14
15 if libdir != '@' 'LIBDIR' '@':
15 if libdir != '@' 'LIBDIR' '@':
16 if not os.path.isabs(libdir):
16 if not os.path.isabs(libdir):
17 libdir = os.path.join(os.path.dirname(__file__), libdir)
17 libdir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
18 libdir)
18 libdir = os.path.abspath(libdir)
19 libdir = os.path.abspath(libdir)
19 sys.path.insert(0, libdir)
20 sys.path.insert(0, libdir)
20
21
21 # enable importing on demand to reduce startup time
22 # enable importing on demand to reduce startup time
22 try:
23 try:
23 from mercurial import demandimport; demandimport.enable()
24 from mercurial import demandimport; demandimport.enable()
24 except ImportError:
25 except ImportError:
25 import sys
26 import sys
26 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
27 sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" %
27 ' '.join(sys.path))
28 ' '.join(sys.path))
28 sys.stderr.write("(check your install and PYTHONPATH)\n")
29 sys.stderr.write("(check your install and PYTHONPATH)\n")
29 sys.exit(-1)
30 sys.exit(-1)
30
31
31 import mercurial.util
32 import mercurial.util
32 import mercurial.dispatch
33 import mercurial.dispatch
33
34
34 for fp in (sys.stdin, sys.stdout, sys.stderr):
35 for fp in (sys.stdin, sys.stdout, sys.stderr):
35 mercurial.util.set_binary(fp)
36 mercurial.util.set_binary(fp)
36
37
37 mercurial.dispatch.run()
38 mercurial.dispatch.run()
@@ -1,317 +1,319 b''
1 # color.py color output for the status and qseries commands
1 # color.py color output for the status and qseries commands
2 #
2 #
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
4 #
4 #
5 # This program is free software; you can redistribute it and/or modify it
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
8 # option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful, but
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
13 # Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License along
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
18
19 '''colorize output from some commands
19 '''colorize output from some commands
20
20
21 This extension modifies the status and resolve commands to add color to their
21 This extension modifies the status and resolve commands to add color to their
22 output to reflect file status, the qseries command to add color to reflect
22 output to reflect file status, the qseries command to add color to reflect
23 patch status (applied, unapplied, missing), and to diff-related
23 patch status (applied, unapplied, missing), and to diff-related
24 commands to highlight additions, removals, diff headers, and trailing
24 commands to highlight additions, removals, diff headers, and trailing
25 whitespace.
25 whitespace.
26
26
27 Other effects in addition to color, like bold and underlined text, are
27 Other effects in addition to color, like bold and underlined text, are
28 also available. Effects are rendered with the ECMA-48 SGR control
28 also available. Effects are rendered with the ECMA-48 SGR control
29 function (aka ANSI escape codes). This module also provides the
29 function (aka ANSI escape codes). This module also provides the
30 render_text function, which can be used to add effects to any text.
30 render_text function, which can be used to add effects to any text.
31
31
32 Default effects may be overridden from your configuration file::
32 Default effects may be overridden from your configuration file::
33
33
34 [color]
34 [color]
35 status.modified = blue bold underline red_background
35 status.modified = blue bold underline red_background
36 status.added = green bold
36 status.added = green bold
37 status.removed = red bold blue_background
37 status.removed = red bold blue_background
38 status.deleted = cyan bold underline
38 status.deleted = cyan bold underline
39 status.unknown = magenta bold underline
39 status.unknown = magenta bold underline
40 status.ignored = black bold
40 status.ignored = black bold
41
41
42 # 'none' turns off all effects
42 # 'none' turns off all effects
43 status.clean = none
43 status.clean = none
44 status.copied = none
44 status.copied = none
45
45
46 qseries.applied = blue bold underline
46 qseries.applied = blue bold underline
47 qseries.unapplied = black bold
47 qseries.unapplied = black bold
48 qseries.missing = red bold
48 qseries.missing = red bold
49
49
50 diff.diffline = bold
50 diff.diffline = bold
51 diff.extended = cyan bold
51 diff.extended = cyan bold
52 diff.file_a = red bold
52 diff.file_a = red bold
53 diff.file_b = green bold
53 diff.file_b = green bold
54 diff.hunk = magenta
54 diff.hunk = magenta
55 diff.deleted = red
55 diff.deleted = red
56 diff.inserted = green
56 diff.inserted = green
57 diff.changed = white
57 diff.changed = white
58 diff.trailingwhitespace = bold red_background
58 diff.trailingwhitespace = bold red_background
59
59
60 resolve.unresolved = red bold
60 resolve.unresolved = red bold
61 resolve.resolved = green bold
61 resolve.resolved = green bold
62
62
63 bookmarks.current = green
63 bookmarks.current = green
64
64
65 branches.active = none
65 branches.active = none
66 branches.closed = black bold
66 branches.closed = black bold
67 branches.current = green
67 branches.current = green
68 branches.inactive = none
68 branches.inactive = none
69
69
70 The color extension will try to detect whether to use ANSI codes or
70 The color extension will try to detect whether to use ANSI codes or
71 Win32 console APIs, unless it is made explicit::
71 Win32 console APIs, unless it is made explicit::
72
72
73 [color]
73 [color]
74 mode = ansi
74 mode = ansi
75
75
76 Any value other than 'ansi', 'win32', or 'auto' will disable color.
76 Any value other than 'ansi', 'win32', or 'auto' will disable color.
77
77
78 '''
78 '''
79
79
80 import os
80 import os
81
81
82 from mercurial import commands, dispatch, extensions, ui as uimod, util
82 from mercurial import commands, dispatch, extensions, ui as uimod, util
83 from mercurial.i18n import _
83 from mercurial.i18n import _
84
84
85 # start and stop parameters for effects
85 # start and stop parameters for effects
86 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
86 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
87 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
87 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
88 'italic': 3, 'underline': 4, 'inverse': 7,
88 'italic': 3, 'underline': 4, 'inverse': 7,
89 'black_background': 40, 'red_background': 41,
89 'black_background': 40, 'red_background': 41,
90 'green_background': 42, 'yellow_background': 43,
90 'green_background': 42, 'yellow_background': 43,
91 'blue_background': 44, 'purple_background': 45,
91 'blue_background': 44, 'purple_background': 45,
92 'cyan_background': 46, 'white_background': 47}
92 'cyan_background': 46, 'white_background': 47}
93
93
94 _styles = {'grep.match': 'red bold',
94 _styles = {'grep.match': 'red bold',
95 'branches.active': 'none',
95 'branches.active': 'none',
96 'branches.closed': 'black bold',
96 'branches.closed': 'black bold',
97 'branches.current': 'green',
97 'branches.current': 'green',
98 'branches.inactive': 'none',
98 'branches.inactive': 'none',
99 'diff.changed': 'white',
99 'diff.changed': 'white',
100 'diff.deleted': 'red',
100 'diff.deleted': 'red',
101 'diff.diffline': 'bold',
101 'diff.diffline': 'bold',
102 'diff.extended': 'cyan bold',
102 'diff.extended': 'cyan bold',
103 'diff.file_a': 'red bold',
103 'diff.file_a': 'red bold',
104 'diff.file_b': 'green bold',
104 'diff.file_b': 'green bold',
105 'diff.hunk': 'magenta',
105 'diff.hunk': 'magenta',
106 'diff.inserted': 'green',
106 'diff.inserted': 'green',
107 'diff.trailingwhitespace': 'bold red_background',
107 'diff.trailingwhitespace': 'bold red_background',
108 'diffstat.deleted': 'red',
108 'diffstat.deleted': 'red',
109 'diffstat.inserted': 'green',
109 'diffstat.inserted': 'green',
110 'log.changeset': 'yellow',
110 'log.changeset': 'yellow',
111 'resolve.resolved': 'green bold',
111 'resolve.resolved': 'green bold',
112 'resolve.unresolved': 'red bold',
112 'resolve.unresolved': 'red bold',
113 'status.added': 'green bold',
113 'status.added': 'green bold',
114 'status.clean': 'none',
114 'status.clean': 'none',
115 'status.copied': 'none',
115 'status.copied': 'none',
116 'status.deleted': 'cyan bold underline',
116 'status.deleted': 'cyan bold underline',
117 'status.ignored': 'black bold',
117 'status.ignored': 'black bold',
118 'status.modified': 'blue bold',
118 'status.modified': 'blue bold',
119 'status.removed': 'red bold',
119 'status.removed': 'red bold',
120 'status.unknown': 'magenta bold underline'}
120 'status.unknown': 'magenta bold underline'}
121
121
122
122
123 def render_effects(text, effects):
123 def render_effects(text, effects):
124 'Wrap text in commands to turn on each effect.'
124 'Wrap text in commands to turn on each effect.'
125 if not text:
125 if not text:
126 return text
126 return text
127 start = [str(_effects[e]) for e in ['none'] + effects.split()]
127 start = [str(_effects[e]) for e in ['none'] + effects.split()]
128 start = '\033[' + ';'.join(start) + 'm'
128 start = '\033[' + ';'.join(start) + 'm'
129 stop = '\033[' + str(_effects['none']) + 'm'
129 stop = '\033[' + str(_effects['none']) + 'm'
130 return ''.join([start, text, stop])
130 return ''.join([start, text, stop])
131
131
132 def extstyles():
132 def extstyles():
133 for name, ext in extensions.extensions():
133 for name, ext in extensions.extensions():
134 _styles.update(getattr(ext, 'colortable', {}))
134 _styles.update(getattr(ext, 'colortable', {}))
135
135
136 def configstyles(ui):
136 def configstyles(ui):
137 for status, cfgeffects in ui.configitems('color'):
137 for status, cfgeffects in ui.configitems('color'):
138 if '.' not in status:
138 if '.' not in status:
139 continue
139 continue
140 cfgeffects = ui.configlist('color', status)
140 cfgeffects = ui.configlist('color', status)
141 if cfgeffects:
141 if cfgeffects:
142 good = []
142 good = []
143 for e in cfgeffects:
143 for e in cfgeffects:
144 if e in _effects:
144 if e in _effects:
145 good.append(e)
145 good.append(e)
146 else:
146 else:
147 ui.warn(_("ignoring unknown color/effect %r "
147 ui.warn(_("ignoring unknown color/effect %r "
148 "(configured in color.%s)\n")
148 "(configured in color.%s)\n")
149 % (e, status))
149 % (e, status))
150 _styles[status] = ' '.join(good)
150 _styles[status] = ' '.join(good)
151
151
152 class colorui(uimod.ui):
152 class colorui(uimod.ui):
153 def popbuffer(self, labeled=False):
153 def popbuffer(self, labeled=False):
154 if labeled:
154 if labeled:
155 return ''.join(self.label(a, label) for a, label
155 return ''.join(self.label(a, label) for a, label
156 in self._buffers.pop())
156 in self._buffers.pop())
157 return ''.join(a for a, label in self._buffers.pop())
157 return ''.join(a for a, label in self._buffers.pop())
158
158
159 _colormode = 'ansi'
159 _colormode = 'ansi'
160 def write(self, *args, **opts):
160 def write(self, *args, **opts):
161 label = opts.get('label', '')
161 label = opts.get('label', '')
162 if self._buffers:
162 if self._buffers:
163 self._buffers[-1].extend([(str(a), label) for a in args])
163 self._buffers[-1].extend([(str(a), label) for a in args])
164 elif self._colormode == 'win32':
164 elif self._colormode == 'win32':
165 for a in args:
165 for a in args:
166 win32print(a, super(colorui, self).write, **opts)
166 win32print(a, super(colorui, self).write, **opts)
167 else:
167 else:
168 return super(colorui, self).write(
168 return super(colorui, self).write(
169 *[self.label(str(a), label) for a in args], **opts)
169 *[self.label(str(a), label) for a in args], **opts)
170
170
171 def write_err(self, *args, **opts):
171 def write_err(self, *args, **opts):
172 label = opts.get('label', '')
172 label = opts.get('label', '')
173 if self._colormode == 'win32':
173 if self._colormode == 'win32':
174 for a in args:
174 for a in args:
175 win32print(a, super(colorui, self).write_err, **opts)
175 win32print(a, super(colorui, self).write_err, **opts)
176 else:
176 else:
177 return super(colorui, self).write_err(
177 return super(colorui, self).write_err(
178 *[self.label(str(a), label) for a in args], **opts)
178 *[self.label(str(a), label) for a in args], **opts)
179
179
180 def label(self, msg, label):
180 def label(self, msg, label):
181 effects = []
181 effects = []
182 for l in label.split():
182 for l in label.split():
183 s = _styles.get(l, '')
183 s = _styles.get(l, '')
184 if s:
184 if s:
185 effects.append(s)
185 effects.append(s)
186 effects = ''.join(effects)
186 effects = ''.join(effects)
187 if effects:
187 if effects:
188 return '\n'.join([render_effects(s, effects)
188 return '\n'.join([render_effects(s, effects)
189 for s in msg.split('\n')])
189 for s in msg.split('\n')])
190 return msg
190 return msg
191
191
192
192
193 def uisetup(ui):
193 def uisetup(ui):
194 if ui.plain():
194 if ui.plain():
195 return
195 return
196 mode = ui.config('color', 'mode', 'auto')
196 mode = ui.config('color', 'mode', 'auto')
197 if mode == 'auto':
197 if mode == 'auto':
198 if os.name == 'nt' and 'TERM' not in os.environ:
198 if os.name == 'nt' and 'TERM' not in os.environ:
199 # looks line a cmd.exe console, use win32 API or nothing
199 # looks line a cmd.exe console, use win32 API or nothing
200 mode = w32effects and 'win32' or 'none'
200 mode = w32effects and 'win32' or 'none'
201 else:
201 else:
202 mode = 'ansi'
202 mode = 'ansi'
203 if mode == 'win32':
203 if mode == 'win32':
204 if w32effects is None:
204 if w32effects is None:
205 # only warn if color.mode is explicitly set to win32
205 # only warn if color.mode is explicitly set to win32
206 ui.warn(_('win32console not found, please install pywin32\n'))
206 ui.warn(_('win32console not found, please install pywin32\n'))
207 return
207 return
208 _effects.update(w32effects)
208 _effects.update(w32effects)
209 elif mode != 'ansi':
209 elif mode != 'ansi':
210 return
210 return
211 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
211 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
212 coloropt = opts['color']
212 coloropt = opts['color']
213 auto = coloropt == 'auto'
213 auto = coloropt == 'auto'
214 always = util.parsebool(coloropt)
214 always = util.parsebool(coloropt)
215 if (always or
215 if (always or
216 (always is None and
216 (always is None and
217 (auto and (os.environ.get('TERM') != 'dumb' and ui_.formatted())))):
217 (auto and (os.environ.get('TERM') != 'dumb' and ui_.formatted())))):
218 colorui._colormode = mode
218 colorui._colormode = mode
219 colorui.__bases__ = (ui_.__class__,)
219 colorui.__bases__ = (ui_.__class__,)
220 ui_.__class__ = colorui
220 ui_.__class__ = colorui
221 extstyles()
221 extstyles()
222 configstyles(ui_)
222 configstyles(ui_)
223 return orig(ui_, opts, cmd, cmdfunc)
223 return orig(ui_, opts, cmd, cmdfunc)
224 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
224 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
225
225
226 def extsetup(ui):
226 def extsetup(ui):
227 commands.globalopts.append(
227 commands.globalopts.append(
228 ('', 'color', 'auto',
228 ('', 'color', 'auto',
229 # i18n: 'always', 'auto', and 'never' are keywords and should
230 # not be translated
229 _("when to colorize (boolean, always, auto, or never)"),
231 _("when to colorize (boolean, always, auto, or never)"),
230 _('TYPE')))
232 _('TYPE')))
231
233
232 try:
234 try:
233 import re, pywintypes, win32console as win32c
235 import re, pywintypes, win32console as win32c
234
236
235 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
237 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
236 w32effects = {
238 w32effects = {
237 'none': -1,
239 'none': -1,
238 'black': 0,
240 'black': 0,
239 'red': win32c.FOREGROUND_RED,
241 'red': win32c.FOREGROUND_RED,
240 'green': win32c.FOREGROUND_GREEN,
242 'green': win32c.FOREGROUND_GREEN,
241 'yellow': win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN,
243 'yellow': win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN,
242 'blue': win32c.FOREGROUND_BLUE,
244 'blue': win32c.FOREGROUND_BLUE,
243 'magenta': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_RED,
245 'magenta': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_RED,
244 'cyan': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_GREEN,
246 'cyan': win32c.FOREGROUND_BLUE | win32c.FOREGROUND_GREEN,
245 'white': (win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN |
247 'white': (win32c.FOREGROUND_RED | win32c.FOREGROUND_GREEN |
246 win32c.FOREGROUND_BLUE),
248 win32c.FOREGROUND_BLUE),
247 'bold': win32c.FOREGROUND_INTENSITY,
249 'bold': win32c.FOREGROUND_INTENSITY,
248 'black_background': 0x100, # unused value > 0x0f
250 'black_background': 0x100, # unused value > 0x0f
249 'red_background': win32c.BACKGROUND_RED,
251 'red_background': win32c.BACKGROUND_RED,
250 'green_background': win32c.BACKGROUND_GREEN,
252 'green_background': win32c.BACKGROUND_GREEN,
251 'yellow_background': win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN,
253 'yellow_background': win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN,
252 'blue_background': win32c.BACKGROUND_BLUE,
254 'blue_background': win32c.BACKGROUND_BLUE,
253 'purple_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_RED,
255 'purple_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_RED,
254 'cyan_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_GREEN,
256 'cyan_background': win32c.BACKGROUND_BLUE | win32c.BACKGROUND_GREEN,
255 'white_background': (win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN |
257 'white_background': (win32c.BACKGROUND_RED | win32c.BACKGROUND_GREEN |
256 win32c.BACKGROUND_BLUE),
258 win32c.BACKGROUND_BLUE),
257 'bold_background': win32c.BACKGROUND_INTENSITY,
259 'bold_background': win32c.BACKGROUND_INTENSITY,
258 'underline': win32c.COMMON_LVB_UNDERSCORE, # double-byte charsets only
260 'underline': win32c.COMMON_LVB_UNDERSCORE, # double-byte charsets only
259 'inverse': win32c.COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
261 'inverse': win32c.COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
260 }
262 }
261
263
262 passthrough = set([win32c.FOREGROUND_INTENSITY,
264 passthrough = set([win32c.FOREGROUND_INTENSITY,
263 win32c.BACKGROUND_INTENSITY,
265 win32c.BACKGROUND_INTENSITY,
264 win32c.COMMON_LVB_UNDERSCORE,
266 win32c.COMMON_LVB_UNDERSCORE,
265 win32c.COMMON_LVB_REVERSE_VIDEO])
267 win32c.COMMON_LVB_REVERSE_VIDEO])
266
268
267 try:
269 try:
268 stdout = win32c.GetStdHandle(win32c.STD_OUTPUT_HANDLE)
270 stdout = win32c.GetStdHandle(win32c.STD_OUTPUT_HANDLE)
269 if stdout is None:
271 if stdout is None:
270 raise ImportError()
272 raise ImportError()
271 origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
273 origattr = stdout.GetConsoleScreenBufferInfo()['Attributes']
272 except pywintypes.error:
274 except pywintypes.error:
273 # stdout may be defined but not support
275 # stdout may be defined but not support
274 # GetConsoleScreenBufferInfo(), when called from subprocess or
276 # GetConsoleScreenBufferInfo(), when called from subprocess or
275 # redirected.
277 # redirected.
276 raise ImportError()
278 raise ImportError()
277 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
279 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL)
278
280
279 def win32print(text, orig, **opts):
281 def win32print(text, orig, **opts):
280 label = opts.get('label', '')
282 label = opts.get('label', '')
281 attr = origattr
283 attr = origattr
282
284
283 def mapcolor(val, attr):
285 def mapcolor(val, attr):
284 if val == -1:
286 if val == -1:
285 return origattr
287 return origattr
286 elif val in passthrough:
288 elif val in passthrough:
287 return attr | val
289 return attr | val
288 elif val > 0x0f:
290 elif val > 0x0f:
289 return (val & 0x70) | (attr & 0x8f)
291 return (val & 0x70) | (attr & 0x8f)
290 else:
292 else:
291 return (val & 0x07) | (attr & 0xf8)
293 return (val & 0x07) | (attr & 0xf8)
292
294
293 # determine console attributes based on labels
295 # determine console attributes based on labels
294 for l in label.split():
296 for l in label.split():
295 style = _styles.get(l, '')
297 style = _styles.get(l, '')
296 for effect in style.split():
298 for effect in style.split():
297 attr = mapcolor(w32effects[effect], attr)
299 attr = mapcolor(w32effects[effect], attr)
298
300
299 # hack to ensure regexp finds data
301 # hack to ensure regexp finds data
300 if not text.startswith('\033['):
302 if not text.startswith('\033['):
301 text = '\033[m' + text
303 text = '\033[m' + text
302
304
303 # Look for ANSI-like codes embedded in text
305 # Look for ANSI-like codes embedded in text
304 m = re.match(ansire, text)
306 m = re.match(ansire, text)
305 while m:
307 while m:
306 for sattr in m.group(1).split(';'):
308 for sattr in m.group(1).split(';'):
307 if sattr:
309 if sattr:
308 attr = mapcolor(int(sattr), attr)
310 attr = mapcolor(int(sattr), attr)
309 stdout.SetConsoleTextAttribute(attr)
311 stdout.SetConsoleTextAttribute(attr)
310 orig(m.group(2), **opts)
312 orig(m.group(2), **opts)
311 m = re.match(ansire, m.group(3))
313 m = re.match(ansire, m.group(3))
312
314
313 # Explicity reset original attributes
315 # Explicity reset original attributes
314 stdout.SetConsoleTextAttribute(origattr)
316 stdout.SetConsoleTextAttribute(origattr)
315
317
316 except ImportError:
318 except ImportError:
317 w32effects = None
319 w32effects = None
@@ -1,257 +1,257 b''
1 """automatically manage newlines in repository files
1 """automatically manage newlines in repository files
2
2
3 This extension allows you to manage the type of line endings (CRLF or
3 This extension allows you to manage the type of line endings (CRLF or
4 LF) that are used in the repository and in the local working
4 LF) that are used in the repository and in the local working
5 directory. That way you can get CRLF line endings on Windows and LF on
5 directory. That way you can get CRLF line endings on Windows and LF on
6 Unix/Mac, thereby letting everybody use their OS native line endings.
6 Unix/Mac, thereby letting everybody use their OS native line endings.
7
7
8 The extension reads its configuration from a versioned ``.hgeol``
8 The extension reads its configuration from a versioned ``.hgeol``
9 configuration file every time you run an ``hg`` command. The
9 configuration file every time you run an ``hg`` command. The
10 ``.hgeol`` file use the same syntax as all other Mercurial
10 ``.hgeol`` file use the same syntax as all other Mercurial
11 configuration files. It uses two sections, ``[patterns]`` and
11 configuration files. It uses two sections, ``[patterns]`` and
12 ``[repository]``.
12 ``[repository]``.
13
13
14 The ``[patterns]`` section specifies the line endings used in the
14 The ``[patterns]`` section specifies the line endings used in the
15 working directory. The format is specified by a file pattern. The
15 working directory. The format is specified by a file pattern. The
16 first match is used, so put more specific patterns first. The
16 first match is used, so put more specific patterns first. The
17 available line endings are ``LF``, ``CRLF``, and ``BIN``.
17 available line endings are ``LF``, ``CRLF``, and ``BIN``.
18
18
19 Files with the declared format of ``CRLF`` or ``LF`` are always
19 Files with the declared format of ``CRLF`` or ``LF`` are always
20 checked out in that format and files declared to be binary (``BIN``)
20 checked out in that format and files declared to be binary (``BIN``)
21 are left unchanged. Additionally, ``native`` is an alias for the
21 are left unchanged. Additionally, ``native`` is an alias for the
22 platform's default line ending: ``LF`` on Unix (including Mac OS X)
22 platform's default line ending: ``LF`` on Unix (including Mac OS X)
23 and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line
23 and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line
24 endings) is Mercurial's default behaviour; it is only needed if you
24 endings) is Mercurial's default behaviour; it is only needed if you
25 need to override a later, more general pattern.
25 need to override a later, more general pattern.
26
26
27 The optional ``[repository]`` section specifies the line endings to
27 The optional ``[repository]`` section specifies the line endings to
28 use for files stored in the repository. It has a single setting,
28 use for files stored in the repository. It has a single setting,
29 ``native``, which determines the storage line endings for files
29 ``native``, which determines the storage line endings for files
30 declared as ``native`` in the ``[patterns]`` section. It can be set to
30 declared as ``native`` in the ``[patterns]`` section. It can be set to
31 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
31 ``LF`` or ``CRLF``. The default is ``LF``. For example, this means
32 that on Windows, files configured as ``native`` (``CRLF`` by default)
32 that on Windows, files configured as ``native`` (``CRLF`` by default)
33 will be converted to ``LF`` when stored in the repository. Files
33 will be converted to ``LF`` when stored in the repository. Files
34 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
34 declared as ``LF``, ``CRLF``, or ``BIN`` in the ``[patterns]`` section
35 are always stored as-is in the repository.
35 are always stored as-is in the repository.
36
36
37 Example versioned ``.hgeol`` file::
37 Example versioned ``.hgeol`` file::
38
38
39 [patterns]
39 [patterns]
40 **.py = native
40 **.py = native
41 **.vcproj = CRLF
41 **.vcproj = CRLF
42 **.txt = native
42 **.txt = native
43 Makefile = LF
43 Makefile = LF
44 **.jpg = BIN
44 **.jpg = BIN
45
45
46 [repository]
46 [repository]
47 native = LF
47 native = LF
48
48
49 The extension uses an optional ``[eol]`` section in your hgrc file
49 The extension uses an optional ``[eol]`` section in your hgrc file
50 (not the ``.hgeol`` file) for settings that control the overall
50 (not the ``.hgeol`` file) for settings that control the overall
51 behavior. There are two settings:
51 behavior. There are two settings:
52
52
53 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
53 - ``eol.native`` (default ``os.linesep``) can be set to ``LF`` or
54 ``CRLF`` override the default interpretation of ``native`` for
54 ``CRLF`` to override the default interpretation of ``native`` for
55 checkout. This can be used with :hg:`archive` on Unix, say, to
55 checkout. This can be used with :hg:`archive` on Unix, say, to
56 generate an archive where files have line endings for Windows.
56 generate an archive where files have line endings for Windows.
57
57
58 - ``eol.only-consistent`` (default True) can be set to False to make
58 - ``eol.only-consistent`` (default True) can be set to False to make
59 the extension convert files with inconsistent EOLs. Inconsistent
59 the extension convert files with inconsistent EOLs. Inconsistent
60 means that there is both ``CRLF`` and ``LF`` present in the file.
60 means that there is both ``CRLF`` and ``LF`` present in the file.
61 Such files are normally not touched under the assumption that they
61 Such files are normally not touched under the assumption that they
62 have mixed EOLs on purpose.
62 have mixed EOLs on purpose.
63
63
64 See :hg:`help patterns` for more information about the glob patterns
64 See :hg:`help patterns` for more information about the glob patterns
65 used.
65 used.
66 """
66 """
67
67
68 from mercurial.i18n import _
68 from mercurial.i18n import _
69 from mercurial import util, config, extensions, match
69 from mercurial import util, config, extensions, match
70 import re, os
70 import re, os
71
71
72 # Matches a lone LF, i.e., one that is not part of CRLF.
72 # Matches a lone LF, i.e., one that is not part of CRLF.
73 singlelf = re.compile('(^|[^\r])\n')
73 singlelf = re.compile('(^|[^\r])\n')
74 # Matches a single EOL which can either be a CRLF where repeated CR
74 # Matches a single EOL which can either be a CRLF where repeated CR
75 # are removed or a LF. We do not care about old Machintosh files, so a
75 # are removed or a LF. We do not care about old Machintosh files, so a
76 # stray CR is an error.
76 # stray CR is an error.
77 eolre = re.compile('\r*\n')
77 eolre = re.compile('\r*\n')
78
78
79
79
80 def inconsistenteol(data):
80 def inconsistenteol(data):
81 return '\r\n' in data and singlelf.search(data)
81 return '\r\n' in data and singlelf.search(data)
82
82
83 def tolf(s, params, ui, **kwargs):
83 def tolf(s, params, ui, **kwargs):
84 """Filter to convert to LF EOLs."""
84 """Filter to convert to LF EOLs."""
85 if util.binary(s):
85 if util.binary(s):
86 return s
86 return s
87 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
87 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
88 return s
88 return s
89 return eolre.sub('\n', s)
89 return eolre.sub('\n', s)
90
90
91 def tocrlf(s, params, ui, **kwargs):
91 def tocrlf(s, params, ui, **kwargs):
92 """Filter to convert to CRLF EOLs."""
92 """Filter to convert to CRLF EOLs."""
93 if util.binary(s):
93 if util.binary(s):
94 return s
94 return s
95 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
95 if ui.configbool('eol', 'only-consistent', True) and inconsistenteol(s):
96 return s
96 return s
97 return eolre.sub('\r\n', s)
97 return eolre.sub('\r\n', s)
98
98
99 def isbinary(s, params):
99 def isbinary(s, params):
100 """Filter to do nothing with the file."""
100 """Filter to do nothing with the file."""
101 return s
101 return s
102
102
103 filters = {
103 filters = {
104 'to-lf': tolf,
104 'to-lf': tolf,
105 'to-crlf': tocrlf,
105 'to-crlf': tocrlf,
106 'is-binary': isbinary,
106 'is-binary': isbinary,
107 }
107 }
108
108
109
109
110 def hook(ui, repo, node, hooktype, **kwargs):
110 def hook(ui, repo, node, hooktype, **kwargs):
111 """verify that files have expected EOLs"""
111 """verify that files have expected EOLs"""
112 files = set()
112 files = set()
113 for rev in xrange(repo[node].rev(), len(repo)):
113 for rev in xrange(repo[node].rev(), len(repo)):
114 files.update(repo[rev].files())
114 files.update(repo[rev].files())
115 tip = repo['tip']
115 tip = repo['tip']
116 for f in files:
116 for f in files:
117 if f not in tip:
117 if f not in tip:
118 continue
118 continue
119 for pattern, target in ui.configitems('encode'):
119 for pattern, target in ui.configitems('encode'):
120 if match.match(repo.root, '', [pattern])(f):
120 if match.match(repo.root, '', [pattern])(f):
121 data = tip[f].data()
121 data = tip[f].data()
122 if target == "to-lf" and "\r\n" in data:
122 if target == "to-lf" and "\r\n" in data:
123 raise util.Abort(_("%s should not have CRLF line endings")
123 raise util.Abort(_("%s should not have CRLF line endings")
124 % f)
124 % f)
125 elif target == "to-crlf" and singlelf.search(data):
125 elif target == "to-crlf" and singlelf.search(data):
126 raise util.Abort(_("%s should not have LF line endings")
126 raise util.Abort(_("%s should not have LF line endings")
127 % f)
127 % f)
128
128
129
129
130 def preupdate(ui, repo, hooktype, parent1, parent2):
130 def preupdate(ui, repo, hooktype, parent1, parent2):
131 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
131 #print "preupdate for %s: %s -> %s" % (repo.root, parent1, parent2)
132 repo.readhgeol(parent1)
132 repo.readhgeol(parent1)
133 return False
133 return False
134
134
135 def uisetup(ui):
135 def uisetup(ui):
136 ui.setconfig('hooks', 'preupdate.eol', preupdate)
136 ui.setconfig('hooks', 'preupdate.eol', preupdate)
137
137
138 def extsetup(ui):
138 def extsetup(ui):
139 try:
139 try:
140 extensions.find('win32text')
140 extensions.find('win32text')
141 raise util.Abort(_("the eol extension is incompatible with the "
141 raise util.Abort(_("the eol extension is incompatible with the "
142 "win32text extension"))
142 "win32text extension"))
143 except KeyError:
143 except KeyError:
144 pass
144 pass
145
145
146
146
147 def reposetup(ui, repo):
147 def reposetup(ui, repo):
148 uisetup(repo.ui)
148 uisetup(repo.ui)
149 #print "reposetup for", repo.root
149 #print "reposetup for", repo.root
150
150
151 if not repo.local():
151 if not repo.local():
152 return
152 return
153 for name, fn in filters.iteritems():
153 for name, fn in filters.iteritems():
154 repo.adddatafilter(name, fn)
154 repo.adddatafilter(name, fn)
155
155
156 ui.setconfig('patch', 'eol', 'auto')
156 ui.setconfig('patch', 'eol', 'auto')
157
157
158 class eolrepo(repo.__class__):
158 class eolrepo(repo.__class__):
159
159
160 _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
160 _decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
161 _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
161 _encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'}
162
162
163 def readhgeol(self, node=None, data=None):
163 def readhgeol(self, node=None, data=None):
164 if data is None:
164 if data is None:
165 try:
165 try:
166 if node is None:
166 if node is None:
167 data = self.wfile('.hgeol').read()
167 data = self.wfile('.hgeol').read()
168 else:
168 else:
169 data = self[node]['.hgeol'].data()
169 data = self[node]['.hgeol'].data()
170 except (IOError, LookupError):
170 except (IOError, LookupError):
171 return None
171 return None
172
172
173 if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
173 if self.ui.config('eol', 'native', os.linesep) in ('LF', '\n'):
174 self._decode['NATIVE'] = 'to-lf'
174 self._decode['NATIVE'] = 'to-lf'
175 else:
175 else:
176 self._decode['NATIVE'] = 'to-crlf'
176 self._decode['NATIVE'] = 'to-crlf'
177
177
178 eol = config.config()
178 eol = config.config()
179 eol.parse('.hgeol', data)
179 eol.parse('.hgeol', data)
180
180
181 if eol.get('repository', 'native') == 'CRLF':
181 if eol.get('repository', 'native') == 'CRLF':
182 self._encode['NATIVE'] = 'to-crlf'
182 self._encode['NATIVE'] = 'to-crlf'
183 else:
183 else:
184 self._encode['NATIVE'] = 'to-lf'
184 self._encode['NATIVE'] = 'to-lf'
185
185
186 for pattern, style in eol.items('patterns'):
186 for pattern, style in eol.items('patterns'):
187 key = style.upper()
187 key = style.upper()
188 try:
188 try:
189 self.ui.setconfig('decode', pattern, self._decode[key])
189 self.ui.setconfig('decode', pattern, self._decode[key])
190 self.ui.setconfig('encode', pattern, self._encode[key])
190 self.ui.setconfig('encode', pattern, self._encode[key])
191 except KeyError:
191 except KeyError:
192 self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
192 self.ui.warn(_("ignoring unknown EOL style '%s' from %s\n")
193 % (style, eol.source('patterns', pattern)))
193 % (style, eol.source('patterns', pattern)))
194
194
195 include = []
195 include = []
196 exclude = []
196 exclude = []
197 for pattern, style in eol.items('patterns'):
197 for pattern, style in eol.items('patterns'):
198 key = style.upper()
198 key = style.upper()
199 if key == 'BIN':
199 if key == 'BIN':
200 exclude.append(pattern)
200 exclude.append(pattern)
201 else:
201 else:
202 include.append(pattern)
202 include.append(pattern)
203
203
204 # This will match the files for which we need to care
204 # This will match the files for which we need to care
205 # about inconsistent newlines.
205 # about inconsistent newlines.
206 return match.match(self.root, '', [], include, exclude)
206 return match.match(self.root, '', [], include, exclude)
207
207
208 def _hgcleardirstate(self):
208 def _hgcleardirstate(self):
209 self._eolfile = self.readhgeol() or self.readhgeol('tip')
209 self._eolfile = self.readhgeol() or self.readhgeol('tip')
210
210
211 if not self._eolfile:
211 if not self._eolfile:
212 self._eolfile = util.never
212 self._eolfile = util.never
213 return
213 return
214
214
215 try:
215 try:
216 cachemtime = os.path.getmtime(self.join("eol.cache"))
216 cachemtime = os.path.getmtime(self.join("eol.cache"))
217 except OSError:
217 except OSError:
218 cachemtime = 0
218 cachemtime = 0
219
219
220 try:
220 try:
221 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
221 eolmtime = os.path.getmtime(self.wjoin(".hgeol"))
222 except OSError:
222 except OSError:
223 eolmtime = 0
223 eolmtime = 0
224
224
225 if eolmtime > cachemtime:
225 if eolmtime > cachemtime:
226 ui.debug("eol: detected change in .hgeol\n")
226 ui.debug("eol: detected change in .hgeol\n")
227 # TODO: we could introduce a method for this in dirstate.
227 # TODO: we could introduce a method for this in dirstate.
228 wlock = None
228 wlock = None
229 try:
229 try:
230 wlock = self.wlock()
230 wlock = self.wlock()
231 for f, e in self.dirstate._map.iteritems():
231 for f, e in self.dirstate._map.iteritems():
232 self.dirstate._map[f] = (e[0], e[1], -1, 0)
232 self.dirstate._map[f] = (e[0], e[1], -1, 0)
233 self.dirstate._dirty = True
233 self.dirstate._dirty = True
234 # Touch the cache to update mtime. TODO: are we sure this
234 # Touch the cache to update mtime. TODO: are we sure this
235 # always enought to update the mtime, or should we write a
235 # always enought to update the mtime, or should we write a
236 # bit to the file?
236 # bit to the file?
237 self.opener("eol.cache", "w").close()
237 self.opener("eol.cache", "w").close()
238 finally:
238 finally:
239 if wlock is not None:
239 if wlock is not None:
240 wlock.release()
240 wlock.release()
241
241
242 def commitctx(self, ctx, error=False):
242 def commitctx(self, ctx, error=False):
243 for f in sorted(ctx.added() + ctx.modified()):
243 for f in sorted(ctx.added() + ctx.modified()):
244 if not self._eolfile(f):
244 if not self._eolfile(f):
245 continue
245 continue
246 data = ctx[f].data()
246 data = ctx[f].data()
247 if util.binary(data):
247 if util.binary(data):
248 # We should not abort here, since the user should
248 # We should not abort here, since the user should
249 # be able to say "** = native" to automatically
249 # be able to say "** = native" to automatically
250 # have all non-binary files taken care of.
250 # have all non-binary files taken care of.
251 continue
251 continue
252 if inconsistenteol(data):
252 if inconsistenteol(data):
253 raise util.Abort(_("inconsistent newline style "
253 raise util.Abort(_("inconsistent newline style "
254 "in %s\n" % f))
254 "in %s\n" % f))
255 return super(eolrepo, self).commitctx(ctx, error)
255 return super(eolrepo, self).commitctx(ctx, error)
256 repo.__class__ = eolrepo
256 repo.__class__ = eolrepo
257 repo._hgcleardirstate()
257 repo._hgcleardirstate()
@@ -1,4479 +1,4489 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, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, util, revlog, extensions, copies, error
12 import hg, util, revlog, extensions, copies, error
13 import patch, help, mdiff, url, encoding, templatekw, discovery
13 import patch, help, mdiff, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset
16 import minirst, revset
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 .hgignore. As with add, these changes take effect at the next
61 .hgignore. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 ctx = repo[opts.get('rev')]
129 ctx = repo[opts.get('rev')]
130 m = cmdutil.match(repo, pats, opts)
130 m = cmdutil.match(repo, pats, opts)
131 follow = not opts.get('no_follow')
131 follow = not opts.get('no_follow')
132 for abs in ctx.walk(m):
132 for abs in ctx.walk(m):
133 fctx = ctx[abs]
133 fctx = ctx[abs]
134 if not opts.get('text') and util.binary(fctx.data()):
134 if not opts.get('text') and util.binary(fctx.data()):
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
135 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
136 continue
136 continue
137
137
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
138 lines = fctx.annotate(follow=follow, linenumber=linenumber)
139 pieces = []
139 pieces = []
140
140
141 for f in funcmap:
141 for f in funcmap:
142 l = [f(n) for n, dummy in lines]
142 l = [f(n) for n, dummy in lines]
143 if l:
143 if l:
144 sized = [(x, encoding.colwidth(x)) for x in l]
144 sized = [(x, encoding.colwidth(x)) for x in l]
145 ml = max([w for x, w in sized])
145 ml = max([w for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
146 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
147
147
148 if pieces:
148 if pieces:
149 for p, l in zip(zip(*pieces), lines):
149 for p, l in zip(zip(*pieces), lines):
150 ui.write("%s: %s" % (" ".join(p), l[1]))
150 ui.write("%s: %s" % (" ".join(p), l[1]))
151
151
152 def archive(ui, repo, dest, **opts):
152 def archive(ui, repo, dest, **opts):
153 '''create an unversioned archive of a repository revision
153 '''create an unversioned archive of a repository revision
154
154
155 By default, the revision used is the parent of the working
155 By default, the revision used is the parent of the working
156 directory; use -r/--rev to specify a different revision.
156 directory; use -r/--rev to specify a different revision.
157
157
158 The archive type is automatically detected based on file
158 The archive type is automatically detected based on file
159 extension (or override using -t/--type).
159 extension (or override using -t/--type).
160
160
161 Valid types are:
161 Valid types are:
162
162
163 :``files``: a directory full of files (default)
163 :``files``: a directory full of files (default)
164 :``tar``: tar archive, uncompressed
164 :``tar``: tar archive, uncompressed
165 :``tbz2``: tar archive, compressed using bzip2
165 :``tbz2``: tar archive, compressed using bzip2
166 :``tgz``: tar archive, compressed using gzip
166 :``tgz``: tar archive, compressed using gzip
167 :``uzip``: zip archive, uncompressed
167 :``uzip``: zip archive, uncompressed
168 :``zip``: zip archive, compressed using deflate
168 :``zip``: zip archive, compressed using deflate
169
169
170 The exact name of the destination archive or directory is given
170 The exact name of the destination archive or directory is given
171 using a format string; see :hg:`help export` for details.
171 using a format string; see :hg:`help export` for details.
172
172
173 Each member added to an archive file has a directory prefix
173 Each member added to an archive file has a directory prefix
174 prepended. Use -p/--prefix to specify a format string for the
174 prepended. Use -p/--prefix to specify a format string for the
175 prefix. The default is the basename of the archive, with suffixes
175 prefix. The default is the basename of the archive, with suffixes
176 removed.
176 removed.
177
177
178 Returns 0 on success.
178 Returns 0 on success.
179 '''
179 '''
180
180
181 ctx = repo[opts.get('rev')]
181 ctx = repo[opts.get('rev')]
182 if not ctx:
182 if not ctx:
183 raise util.Abort(_('no working directory: please specify a revision'))
183 raise util.Abort(_('no working directory: please specify a revision'))
184 node = ctx.node()
184 node = ctx.node()
185 dest = cmdutil.make_filename(repo, dest, node)
185 dest = cmdutil.make_filename(repo, dest, node)
186 if os.path.realpath(dest) == repo.root:
186 if os.path.realpath(dest) == repo.root:
187 raise util.Abort(_('repository root cannot be destination'))
187 raise util.Abort(_('repository root cannot be destination'))
188
188
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
189 kind = opts.get('type') or archival.guesskind(dest) or 'files'
190 prefix = opts.get('prefix')
190 prefix = opts.get('prefix')
191
191
192 if dest == '-':
192 if dest == '-':
193 if kind == 'files':
193 if kind == 'files':
194 raise util.Abort(_('cannot archive plain files to stdout'))
194 raise util.Abort(_('cannot archive plain files to stdout'))
195 dest = sys.stdout
195 dest = sys.stdout
196 if not prefix:
196 if not prefix:
197 prefix = os.path.basename(repo.root) + '-%h'
197 prefix = os.path.basename(repo.root) + '-%h'
198
198
199 prefix = cmdutil.make_filename(repo, prefix, node)
199 prefix = cmdutil.make_filename(repo, prefix, node)
200 matchfn = cmdutil.match(repo, [], opts)
200 matchfn = cmdutil.match(repo, [], opts)
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
201 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
202 matchfn, prefix, subrepos=opts.get('subrepos'))
202 matchfn, prefix, subrepos=opts.get('subrepos'))
203
203
204 def backout(ui, repo, node=None, rev=None, **opts):
204 def backout(ui, repo, node=None, rev=None, **opts):
205 '''reverse effect of earlier changeset
205 '''reverse effect of earlier changeset
206
206
207 The backout command merges the reverse effect of the reverted
207 The backout command merges the reverse effect of the reverted
208 changeset into the working directory.
208 changeset into the working directory.
209
209
210 With the --merge option, it first commits the reverted changes
210 With the --merge option, it first commits the reverted changes
211 as a new changeset. This new changeset is a child of the reverted
211 as a new changeset. This new changeset is a child of the reverted
212 changeset.
212 changeset.
213 The --merge option remembers the parent of the working directory
213 The --merge option remembers the parent of the working directory
214 before starting the backout, then merges the new head with that
214 before starting the backout, then merges the new head with that
215 changeset afterwards.
215 changeset afterwards.
216 This will result in an explicit merge in the history.
216 This will result in an explicit merge in the history.
217
217
218 If you backout a changeset other than the original parent of the
218 If you backout a changeset other than the original parent of the
219 working directory, the result of this merge is not committed,
219 working directory, the result of this merge is not committed,
220 as with a normal merge. Otherwise, no merge is needed and the
220 as with a normal merge. Otherwise, no merge is needed and the
221 commit is automatic.
221 commit is automatic.
222
222
223 Note that the default behavior (without --merge) has changed in
223 Note that the default behavior (without --merge) has changed in
224 version 1.7. To restore the previous default behavior, use
224 version 1.7. To restore the previous default behavior, use
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
225 :hg:`backout --merge` and then :hg:`update --clean .` to get rid of
226 the ongoing merge.
226 the ongoing merge.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = repo.lookup(rev)
246 node = repo.lookup(rev)
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
281 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
282
286
283 commit_opts = opts.copy()
287 commit_opts = opts.copy()
284 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
285 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
286 # we don't translate commit messages
290 # we don't translate commit messages
287 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
288 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
289 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
290 def nice(node):
294 def nice(node):
291 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
292 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
293 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
294 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
295 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
296 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
297 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
298 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
299 return 0
307 return 0
300
308
301 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
302 reset=None, good=None, bad=None, skip=None, noupdate=None):
310 reset=None, good=None, bad=None, skip=None, noupdate=None):
303 """subdivision search of changesets
311 """subdivision search of changesets
304
312
305 This command helps to find changesets which introduce problems. To
313 This command helps to find changesets which introduce problems. To
306 use, mark the earliest changeset you know exhibits the problem as
314 use, mark the earliest changeset you know exhibits the problem as
307 bad, then mark the latest changeset which is free from the problem
315 bad, then mark the latest changeset which is free from the problem
308 as good. Bisect will update your working directory to a revision
316 as good. Bisect will update your working directory to a revision
309 for testing (unless the -U/--noupdate option is specified). Once
317 for testing (unless the -U/--noupdate option is specified). Once
310 you have performed tests, mark the working directory as good or
318 you have performed tests, mark the working directory as good or
311 bad, and bisect will either update to another candidate changeset
319 bad, and bisect will either update to another candidate changeset
312 or announce that it has found the bad revision.
320 or announce that it has found the bad revision.
313
321
314 As a shortcut, you can also use the revision argument to mark a
322 As a shortcut, you can also use the revision argument to mark a
315 revision as good or bad without checking it out first.
323 revision as good or bad without checking it out first.
316
324
317 If you supply a command, it will be used for automatic bisection.
325 If you supply a command, it will be used for automatic bisection.
318 Its exit status will be used to mark revisions as good or bad:
326 Its exit status will be used to mark revisions as good or bad:
319 status 0 means good, 125 means to skip the revision, 127
327 status 0 means good, 125 means to skip the revision, 127
320 (command not found) will abort the bisection, and any other
328 (command not found) will abort the bisection, and any other
321 non-zero exit status means the revision is bad.
329 non-zero exit status means the revision is bad.
322
330
323 Returns 0 on success.
331 Returns 0 on success.
324 """
332 """
325 def print_result(nodes, good):
333 def print_result(nodes, good):
326 displayer = cmdutil.show_changeset(ui, repo, {})
334 displayer = cmdutil.show_changeset(ui, repo, {})
327 if len(nodes) == 1:
335 if len(nodes) == 1:
328 # narrowed it down to a single revision
336 # narrowed it down to a single revision
329 if good:
337 if good:
330 ui.write(_("The first good revision is:\n"))
338 ui.write(_("The first good revision is:\n"))
331 else:
339 else:
332 ui.write(_("The first bad revision is:\n"))
340 ui.write(_("The first bad revision is:\n"))
333 displayer.show(repo[nodes[0]])
341 displayer.show(repo[nodes[0]])
334 parents = repo[nodes[0]].parents()
342 parents = repo[nodes[0]].parents()
335 if len(parents) > 1:
343 if len(parents) > 1:
336 side = good and state['bad'] or state['good']
344 side = good and state['bad'] or state['good']
337 num = len(set(i.node() for i in parents) & set(side))
345 num = len(set(i.node() for i in parents) & set(side))
338 if num == 1:
346 if num == 1:
339 common = parents[0].ancestor(parents[1])
347 common = parents[0].ancestor(parents[1])
340 ui.write(_('Not all ancestors of this changeset have been'
348 ui.write(_('Not all ancestors of this changeset have been'
341 ' checked.\nTo check the other ancestors, start'
349 ' checked.\nTo check the other ancestors, start'
342 ' from the common ancestor, %s.\n' % common))
350 ' from the common ancestor, %s.\n' % common))
343 else:
351 else:
344 # multiple possible revisions
352 # multiple possible revisions
345 if good:
353 if good:
346 ui.write(_("Due to skipped revisions, the first "
354 ui.write(_("Due to skipped revisions, the first "
347 "good revision could be any of:\n"))
355 "good revision could be any of:\n"))
348 else:
356 else:
349 ui.write(_("Due to skipped revisions, the first "
357 ui.write(_("Due to skipped revisions, the first "
350 "bad revision could be any of:\n"))
358 "bad revision could be any of:\n"))
351 for n in nodes:
359 for n in nodes:
352 displayer.show(repo[n])
360 displayer.show(repo[n])
353 displayer.close()
361 displayer.close()
354
362
355 def check_state(state, interactive=True):
363 def check_state(state, interactive=True):
356 if not state['good'] or not state['bad']:
364 if not state['good'] or not state['bad']:
357 if (good or bad or skip or reset) and interactive:
365 if (good or bad or skip or reset) and interactive:
358 return
366 return
359 if not state['good']:
367 if not state['good']:
360 raise util.Abort(_('cannot bisect (no known good revisions)'))
368 raise util.Abort(_('cannot bisect (no known good revisions)'))
361 else:
369 else:
362 raise util.Abort(_('cannot bisect (no known bad revisions)'))
370 raise util.Abort(_('cannot bisect (no known bad revisions)'))
363 return True
371 return True
364
372
365 # backward compatibility
373 # backward compatibility
366 if rev in "good bad reset init".split():
374 if rev in "good bad reset init".split():
367 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
375 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
368 cmd, rev, extra = rev, extra, None
376 cmd, rev, extra = rev, extra, None
369 if cmd == "good":
377 if cmd == "good":
370 good = True
378 good = True
371 elif cmd == "bad":
379 elif cmd == "bad":
372 bad = True
380 bad = True
373 else:
381 else:
374 reset = True
382 reset = True
375 elif extra or good + bad + skip + reset + bool(command) > 1:
383 elif extra or good + bad + skip + reset + bool(command) > 1:
376 raise util.Abort(_('incompatible arguments'))
384 raise util.Abort(_('incompatible arguments'))
377
385
378 if reset:
386 if reset:
379 p = repo.join("bisect.state")
387 p = repo.join("bisect.state")
380 if os.path.exists(p):
388 if os.path.exists(p):
381 os.unlink(p)
389 os.unlink(p)
382 return
390 return
383
391
384 state = hbisect.load_state(repo)
392 state = hbisect.load_state(repo)
385
393
386 if command:
394 if command:
387 changesets = 1
395 changesets = 1
388 try:
396 try:
389 while changesets:
397 while changesets:
390 # update state
398 # update state
391 status = util.system(command)
399 status = util.system(command)
392 if status == 125:
400 if status == 125:
393 transition = "skip"
401 transition = "skip"
394 elif status == 0:
402 elif status == 0:
395 transition = "good"
403 transition = "good"
396 # status < 0 means process was killed
404 # status < 0 means process was killed
397 elif status == 127:
405 elif status == 127:
398 raise util.Abort(_("failed to execute %s") % command)
406 raise util.Abort(_("failed to execute %s") % command)
399 elif status < 0:
407 elif status < 0:
400 raise util.Abort(_("%s killed") % command)
408 raise util.Abort(_("%s killed") % command)
401 else:
409 else:
402 transition = "bad"
410 transition = "bad"
403 ctx = repo[rev or '.']
411 ctx = repo[rev or '.']
404 state[transition].append(ctx.node())
412 state[transition].append(ctx.node())
405 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
413 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
406 check_state(state, interactive=False)
414 check_state(state, interactive=False)
407 # bisect
415 # bisect
408 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
416 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
409 # update to next check
417 # update to next check
410 cmdutil.bail_if_changed(repo)
418 cmdutil.bail_if_changed(repo)
411 hg.clean(repo, nodes[0], show_stats=False)
419 hg.clean(repo, nodes[0], show_stats=False)
412 finally:
420 finally:
413 hbisect.save_state(repo, state)
421 hbisect.save_state(repo, state)
414 print_result(nodes, good)
422 print_result(nodes, good)
415 return
423 return
416
424
417 # update state
425 # update state
418
426
419 if rev:
427 if rev:
420 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
428 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
421 else:
429 else:
422 nodes = [repo.lookup('.')]
430 nodes = [repo.lookup('.')]
423
431
424 if good or bad or skip:
432 if good or bad or skip:
425 if good:
433 if good:
426 state['good'] += nodes
434 state['good'] += nodes
427 elif bad:
435 elif bad:
428 state['bad'] += nodes
436 state['bad'] += nodes
429 elif skip:
437 elif skip:
430 state['skip'] += nodes
438 state['skip'] += nodes
431 hbisect.save_state(repo, state)
439 hbisect.save_state(repo, state)
432
440
433 if not check_state(state):
441 if not check_state(state):
434 return
442 return
435
443
436 # actually bisect
444 # actually bisect
437 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
445 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
438 if changesets == 0:
446 if changesets == 0:
439 print_result(nodes, good)
447 print_result(nodes, good)
440 else:
448 else:
441 assert len(nodes) == 1 # only a single node can be tested next
449 assert len(nodes) == 1 # only a single node can be tested next
442 node = nodes[0]
450 node = nodes[0]
443 # compute the approximate number of remaining tests
451 # compute the approximate number of remaining tests
444 tests, size = 0, 2
452 tests, size = 0, 2
445 while size <= changesets:
453 while size <= changesets:
446 tests, size = tests + 1, size * 2
454 tests, size = tests + 1, size * 2
447 rev = repo.changelog.rev(node)
455 rev = repo.changelog.rev(node)
448 ui.write(_("Testing changeset %d:%s "
456 ui.write(_("Testing changeset %d:%s "
449 "(%d changesets remaining, ~%d tests)\n")
457 "(%d changesets remaining, ~%d tests)\n")
450 % (rev, short(node), changesets, tests))
458 % (rev, short(node), changesets, tests))
451 if not noupdate:
459 if not noupdate:
452 cmdutil.bail_if_changed(repo)
460 cmdutil.bail_if_changed(repo)
453 return hg.clean(repo, node)
461 return hg.clean(repo, node)
454
462
455 def branch(ui, repo, label=None, **opts):
463 def branch(ui, repo, label=None, **opts):
456 """set or show the current branch name
464 """set or show the current branch name
457
465
458 With no argument, show the current branch name. With one argument,
466 With no argument, show the current branch name. With one argument,
459 set the working directory branch name (the branch will not exist
467 set the working directory branch name (the branch will not exist
460 in the repository until the next commit). Standard practice
468 in the repository until the next commit). Standard practice
461 recommends that primary development take place on the 'default'
469 recommends that primary development take place on the 'default'
462 branch.
470 branch.
463
471
464 Unless -f/--force is specified, branch will not let you set a
472 Unless -f/--force is specified, branch will not let you set a
465 branch name that already exists, even if it's inactive.
473 branch name that already exists, even if it's inactive.
466
474
467 Use -C/--clean to reset the working directory branch to that of
475 Use -C/--clean to reset the working directory branch to that of
468 the parent of the working directory, negating a previous branch
476 the parent of the working directory, negating a previous branch
469 change.
477 change.
470
478
471 Use the command :hg:`update` to switch to an existing branch. Use
479 Use the command :hg:`update` to switch to an existing branch. Use
472 :hg:`commit --close-branch` to mark this branch as closed.
480 :hg:`commit --close-branch` to mark this branch as closed.
473
481
474 Returns 0 on success.
482 Returns 0 on success.
475 """
483 """
476
484
477 if opts.get('clean'):
485 if opts.get('clean'):
478 label = repo[None].parents()[0].branch()
486 label = repo[None].parents()[0].branch()
479 repo.dirstate.setbranch(label)
487 repo.dirstate.setbranch(label)
480 ui.status(_('reset working directory to branch %s\n') % label)
488 ui.status(_('reset working directory to branch %s\n') % label)
481 elif label:
489 elif label:
482 utflabel = encoding.fromlocal(label)
490 utflabel = encoding.fromlocal(label)
483 if not opts.get('force') and utflabel in repo.branchtags():
491 if not opts.get('force') and utflabel in repo.branchtags():
484 if label not in [p.branch() for p in repo.parents()]:
492 if label not in [p.branch() for p in repo.parents()]:
485 raise util.Abort(_('a branch of the same name already exists'
493 raise util.Abort(_('a branch of the same name already exists'
486 " (use 'hg update' to switch to it)"))
494 " (use 'hg update' to switch to it)"))
487 repo.dirstate.setbranch(utflabel)
495 repo.dirstate.setbranch(utflabel)
488 ui.status(_('marked working directory as branch %s\n') % label)
496 ui.status(_('marked working directory as branch %s\n') % label)
489 else:
497 else:
490 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
498 ui.write("%s\n" % encoding.tolocal(repo.dirstate.branch()))
491
499
492 def branches(ui, repo, active=False, closed=False):
500 def branches(ui, repo, active=False, closed=False):
493 """list repository named branches
501 """list repository named branches
494
502
495 List the repository's named branches, indicating which ones are
503 List the repository's named branches, indicating which ones are
496 inactive. If -c/--closed is specified, also list branches which have
504 inactive. If -c/--closed is specified, also list branches which have
497 been marked closed (see :hg:`commit --close-branch`).
505 been marked closed (see :hg:`commit --close-branch`).
498
506
499 If -a/--active is specified, only show active branches. A branch
507 If -a/--active is specified, only show active branches. A branch
500 is considered active if it contains repository heads.
508 is considered active if it contains repository heads.
501
509
502 Use the command :hg:`update` to switch to an existing branch.
510 Use the command :hg:`update` to switch to an existing branch.
503
511
504 Returns 0.
512 Returns 0.
505 """
513 """
506
514
507 hexfunc = ui.debugflag and hex or short
515 hexfunc = ui.debugflag and hex or short
508 activebranches = [repo[n].branch() for n in repo.heads()]
516 activebranches = [repo[n].branch() for n in repo.heads()]
509 def testactive(tag, node):
517 def testactive(tag, node):
510 realhead = tag in activebranches
518 realhead = tag in activebranches
511 open = node in repo.branchheads(tag, closed=False)
519 open = node in repo.branchheads(tag, closed=False)
512 return realhead and open
520 return realhead and open
513 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
521 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
514 for tag, node in repo.branchtags().items()],
522 for tag, node in repo.branchtags().items()],
515 reverse=True)
523 reverse=True)
516
524
517 for isactive, node, tag in branches:
525 for isactive, node, tag in branches:
518 if (not active) or isactive:
526 if (not active) or isactive:
519 encodedtag = encoding.tolocal(tag)
527 encodedtag = encoding.tolocal(tag)
520 if ui.quiet:
528 if ui.quiet:
521 ui.write("%s\n" % encodedtag)
529 ui.write("%s\n" % encodedtag)
522 else:
530 else:
523 hn = repo.lookup(node)
531 hn = repo.lookup(node)
524 if isactive:
532 if isactive:
525 label = 'branches.active'
533 label = 'branches.active'
526 notice = ''
534 notice = ''
527 elif hn not in repo.branchheads(tag, closed=False):
535 elif hn not in repo.branchheads(tag, closed=False):
528 if not closed:
536 if not closed:
529 continue
537 continue
530 label = 'branches.closed'
538 label = 'branches.closed'
531 notice = _(' (closed)')
539 notice = _(' (closed)')
532 else:
540 else:
533 label = 'branches.inactive'
541 label = 'branches.inactive'
534 notice = _(' (inactive)')
542 notice = _(' (inactive)')
535 if tag == repo.dirstate.branch():
543 if tag == repo.dirstate.branch():
536 label = 'branches.current'
544 label = 'branches.current'
537 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
545 rev = str(node).rjust(31 - encoding.colwidth(encodedtag))
538 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
546 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
539 encodedtag = ui.label(encodedtag, label)
547 encodedtag = ui.label(encodedtag, label)
540 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
548 ui.write("%s %s%s\n" % (encodedtag, rev, notice))
541
549
542 def bundle(ui, repo, fname, dest=None, **opts):
550 def bundle(ui, repo, fname, dest=None, **opts):
543 """create a changegroup file
551 """create a changegroup file
544
552
545 Generate a compressed changegroup file collecting changesets not
553 Generate a compressed changegroup file collecting changesets not
546 known to be in another repository.
554 known to be in another repository.
547
555
548 If you omit the destination repository, then hg assumes the
556 If you omit the destination repository, then hg assumes the
549 destination will have all the nodes you specify with --base
557 destination will have all the nodes you specify with --base
550 parameters. To create a bundle containing all changesets, use
558 parameters. To create a bundle containing all changesets, use
551 -a/--all (or --base null).
559 -a/--all (or --base null).
552
560
553 You can change compression method with the -t/--type option.
561 You can change compression method with the -t/--type option.
554 The available compression methods are: none, bzip2, and
562 The available compression methods are: none, bzip2, and
555 gzip (by default, bundles are compressed using bzip2).
563 gzip (by default, bundles are compressed using bzip2).
556
564
557 The bundle file can then be transferred using conventional means
565 The bundle file can then be transferred using conventional means
558 and applied to another repository with the unbundle or pull
566 and applied to another repository with the unbundle or pull
559 command. This is useful when direct push and pull are not
567 command. This is useful when direct push and pull are not
560 available or when exporting an entire repository is undesirable.
568 available or when exporting an entire repository is undesirable.
561
569
562 Applying bundles preserves all changeset contents including
570 Applying bundles preserves all changeset contents including
563 permissions, copy/rename information, and revision history.
571 permissions, copy/rename information, and revision history.
564
572
565 Returns 0 on success, 1 if no changes found.
573 Returns 0 on success, 1 if no changes found.
566 """
574 """
567 revs = opts.get('rev') or None
575 revs = opts.get('rev') or None
568 if opts.get('all'):
576 if opts.get('all'):
569 base = ['null']
577 base = ['null']
570 else:
578 else:
571 base = opts.get('base')
579 base = opts.get('base')
572 if base:
580 if base:
573 if dest:
581 if dest:
574 raise util.Abort(_("--base is incompatible with specifying "
582 raise util.Abort(_("--base is incompatible with specifying "
575 "a destination"))
583 "a destination"))
576 base = [repo.lookup(rev) for rev in base]
584 base = [repo.lookup(rev) for rev in base]
577 # create the right base
585 # create the right base
578 # XXX: nodesbetween / changegroup* should be "fixed" instead
586 # XXX: nodesbetween / changegroup* should be "fixed" instead
579 o = []
587 o = []
580 has = set((nullid,))
588 has = set((nullid,))
581 for n in base:
589 for n in base:
582 has.update(repo.changelog.reachable(n))
590 has.update(repo.changelog.reachable(n))
583 if revs:
591 if revs:
584 revs = [repo.lookup(rev) for rev in revs]
592 revs = [repo.lookup(rev) for rev in revs]
585 visit = revs[:]
593 visit = revs[:]
586 has.difference_update(visit)
594 has.difference_update(visit)
587 else:
595 else:
588 visit = repo.changelog.heads()
596 visit = repo.changelog.heads()
589 seen = {}
597 seen = {}
590 while visit:
598 while visit:
591 n = visit.pop(0)
599 n = visit.pop(0)
592 parents = [p for p in repo.changelog.parents(n) if p not in has]
600 parents = [p for p in repo.changelog.parents(n) if p not in has]
593 if len(parents) == 0:
601 if len(parents) == 0:
594 if n not in has:
602 if n not in has:
595 o.append(n)
603 o.append(n)
596 else:
604 else:
597 for p in parents:
605 for p in parents:
598 if p not in seen:
606 if p not in seen:
599 seen[p] = 1
607 seen[p] = 1
600 visit.append(p)
608 visit.append(p)
601 else:
609 else:
602 dest = ui.expandpath(dest or 'default-push', dest or 'default')
610 dest = ui.expandpath(dest or 'default-push', dest or 'default')
603 dest, branches = hg.parseurl(dest, opts.get('branch'))
611 dest, branches = hg.parseurl(dest, opts.get('branch'))
604 other = hg.repository(hg.remoteui(repo, opts), dest)
612 other = hg.repository(hg.remoteui(repo, opts), dest)
605 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
613 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
606 if revs:
614 if revs:
607 revs = [repo.lookup(rev) for rev in revs]
615 revs = [repo.lookup(rev) for rev in revs]
608 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
616 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
609
617
610 if not o:
618 if not o:
611 ui.status(_("no changes found\n"))
619 ui.status(_("no changes found\n"))
612 return 1
620 return 1
613
621
614 if revs:
622 if revs:
615 cg = repo.changegroupsubset(o, revs, 'bundle')
623 cg = repo.changegroupsubset(o, revs, 'bundle')
616 else:
624 else:
617 cg = repo.changegroup(o, 'bundle')
625 cg = repo.changegroup(o, 'bundle')
618
626
619 bundletype = opts.get('type', 'bzip2').lower()
627 bundletype = opts.get('type', 'bzip2').lower()
620 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
628 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
621 bundletype = btypes.get(bundletype)
629 bundletype = btypes.get(bundletype)
622 if bundletype not in changegroup.bundletypes:
630 if bundletype not in changegroup.bundletypes:
623 raise util.Abort(_('unknown bundle type specified with --type'))
631 raise util.Abort(_('unknown bundle type specified with --type'))
624
632
625 changegroup.writebundle(cg, fname, bundletype)
633 changegroup.writebundle(cg, fname, bundletype)
626
634
627 def cat(ui, repo, file1, *pats, **opts):
635 def cat(ui, repo, file1, *pats, **opts):
628 """output the current or given revision of files
636 """output the current or given revision of files
629
637
630 Print the specified files as they were at the given revision. If
638 Print the specified files as they were at the given revision. If
631 no revision is given, the parent of the working directory is used,
639 no revision is given, the parent of the working directory is used,
632 or tip if no revision is checked out.
640 or tip if no revision is checked out.
633
641
634 Output may be to a file, in which case the name of the file is
642 Output may be to a file, in which case the name of the file is
635 given using a format string. The formatting rules are the same as
643 given using a format string. The formatting rules are the same as
636 for the export command, with the following additions:
644 for the export command, with the following additions:
637
645
638 :``%s``: basename of file being printed
646 :``%s``: basename of file being printed
639 :``%d``: dirname of file being printed, or '.' if in repository root
647 :``%d``: dirname of file being printed, or '.' if in repository root
640 :``%p``: root-relative path name of file being printed
648 :``%p``: root-relative path name of file being printed
641
649
642 Returns 0 on success.
650 Returns 0 on success.
643 """
651 """
644 ctx = cmdutil.revsingle(repo, opts.get('rev'))
652 ctx = cmdutil.revsingle(repo, opts.get('rev'))
645 err = 1
653 err = 1
646 m = cmdutil.match(repo, (file1,) + pats, opts)
654 m = cmdutil.match(repo, (file1,) + pats, opts)
647 for abs in ctx.walk(m):
655 for abs in ctx.walk(m):
648 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
656 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
649 data = ctx[abs].data()
657 data = ctx[abs].data()
650 if opts.get('decode'):
658 if opts.get('decode'):
651 data = repo.wwritedata(abs, data)
659 data = repo.wwritedata(abs, data)
652 fp.write(data)
660 fp.write(data)
653 err = 0
661 err = 0
654 return err
662 return err
655
663
656 def clone(ui, source, dest=None, **opts):
664 def clone(ui, source, dest=None, **opts):
657 """make a copy of an existing repository
665 """make a copy of an existing repository
658
666
659 Create a copy of an existing repository in a new directory.
667 Create a copy of an existing repository in a new directory.
660
668
661 If no destination directory name is specified, it defaults to the
669 If no destination directory name is specified, it defaults to the
662 basename of the source.
670 basename of the source.
663
671
664 The location of the source is added to the new repository's
672 The location of the source is added to the new repository's
665 .hg/hgrc file, as the default to be used for future pulls.
673 .hg/hgrc file, as the default to be used for future pulls.
666
674
667 See :hg:`help urls` for valid source format details.
675 See :hg:`help urls` for valid source format details.
668
676
669 It is possible to specify an ``ssh://`` URL as the destination, but no
677 It is possible to specify an ``ssh://`` URL as the destination, but no
670 .hg/hgrc and working directory will be created on the remote side.
678 .hg/hgrc and working directory will be created on the remote side.
671 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
679 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
672
680
673 A set of changesets (tags, or branch names) to pull may be specified
681 A set of changesets (tags, or branch names) to pull may be specified
674 by listing each changeset (tag, or branch name) with -r/--rev.
682 by listing each changeset (tag, or branch name) with -r/--rev.
675 If -r/--rev is used, the cloned repository will contain only a subset
683 If -r/--rev is used, the cloned repository will contain only a subset
676 of the changesets of the source repository. Only the set of changesets
684 of the changesets of the source repository. Only the set of changesets
677 defined by all -r/--rev options (including all their ancestors)
685 defined by all -r/--rev options (including all their ancestors)
678 will be pulled into the destination repository.
686 will be pulled into the destination repository.
679 No subsequent changesets (including subsequent tags) will be present
687 No subsequent changesets (including subsequent tags) will be present
680 in the destination.
688 in the destination.
681
689
682 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
690 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
683 local source repositories.
691 local source repositories.
684
692
685 For efficiency, hardlinks are used for cloning whenever the source
693 For efficiency, hardlinks are used for cloning whenever the source
686 and destination are on the same filesystem (note this applies only
694 and destination are on the same filesystem (note this applies only
687 to the repository data, not to the working directory). Some
695 to the repository data, not to the working directory). Some
688 filesystems, such as AFS, implement hardlinking incorrectly, but
696 filesystems, such as AFS, implement hardlinking incorrectly, but
689 do not report errors. In these cases, use the --pull option to
697 do not report errors. In these cases, use the --pull option to
690 avoid hardlinking.
698 avoid hardlinking.
691
699
692 In some cases, you can clone repositories and the working directory
700 In some cases, you can clone repositories and the working directory
693 using full hardlinks with ::
701 using full hardlinks with ::
694
702
695 $ cp -al REPO REPOCLONE
703 $ cp -al REPO REPOCLONE
696
704
697 This is the fastest way to clone, but it is not always safe. The
705 This is the fastest way to clone, but it is not always safe. The
698 operation is not atomic (making sure REPO is not modified during
706 operation is not atomic (making sure REPO is not modified during
699 the operation is up to you) and you have to make sure your editor
707 the operation is up to you) and you have to make sure your editor
700 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
708 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
701 this is not compatible with certain extensions that place their
709 this is not compatible with certain extensions that place their
702 metadata under the .hg directory, such as mq.
710 metadata under the .hg directory, such as mq.
703
711
704 Mercurial will update the working directory to the first applicable
712 Mercurial will update the working directory to the first applicable
705 revision from this list:
713 revision from this list:
706
714
707 a) null if -U or the source repository has no changesets
715 a) null if -U or the source repository has no changesets
708 b) if -u . and the source repository is local, the first parent of
716 b) if -u . and the source repository is local, the first parent of
709 the source repository's working directory
717 the source repository's working directory
710 c) the changeset specified with -u (if a branch name, this means the
718 c) the changeset specified with -u (if a branch name, this means the
711 latest head of that branch)
719 latest head of that branch)
712 d) the changeset specified with -r
720 d) the changeset specified with -r
713 e) the tipmost head specified with -b
721 e) the tipmost head specified with -b
714 f) the tipmost head specified with the url#branch source syntax
722 f) the tipmost head specified with the url#branch source syntax
715 g) the tipmost head of the default branch
723 g) the tipmost head of the default branch
716 h) tip
724 h) tip
717
725
718 Returns 0 on success.
726 Returns 0 on success.
719 """
727 """
720 if opts.get('noupdate') and opts.get('updaterev'):
728 if opts.get('noupdate') and opts.get('updaterev'):
721 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
729 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
722
730
723 r = hg.clone(hg.remoteui(ui, opts), source, dest,
731 r = hg.clone(hg.remoteui(ui, opts), source, dest,
724 pull=opts.get('pull'),
732 pull=opts.get('pull'),
725 stream=opts.get('uncompressed'),
733 stream=opts.get('uncompressed'),
726 rev=opts.get('rev'),
734 rev=opts.get('rev'),
727 update=opts.get('updaterev') or not opts.get('noupdate'),
735 update=opts.get('updaterev') or not opts.get('noupdate'),
728 branch=opts.get('branch'))
736 branch=opts.get('branch'))
729
737
730 return r is None
738 return r is None
731
739
732 def commit(ui, repo, *pats, **opts):
740 def commit(ui, repo, *pats, **opts):
733 """commit the specified files or all outstanding changes
741 """commit the specified files or all outstanding changes
734
742
735 Commit changes to the given files into the repository. Unlike a
743 Commit changes to the given files into the repository. Unlike a
736 centralized RCS, this operation is a local operation. See
744 centralized RCS, this operation is a local operation. See
737 :hg:`push` for a way to actively distribute your changes.
745 :hg:`push` for a way to actively distribute your changes.
738
746
739 If a list of files is omitted, all changes reported by :hg:`status`
747 If a list of files is omitted, all changes reported by :hg:`status`
740 will be committed.
748 will be committed.
741
749
742 If you are committing the result of a merge, do not provide any
750 If you are committing the result of a merge, do not provide any
743 filenames or -I/-X filters.
751 filenames or -I/-X filters.
744
752
745 If no commit message is specified, Mercurial starts your
753 If no commit message is specified, Mercurial starts your
746 configured editor where you can enter a message. In case your
754 configured editor where you can enter a message. In case your
747 commit fails, you will find a backup of your message in
755 commit fails, you will find a backup of your message in
748 ``.hg/last-message.txt``.
756 ``.hg/last-message.txt``.
749
757
750 See :hg:`help dates` for a list of formats valid for -d/--date.
758 See :hg:`help dates` for a list of formats valid for -d/--date.
751
759
752 Returns 0 on success, 1 if nothing changed.
760 Returns 0 on success, 1 if nothing changed.
753 """
761 """
754 extra = {}
762 extra = {}
755 if opts.get('close_branch'):
763 if opts.get('close_branch'):
756 if repo['.'].node() not in repo.branchheads():
764 if repo['.'].node() not in repo.branchheads():
757 # The topo heads set is included in the branch heads set of the
765 # The topo heads set is included in the branch heads set of the
758 # current branch, so it's sufficient to test branchheads
766 # current branch, so it's sufficient to test branchheads
759 raise util.Abort(_('can only close branch heads'))
767 raise util.Abort(_('can only close branch heads'))
760 extra['close'] = 1
768 extra['close'] = 1
761 e = cmdutil.commiteditor
769 e = cmdutil.commiteditor
762 if opts.get('force_editor'):
770 if opts.get('force_editor'):
763 e = cmdutil.commitforceeditor
771 e = cmdutil.commitforceeditor
764
772
765 def commitfunc(ui, repo, message, match, opts):
773 def commitfunc(ui, repo, message, match, opts):
766 return repo.commit(message, opts.get('user'), opts.get('date'), match,
774 return repo.commit(message, opts.get('user'), opts.get('date'), match,
767 editor=e, extra=extra)
775 editor=e, extra=extra)
768
776
769 branch = repo[None].branch()
777 branch = repo[None].branch()
770 bheads = repo.branchheads(branch)
778 bheads = repo.branchheads(branch)
771
779
772 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
780 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
773 if not node:
781 if not node:
774 ui.status(_("nothing changed\n"))
782 ui.status(_("nothing changed\n"))
775 return 1
783 return 1
776
784
777 ctx = repo[node]
785 ctx = repo[node]
778 parents = ctx.parents()
786 parents = ctx.parents()
779
787
780 if bheads and not [x for x in parents
788 if bheads and not [x for x in parents
781 if x.node() in bheads and x.branch() == branch]:
789 if x.node() in bheads and x.branch() == branch]:
782 ui.status(_('created new head\n'))
790 ui.status(_('created new head\n'))
783 # The message is not printed for initial roots. For the other
791 # The message is not printed for initial roots. For the other
784 # changesets, it is printed in the following situations:
792 # changesets, it is printed in the following situations:
785 #
793 #
786 # Par column: for the 2 parents with ...
794 # Par column: for the 2 parents with ...
787 # N: null or no parent
795 # N: null or no parent
788 # B: parent is on another named branch
796 # B: parent is on another named branch
789 # C: parent is a regular non head changeset
797 # C: parent is a regular non head changeset
790 # H: parent was a branch head of the current branch
798 # H: parent was a branch head of the current branch
791 # Msg column: whether we print "created new head" message
799 # Msg column: whether we print "created new head" message
792 # In the following, it is assumed that there already exists some
800 # In the following, it is assumed that there already exists some
793 # initial branch heads of the current branch, otherwise nothing is
801 # initial branch heads of the current branch, otherwise nothing is
794 # printed anyway.
802 # printed anyway.
795 #
803 #
796 # Par Msg Comment
804 # Par Msg Comment
797 # NN y additional topo root
805 # NN y additional topo root
798 #
806 #
799 # BN y additional branch root
807 # BN y additional branch root
800 # CN y additional topo head
808 # CN y additional topo head
801 # HN n usual case
809 # HN n usual case
802 #
810 #
803 # BB y weird additional branch root
811 # BB y weird additional branch root
804 # CB y branch merge
812 # CB y branch merge
805 # HB n merge with named branch
813 # HB n merge with named branch
806 #
814 #
807 # CC y additional head from merge
815 # CC y additional head from merge
808 # CH n merge with a head
816 # CH n merge with a head
809 #
817 #
810 # HH n head merge: head count decreases
818 # HH n head merge: head count decreases
811
819
812 if not opts.get('close_branch'):
820 if not opts.get('close_branch'):
813 for r in parents:
821 for r in parents:
814 if r.extra().get('close') and r.branch() == branch:
822 if r.extra().get('close') and r.branch() == branch:
815 ui.status(_('reopening closed branch head %d\n') % r)
823 ui.status(_('reopening closed branch head %d\n') % r)
816
824
817 if ui.debugflag:
825 if ui.debugflag:
818 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
826 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
819 elif ui.verbose:
827 elif ui.verbose:
820 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
828 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
821
829
822 def copy(ui, repo, *pats, **opts):
830 def copy(ui, repo, *pats, **opts):
823 """mark files as copied for the next commit
831 """mark files as copied for the next commit
824
832
825 Mark dest as having copies of source files. If dest is a
833 Mark dest as having copies of source files. If dest is a
826 directory, copies are put in that directory. If dest is a file,
834 directory, copies are put in that directory. If dest is a file,
827 the source must be a single file.
835 the source must be a single file.
828
836
829 By default, this command copies the contents of files as they
837 By default, this command copies the contents of files as they
830 exist in the working directory. If invoked with -A/--after, the
838 exist in the working directory. If invoked with -A/--after, the
831 operation is recorded, but no copying is performed.
839 operation is recorded, but no copying is performed.
832
840
833 This command takes effect with the next commit. To undo a copy
841 This command takes effect with the next commit. To undo a copy
834 before that, see :hg:`revert`.
842 before that, see :hg:`revert`.
835
843
836 Returns 0 on success, 1 if errors are encountered.
844 Returns 0 on success, 1 if errors are encountered.
837 """
845 """
838 wlock = repo.wlock(False)
846 wlock = repo.wlock(False)
839 try:
847 try:
840 return cmdutil.copy(ui, repo, pats, opts)
848 return cmdutil.copy(ui, repo, pats, opts)
841 finally:
849 finally:
842 wlock.release()
850 wlock.release()
843
851
844 def debugancestor(ui, repo, *args):
852 def debugancestor(ui, repo, *args):
845 """find the ancestor revision of two revisions in a given index"""
853 """find the ancestor revision of two revisions in a given index"""
846 if len(args) == 3:
854 if len(args) == 3:
847 index, rev1, rev2 = args
855 index, rev1, rev2 = args
848 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
856 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
849 lookup = r.lookup
857 lookup = r.lookup
850 elif len(args) == 2:
858 elif len(args) == 2:
851 if not repo:
859 if not repo:
852 raise util.Abort(_("there is no Mercurial repository here "
860 raise util.Abort(_("there is no Mercurial repository here "
853 "(.hg not found)"))
861 "(.hg not found)"))
854 rev1, rev2 = args
862 rev1, rev2 = args
855 r = repo.changelog
863 r = repo.changelog
856 lookup = repo.lookup
864 lookup = repo.lookup
857 else:
865 else:
858 raise util.Abort(_('either two or three arguments required'))
866 raise util.Abort(_('either two or three arguments required'))
859 a = r.ancestor(lookup(rev1), lookup(rev2))
867 a = r.ancestor(lookup(rev1), lookup(rev2))
860 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
868 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
861
869
862 def debugbuilddag(ui, repo, text,
870 def debugbuilddag(ui, repo, text,
863 mergeable_file=False,
871 mergeable_file=False,
864 appended_file=False,
872 appended_file=False,
865 overwritten_file=False,
873 overwritten_file=False,
866 new_file=False):
874 new_file=False):
867 """builds a repo with a given dag from scratch in the current empty repo
875 """builds a repo with a given dag from scratch in the current empty repo
868
876
869 Elements:
877 Elements:
870
878
871 - "+n" is a linear run of n nodes based on the current default parent
879 - "+n" is a linear run of n nodes based on the current default parent
872 - "." is a single node based on the current default parent
880 - "." is a single node based on the current default parent
873 - "$" resets the default parent to null (implied at the start);
881 - "$" resets the default parent to null (implied at the start);
874 otherwise the default parent is always the last node created
882 otherwise the default parent is always the last node created
875 - "<p" sets the default parent to the backref p
883 - "<p" sets the default parent to the backref p
876 - "*p" is a fork at parent p, which is a backref
884 - "*p" is a fork at parent p, which is a backref
877 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
885 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
878 - "/p2" is a merge of the preceding node and p2
886 - "/p2" is a merge of the preceding node and p2
879 - ":tag" defines a local tag for the preceding node
887 - ":tag" defines a local tag for the preceding node
880 - "@branch" sets the named branch for subsequent nodes
888 - "@branch" sets the named branch for subsequent nodes
881 - "!command" runs the command using your shell
889 - "!command" runs the command using your shell
882 - "!!my command\\n" is like "!", but to the end of the line
890 - "!!my command\\n" is like "!", but to the end of the line
883 - "#...\\n" is a comment up to the end of the line
891 - "#...\\n" is a comment up to the end of the line
884
892
885 Whitespace between the above elements is ignored.
893 Whitespace between the above elements is ignored.
886
894
887 A backref is either
895 A backref is either
888
896
889 - a number n, which references the node curr-n, where curr is the current
897 - a number n, which references the node curr-n, where curr is the current
890 node, or
898 node, or
891 - the name of a local tag you placed earlier using ":tag", or
899 - the name of a local tag you placed earlier using ":tag", or
892 - empty to denote the default parent.
900 - empty to denote the default parent.
893
901
894 All string valued-elements are either strictly alphanumeric, or must
902 All string valued-elements are either strictly alphanumeric, or must
895 be enclosed in double quotes ("..."), with "\\" as escape character.
903 be enclosed in double quotes ("..."), with "\\" as escape character.
896
904
897 Note that the --overwritten-file and --appended-file options imply the
905 Note that the --overwritten-file and --appended-file options imply the
898 use of "HGMERGE=internal:local" during DAG buildup.
906 use of "HGMERGE=internal:local" during DAG buildup.
899 """
907 """
900
908
901 if not (mergeable_file or appended_file or overwritten_file or new_file):
909 if not (mergeable_file or appended_file or overwritten_file or new_file):
902 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
910 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
903
911
904 if len(repo.changelog) > 0:
912 if len(repo.changelog) > 0:
905 raise util.Abort(_('repository is not empty'))
913 raise util.Abort(_('repository is not empty'))
906
914
907 if overwritten_file or appended_file:
915 if overwritten_file or appended_file:
908 # we don't want to fail in merges during buildup
916 # we don't want to fail in merges during buildup
909 os.environ['HGMERGE'] = 'internal:local'
917 os.environ['HGMERGE'] = 'internal:local'
910
918
911 def writefile(fname, text, fmode="wb"):
919 def writefile(fname, text, fmode="wb"):
912 f = open(fname, fmode)
920 f = open(fname, fmode)
913 try:
921 try:
914 f.write(text)
922 f.write(text)
915 finally:
923 finally:
916 f.close()
924 f.close()
917
925
918 if mergeable_file:
926 if mergeable_file:
919 linesperrev = 2
927 linesperrev = 2
920 # determine number of revs in DAG
928 # determine number of revs in DAG
921 n = 0
929 n = 0
922 for type, data in dagparser.parsedag(text):
930 for type, data in dagparser.parsedag(text):
923 if type == 'n':
931 if type == 'n':
924 n += 1
932 n += 1
925 # make a file with k lines per rev
933 # make a file with k lines per rev
926 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
934 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
927 + "\n")
935 + "\n")
928
936
929 at = -1
937 at = -1
930 atbranch = 'default'
938 atbranch = 'default'
931 for type, data in dagparser.parsedag(text):
939 for type, data in dagparser.parsedag(text):
932 if type == 'n':
940 if type == 'n':
933 ui.status('node %s\n' % str(data))
941 ui.status('node %s\n' % str(data))
934 id, ps = data
942 id, ps = data
935 p1 = ps[0]
943 p1 = ps[0]
936 if p1 != at:
944 if p1 != at:
937 update(ui, repo, node=str(p1), clean=True)
945 update(ui, repo, node=str(p1), clean=True)
938 at = p1
946 at = p1
939 if repo.dirstate.branch() != atbranch:
947 if repo.dirstate.branch() != atbranch:
940 branch(ui, repo, atbranch, force=True)
948 branch(ui, repo, atbranch, force=True)
941 if len(ps) > 1:
949 if len(ps) > 1:
942 p2 = ps[1]
950 p2 = ps[1]
943 merge(ui, repo, node=p2)
951 merge(ui, repo, node=p2)
944
952
945 if mergeable_file:
953 if mergeable_file:
946 f = open("mf", "rb+")
954 f = open("mf", "rb+")
947 try:
955 try:
948 lines = f.read().split("\n")
956 lines = f.read().split("\n")
949 lines[id * linesperrev] += " r%i" % id
957 lines[id * linesperrev] += " r%i" % id
950 f.seek(0)
958 f.seek(0)
951 f.write("\n".join(lines))
959 f.write("\n".join(lines))
952 finally:
960 finally:
953 f.close()
961 f.close()
954
962
955 if appended_file:
963 if appended_file:
956 writefile("af", "r%i\n" % id, "ab")
964 writefile("af", "r%i\n" % id, "ab")
957
965
958 if overwritten_file:
966 if overwritten_file:
959 writefile("of", "r%i\n" % id)
967 writefile("of", "r%i\n" % id)
960
968
961 if new_file:
969 if new_file:
962 writefile("nf%i" % id, "r%i\n" % id)
970 writefile("nf%i" % id, "r%i\n" % id)
963
971
964 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
972 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
965 at = id
973 at = id
966 elif type == 'l':
974 elif type == 'l':
967 id, name = data
975 id, name = data
968 ui.status('tag %s\n' % name)
976 ui.status('tag %s\n' % name)
969 tag(ui, repo, name, local=True)
977 tag(ui, repo, name, local=True)
970 elif type == 'a':
978 elif type == 'a':
971 ui.status('branch %s\n' % data)
979 ui.status('branch %s\n' % data)
972 atbranch = data
980 atbranch = data
973 elif type in 'cC':
981 elif type in 'cC':
974 r = util.system(data, cwd=repo.root)
982 r = util.system(data, cwd=repo.root)
975 if r:
983 if r:
976 desc, r = util.explain_exit(r)
984 desc, r = util.explain_exit(r)
977 raise util.Abort(_('%s command %s') % (data, desc))
985 raise util.Abort(_('%s command %s') % (data, desc))
978
986
979 def debugcommands(ui, cmd='', *args):
987 def debugcommands(ui, cmd='', *args):
980 """list all available commands and options"""
988 """list all available commands and options"""
981 for cmd, vals in sorted(table.iteritems()):
989 for cmd, vals in sorted(table.iteritems()):
982 cmd = cmd.split('|')[0].strip('^')
990 cmd = cmd.split('|')[0].strip('^')
983 opts = ', '.join([i[1] for i in vals[1]])
991 opts = ', '.join([i[1] for i in vals[1]])
984 ui.write('%s: %s\n' % (cmd, opts))
992 ui.write('%s: %s\n' % (cmd, opts))
985
993
986 def debugcomplete(ui, cmd='', **opts):
994 def debugcomplete(ui, cmd='', **opts):
987 """returns the completion list associated with the given command"""
995 """returns the completion list associated with the given command"""
988
996
989 if opts.get('options'):
997 if opts.get('options'):
990 options = []
998 options = []
991 otables = [globalopts]
999 otables = [globalopts]
992 if cmd:
1000 if cmd:
993 aliases, entry = cmdutil.findcmd(cmd, table, False)
1001 aliases, entry = cmdutil.findcmd(cmd, table, False)
994 otables.append(entry[1])
1002 otables.append(entry[1])
995 for t in otables:
1003 for t in otables:
996 for o in t:
1004 for o in t:
997 if "(DEPRECATED)" in o[3]:
1005 if "(DEPRECATED)" in o[3]:
998 continue
1006 continue
999 if o[0]:
1007 if o[0]:
1000 options.append('-%s' % o[0])
1008 options.append('-%s' % o[0])
1001 options.append('--%s' % o[1])
1009 options.append('--%s' % o[1])
1002 ui.write("%s\n" % "\n".join(options))
1010 ui.write("%s\n" % "\n".join(options))
1003 return
1011 return
1004
1012
1005 cmdlist = cmdutil.findpossible(cmd, table)
1013 cmdlist = cmdutil.findpossible(cmd, table)
1006 if ui.verbose:
1014 if ui.verbose:
1007 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1015 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1008 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1016 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1009
1017
1010 def debugfsinfo(ui, path = "."):
1018 def debugfsinfo(ui, path = "."):
1011 """show information detected about current filesystem"""
1019 """show information detected about current filesystem"""
1012 open('.debugfsinfo', 'w').write('')
1020 open('.debugfsinfo', 'w').write('')
1013 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1021 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1014 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1022 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1015 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1023 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1016 and 'yes' or 'no'))
1024 and 'yes' or 'no'))
1017 os.unlink('.debugfsinfo')
1025 os.unlink('.debugfsinfo')
1018
1026
1019 def debugrebuildstate(ui, repo, rev="tip"):
1027 def debugrebuildstate(ui, repo, rev="tip"):
1020 """rebuild the dirstate as it would look like for the given revision"""
1028 """rebuild the dirstate as it would look like for the given revision"""
1021 ctx = repo[rev]
1029 ctx = repo[rev]
1022 wlock = repo.wlock()
1030 wlock = repo.wlock()
1023 try:
1031 try:
1024 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1032 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1025 finally:
1033 finally:
1026 wlock.release()
1034 wlock.release()
1027
1035
1028 def debugcheckstate(ui, repo):
1036 def debugcheckstate(ui, repo):
1029 """validate the correctness of the current dirstate"""
1037 """validate the correctness of the current dirstate"""
1030 parent1, parent2 = repo.dirstate.parents()
1038 parent1, parent2 = repo.dirstate.parents()
1031 m1 = repo[parent1].manifest()
1039 m1 = repo[parent1].manifest()
1032 m2 = repo[parent2].manifest()
1040 m2 = repo[parent2].manifest()
1033 errors = 0
1041 errors = 0
1034 for f in repo.dirstate:
1042 for f in repo.dirstate:
1035 state = repo.dirstate[f]
1043 state = repo.dirstate[f]
1036 if state in "nr" and f not in m1:
1044 if state in "nr" and f not in m1:
1037 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1045 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1038 errors += 1
1046 errors += 1
1039 if state in "a" and f in m1:
1047 if state in "a" and f in m1:
1040 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1048 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1041 errors += 1
1049 errors += 1
1042 if state in "m" and f not in m1 and f not in m2:
1050 if state in "m" and f not in m1 and f not in m2:
1043 ui.warn(_("%s in state %s, but not in either manifest\n") %
1051 ui.warn(_("%s in state %s, but not in either manifest\n") %
1044 (f, state))
1052 (f, state))
1045 errors += 1
1053 errors += 1
1046 for f in m1:
1054 for f in m1:
1047 state = repo.dirstate[f]
1055 state = repo.dirstate[f]
1048 if state not in "nrm":
1056 if state not in "nrm":
1049 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1057 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1050 errors += 1
1058 errors += 1
1051 if errors:
1059 if errors:
1052 error = _(".hg/dirstate inconsistent with current parent's manifest")
1060 error = _(".hg/dirstate inconsistent with current parent's manifest")
1053 raise util.Abort(error)
1061 raise util.Abort(error)
1054
1062
1055 def showconfig(ui, repo, *values, **opts):
1063 def showconfig(ui, repo, *values, **opts):
1056 """show combined config settings from all hgrc files
1064 """show combined config settings from all hgrc files
1057
1065
1058 With no arguments, print names and values of all config items.
1066 With no arguments, print names and values of all config items.
1059
1067
1060 With one argument of the form section.name, print just the value
1068 With one argument of the form section.name, print just the value
1061 of that config item.
1069 of that config item.
1062
1070
1063 With multiple arguments, print names and values of all config
1071 With multiple arguments, print names and values of all config
1064 items with matching section names.
1072 items with matching section names.
1065
1073
1066 With --debug, the source (filename and line number) is printed
1074 With --debug, the source (filename and line number) is printed
1067 for each config item.
1075 for each config item.
1068
1076
1069 Returns 0 on success.
1077 Returns 0 on success.
1070 """
1078 """
1071
1079
1072 for f in util.rcpath():
1080 for f in util.rcpath():
1073 ui.debug(_('read config from: %s\n') % f)
1081 ui.debug(_('read config from: %s\n') % f)
1074 untrusted = bool(opts.get('untrusted'))
1082 untrusted = bool(opts.get('untrusted'))
1075 if values:
1083 if values:
1076 sections = [v for v in values if '.' not in v]
1084 sections = [v for v in values if '.' not in v]
1077 items = [v for v in values if '.' in v]
1085 items = [v for v in values if '.' in v]
1078 if len(items) > 1 or items and sections:
1086 if len(items) > 1 or items and sections:
1079 raise util.Abort(_('only one config item permitted'))
1087 raise util.Abort(_('only one config item permitted'))
1080 for section, name, value in ui.walkconfig(untrusted=untrusted):
1088 for section, name, value in ui.walkconfig(untrusted=untrusted):
1081 sectname = section + '.' + name
1089 sectname = section + '.' + name
1082 if values:
1090 if values:
1083 for v in values:
1091 for v in values:
1084 if v == section:
1092 if v == section:
1085 ui.debug('%s: ' %
1093 ui.debug('%s: ' %
1086 ui.configsource(section, name, untrusted))
1094 ui.configsource(section, name, untrusted))
1087 ui.write('%s=%s\n' % (sectname, value))
1095 ui.write('%s=%s\n' % (sectname, value))
1088 elif v == sectname:
1096 elif v == sectname:
1089 ui.debug('%s: ' %
1097 ui.debug('%s: ' %
1090 ui.configsource(section, name, untrusted))
1098 ui.configsource(section, name, untrusted))
1091 ui.write(value, '\n')
1099 ui.write(value, '\n')
1092 else:
1100 else:
1093 ui.debug('%s: ' %
1101 ui.debug('%s: ' %
1094 ui.configsource(section, name, untrusted))
1102 ui.configsource(section, name, untrusted))
1095 ui.write('%s=%s\n' % (sectname, value))
1103 ui.write('%s=%s\n' % (sectname, value))
1096
1104
1097 def debugpushkey(ui, repopath, namespace, *keyinfo):
1105 def debugpushkey(ui, repopath, namespace, *keyinfo):
1098 '''access the pushkey key/value protocol
1106 '''access the pushkey key/value protocol
1099
1107
1100 With two args, list the keys in the given namespace.
1108 With two args, list the keys in the given namespace.
1101
1109
1102 With five args, set a key to new if it currently is set to old.
1110 With five args, set a key to new if it currently is set to old.
1103 Reports success or failure.
1111 Reports success or failure.
1104 '''
1112 '''
1105
1113
1106 target = hg.repository(ui, repopath)
1114 target = hg.repository(ui, repopath)
1107 if keyinfo:
1115 if keyinfo:
1108 key, old, new = keyinfo
1116 key, old, new = keyinfo
1109 r = target.pushkey(namespace, key, old, new)
1117 r = target.pushkey(namespace, key, old, new)
1110 ui.status(str(r) + '\n')
1118 ui.status(str(r) + '\n')
1111 return not(r)
1119 return not(r)
1112 else:
1120 else:
1113 for k, v in target.listkeys(namespace).iteritems():
1121 for k, v in target.listkeys(namespace).iteritems():
1114 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1122 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1115 v.encode('string-escape')))
1123 v.encode('string-escape')))
1116
1124
1117 def debugrevspec(ui, repo, expr):
1125 def debugrevspec(ui, repo, expr):
1118 '''parse and apply a revision specification'''
1126 '''parse and apply a revision specification'''
1119 if ui.verbose:
1127 if ui.verbose:
1120 tree = revset.parse(expr)
1128 tree = revset.parse(expr)
1121 ui.note(tree, "\n")
1129 ui.note(tree, "\n")
1122 func = revset.match(expr)
1130 func = revset.match(expr)
1123 for c in func(repo, range(len(repo))):
1131 for c in func(repo, range(len(repo))):
1124 ui.write("%s\n" % c)
1132 ui.write("%s\n" % c)
1125
1133
1126 def debugsetparents(ui, repo, rev1, rev2=None):
1134 def debugsetparents(ui, repo, rev1, rev2=None):
1127 """manually set the parents of the current working directory
1135 """manually set the parents of the current working directory
1128
1136
1129 This is useful for writing repository conversion tools, but should
1137 This is useful for writing repository conversion tools, but should
1130 be used with care.
1138 be used with care.
1131
1139
1132 Returns 0 on success.
1140 Returns 0 on success.
1133 """
1141 """
1134
1142
1135 if not rev2:
1143 if not rev2:
1136 rev2 = hex(nullid)
1144 rev2 = hex(nullid)
1137
1145
1138 wlock = repo.wlock()
1146 wlock = repo.wlock()
1139 try:
1147 try:
1140 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1148 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1141 finally:
1149 finally:
1142 wlock.release()
1150 wlock.release()
1143
1151
1144 def debugstate(ui, repo, nodates=None):
1152 def debugstate(ui, repo, nodates=None):
1145 """show the contents of the current dirstate"""
1153 """show the contents of the current dirstate"""
1146 timestr = ""
1154 timestr = ""
1147 showdate = not nodates
1155 showdate = not nodates
1148 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1156 for file_, ent in sorted(repo.dirstate._map.iteritems()):
1149 if showdate:
1157 if showdate:
1150 if ent[3] == -1:
1158 if ent[3] == -1:
1151 # Pad or slice to locale representation
1159 # Pad or slice to locale representation
1152 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1160 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1153 time.localtime(0)))
1161 time.localtime(0)))
1154 timestr = 'unset'
1162 timestr = 'unset'
1155 timestr = (timestr[:locale_len] +
1163 timestr = (timestr[:locale_len] +
1156 ' ' * (locale_len - len(timestr)))
1164 ' ' * (locale_len - len(timestr)))
1157 else:
1165 else:
1158 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1166 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1159 time.localtime(ent[3]))
1167 time.localtime(ent[3]))
1160 if ent[1] & 020000:
1168 if ent[1] & 020000:
1161 mode = 'lnk'
1169 mode = 'lnk'
1162 else:
1170 else:
1163 mode = '%3o' % (ent[1] & 0777)
1171 mode = '%3o' % (ent[1] & 0777)
1164 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1172 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1165 for f in repo.dirstate.copies():
1173 for f in repo.dirstate.copies():
1166 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1174 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1167
1175
1168 def debugsub(ui, repo, rev=None):
1176 def debugsub(ui, repo, rev=None):
1169 if rev == '':
1177 if rev == '':
1170 rev = None
1178 rev = None
1171 for k, v in sorted(repo[rev].substate.items()):
1179 for k, v in sorted(repo[rev].substate.items()):
1172 ui.write('path %s\n' % k)
1180 ui.write('path %s\n' % k)
1173 ui.write(' source %s\n' % v[0])
1181 ui.write(' source %s\n' % v[0])
1174 ui.write(' revision %s\n' % v[1])
1182 ui.write(' revision %s\n' % v[1])
1175
1183
1176 def debugdag(ui, repo, file_=None, *revs, **opts):
1184 def debugdag(ui, repo, file_=None, *revs, **opts):
1177 """format the changelog or an index DAG as a concise textual description
1185 """format the changelog or an index DAG as a concise textual description
1178
1186
1179 If you pass a revlog index, the revlog's DAG is emitted. If you list
1187 If you pass a revlog index, the revlog's DAG is emitted. If you list
1180 revision numbers, they get labelled in the output as rN.
1188 revision numbers, they get labelled in the output as rN.
1181
1189
1182 Otherwise, the changelog DAG of the current repo is emitted.
1190 Otherwise, the changelog DAG of the current repo is emitted.
1183 """
1191 """
1184 spaces = opts.get('spaces')
1192 spaces = opts.get('spaces')
1185 dots = opts.get('dots')
1193 dots = opts.get('dots')
1186 if file_:
1194 if file_:
1187 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1195 rlog = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1188 revs = set((int(r) for r in revs))
1196 revs = set((int(r) for r in revs))
1189 def events():
1197 def events():
1190 for r in rlog:
1198 for r in rlog:
1191 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1199 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1192 if r in revs:
1200 if r in revs:
1193 yield 'l', (r, "r%i" % r)
1201 yield 'l', (r, "r%i" % r)
1194 elif repo:
1202 elif repo:
1195 cl = repo.changelog
1203 cl = repo.changelog
1196 tags = opts.get('tags')
1204 tags = opts.get('tags')
1197 branches = opts.get('branches')
1205 branches = opts.get('branches')
1198 if tags:
1206 if tags:
1199 labels = {}
1207 labels = {}
1200 for l, n in repo.tags().items():
1208 for l, n in repo.tags().items():
1201 labels.setdefault(cl.rev(n), []).append(l)
1209 labels.setdefault(cl.rev(n), []).append(l)
1202 def events():
1210 def events():
1203 b = "default"
1211 b = "default"
1204 for r in cl:
1212 for r in cl:
1205 if branches:
1213 if branches:
1206 newb = cl.read(cl.node(r))[5]['branch']
1214 newb = cl.read(cl.node(r))[5]['branch']
1207 if newb != b:
1215 if newb != b:
1208 yield 'a', newb
1216 yield 'a', newb
1209 b = newb
1217 b = newb
1210 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1218 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1211 if tags:
1219 if tags:
1212 ls = labels.get(r)
1220 ls = labels.get(r)
1213 if ls:
1221 if ls:
1214 for l in ls:
1222 for l in ls:
1215 yield 'l', (r, l)
1223 yield 'l', (r, l)
1216 else:
1224 else:
1217 raise util.Abort(_('need repo for changelog dag'))
1225 raise util.Abort(_('need repo for changelog dag'))
1218
1226
1219 for line in dagparser.dagtextlines(events(),
1227 for line in dagparser.dagtextlines(events(),
1220 addspaces=spaces,
1228 addspaces=spaces,
1221 wraplabels=True,
1229 wraplabels=True,
1222 wrapannotations=True,
1230 wrapannotations=True,
1223 wrapnonlinear=dots,
1231 wrapnonlinear=dots,
1224 usedots=dots,
1232 usedots=dots,
1225 maxlinewidth=70):
1233 maxlinewidth=70):
1226 ui.write(line)
1234 ui.write(line)
1227 ui.write("\n")
1235 ui.write("\n")
1228
1236
1229 def debugdata(ui, repo, file_, rev):
1237 def debugdata(ui, repo, file_, rev):
1230 """dump the contents of a data file revision"""
1238 """dump the contents of a data file revision"""
1231 r = None
1239 r = None
1232 if repo:
1240 if repo:
1233 filelog = repo.file(file_)
1241 filelog = repo.file(file_)
1234 if len(filelog):
1242 if len(filelog):
1235 r = filelog
1243 r = filelog
1236 if not r:
1244 if not r:
1237 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1245 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
1238 try:
1246 try:
1239 ui.write(r.revision(r.lookup(rev)))
1247 ui.write(r.revision(r.lookup(rev)))
1240 except KeyError:
1248 except KeyError:
1241 raise util.Abort(_('invalid revision identifier %s') % rev)
1249 raise util.Abort(_('invalid revision identifier %s') % rev)
1242
1250
1243 def debugdate(ui, date, range=None, **opts):
1251 def debugdate(ui, date, range=None, **opts):
1244 """parse and display a date"""
1252 """parse and display a date"""
1245 if opts["extended"]:
1253 if opts["extended"]:
1246 d = util.parsedate(date, util.extendeddateformats)
1254 d = util.parsedate(date, util.extendeddateformats)
1247 else:
1255 else:
1248 d = util.parsedate(date)
1256 d = util.parsedate(date)
1249 ui.write("internal: %s %s\n" % d)
1257 ui.write("internal: %s %s\n" % d)
1250 ui.write("standard: %s\n" % util.datestr(d))
1258 ui.write("standard: %s\n" % util.datestr(d))
1251 if range:
1259 if range:
1252 m = util.matchdate(range)
1260 m = util.matchdate(range)
1253 ui.write("match: %s\n" % m(d[0]))
1261 ui.write("match: %s\n" % m(d[0]))
1254
1262
1255 def debugindex(ui, repo, file_):
1263 def debugindex(ui, repo, file_):
1256 """dump the contents of an index file"""
1264 """dump the contents of an index file"""
1257 r = None
1265 r = None
1258 if repo:
1266 if repo:
1259 filelog = repo.file(file_)
1267 filelog = repo.file(file_)
1260 if len(filelog):
1268 if len(filelog):
1261 r = filelog
1269 r = filelog
1262 if not r:
1270 if not r:
1263 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1271 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1264 ui.write(" rev offset length base linkrev"
1272 ui.write(" rev offset length base linkrev"
1265 " nodeid p1 p2\n")
1273 " nodeid p1 p2\n")
1266 for i in r:
1274 for i in r:
1267 node = r.node(i)
1275 node = r.node(i)
1268 try:
1276 try:
1269 pp = r.parents(node)
1277 pp = r.parents(node)
1270 except:
1278 except:
1271 pp = [nullid, nullid]
1279 pp = [nullid, nullid]
1272 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1280 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1273 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1281 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1274 short(node), short(pp[0]), short(pp[1])))
1282 short(node), short(pp[0]), short(pp[1])))
1275
1283
1276 def debugindexdot(ui, repo, file_):
1284 def debugindexdot(ui, repo, file_):
1277 """dump an index DAG as a graphviz dot file"""
1285 """dump an index DAG as a graphviz dot file"""
1278 r = None
1286 r = None
1279 if repo:
1287 if repo:
1280 filelog = repo.file(file_)
1288 filelog = repo.file(file_)
1281 if len(filelog):
1289 if len(filelog):
1282 r = filelog
1290 r = filelog
1283 if not r:
1291 if not r:
1284 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1292 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
1285 ui.write("digraph G {\n")
1293 ui.write("digraph G {\n")
1286 for i in r:
1294 for i in r:
1287 node = r.node(i)
1295 node = r.node(i)
1288 pp = r.parents(node)
1296 pp = r.parents(node)
1289 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1297 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1290 if pp[1] != nullid:
1298 if pp[1] != nullid:
1291 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1299 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1292 ui.write("}\n")
1300 ui.write("}\n")
1293
1301
1294 def debuginstall(ui):
1302 def debuginstall(ui):
1295 '''test Mercurial installation
1303 '''test Mercurial installation
1296
1304
1297 Returns 0 on success.
1305 Returns 0 on success.
1298 '''
1306 '''
1299
1307
1300 def writetemp(contents):
1308 def writetemp(contents):
1301 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1309 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1302 f = os.fdopen(fd, "wb")
1310 f = os.fdopen(fd, "wb")
1303 f.write(contents)
1311 f.write(contents)
1304 f.close()
1312 f.close()
1305 return name
1313 return name
1306
1314
1307 problems = 0
1315 problems = 0
1308
1316
1309 # encoding
1317 # encoding
1310 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1318 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1311 try:
1319 try:
1312 encoding.fromlocal("test")
1320 encoding.fromlocal("test")
1313 except util.Abort, inst:
1321 except util.Abort, inst:
1314 ui.write(" %s\n" % inst)
1322 ui.write(" %s\n" % inst)
1315 ui.write(_(" (check that your locale is properly set)\n"))
1323 ui.write(_(" (check that your locale is properly set)\n"))
1316 problems += 1
1324 problems += 1
1317
1325
1318 # compiled modules
1326 # compiled modules
1319 ui.status(_("Checking installed modules (%s)...\n")
1327 ui.status(_("Checking installed modules (%s)...\n")
1320 % os.path.dirname(__file__))
1328 % os.path.dirname(__file__))
1321 try:
1329 try:
1322 import bdiff, mpatch, base85, osutil
1330 import bdiff, mpatch, base85, osutil
1323 except Exception, inst:
1331 except Exception, inst:
1324 ui.write(" %s\n" % inst)
1332 ui.write(" %s\n" % inst)
1325 ui.write(_(" One or more extensions could not be found"))
1333 ui.write(_(" One or more extensions could not be found"))
1326 ui.write(_(" (check that you compiled the extensions)\n"))
1334 ui.write(_(" (check that you compiled the extensions)\n"))
1327 problems += 1
1335 problems += 1
1328
1336
1329 # templates
1337 # templates
1330 ui.status(_("Checking templates...\n"))
1338 ui.status(_("Checking templates...\n"))
1331 try:
1339 try:
1332 import templater
1340 import templater
1333 templater.templater(templater.templatepath("map-cmdline.default"))
1341 templater.templater(templater.templatepath("map-cmdline.default"))
1334 except Exception, inst:
1342 except Exception, inst:
1335 ui.write(" %s\n" % inst)
1343 ui.write(" %s\n" % inst)
1336 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1344 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1337 problems += 1
1345 problems += 1
1338
1346
1339 # patch
1347 # patch
1340 ui.status(_("Checking patch...\n"))
1348 ui.status(_("Checking patch...\n"))
1341 patchproblems = 0
1349 patchproblems = 0
1342 a = "1\n2\n3\n4\n"
1350 a = "1\n2\n3\n4\n"
1343 b = "1\n2\n3\ninsert\n4\n"
1351 b = "1\n2\n3\ninsert\n4\n"
1344 fa = writetemp(a)
1352 fa = writetemp(a)
1345 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1353 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
1346 os.path.basename(fa))
1354 os.path.basename(fa))
1347 fd = writetemp(d)
1355 fd = writetemp(d)
1348
1356
1349 files = {}
1357 files = {}
1350 try:
1358 try:
1351 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1359 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
1352 except util.Abort, e:
1360 except util.Abort, e:
1353 ui.write(_(" patch call failed:\n"))
1361 ui.write(_(" patch call failed:\n"))
1354 ui.write(" " + str(e) + "\n")
1362 ui.write(" " + str(e) + "\n")
1355 patchproblems += 1
1363 patchproblems += 1
1356 else:
1364 else:
1357 if list(files) != [os.path.basename(fa)]:
1365 if list(files) != [os.path.basename(fa)]:
1358 ui.write(_(" unexpected patch output!\n"))
1366 ui.write(_(" unexpected patch output!\n"))
1359 patchproblems += 1
1367 patchproblems += 1
1360 a = open(fa).read()
1368 a = open(fa).read()
1361 if a != b:
1369 if a != b:
1362 ui.write(_(" patch test failed!\n"))
1370 ui.write(_(" patch test failed!\n"))
1363 patchproblems += 1
1371 patchproblems += 1
1364
1372
1365 if patchproblems:
1373 if patchproblems:
1366 if ui.config('ui', 'patch'):
1374 if ui.config('ui', 'patch'):
1367 ui.write(_(" (Current patch tool may be incompatible with patch,"
1375 ui.write(_(" (Current patch tool may be incompatible with patch,"
1368 " or misconfigured. Please check your configuration"
1376 " or misconfigured. Please check your configuration"
1369 " file)\n"))
1377 " file)\n"))
1370 else:
1378 else:
1371 ui.write(_(" Internal patcher failure, please report this error"
1379 ui.write(_(" Internal patcher failure, please report this error"
1372 " to http://mercurial.selenic.com/bts/\n"))
1380 " to http://mercurial.selenic.com/bts/\n"))
1373 problems += patchproblems
1381 problems += patchproblems
1374
1382
1375 os.unlink(fa)
1383 os.unlink(fa)
1376 os.unlink(fd)
1384 os.unlink(fd)
1377
1385
1378 # editor
1386 # editor
1379 ui.status(_("Checking commit editor...\n"))
1387 ui.status(_("Checking commit editor...\n"))
1380 editor = ui.geteditor()
1388 editor = ui.geteditor()
1381 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1389 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1382 if not cmdpath:
1390 if not cmdpath:
1383 if editor == 'vi':
1391 if editor == 'vi':
1384 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1392 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1385 ui.write(_(" (specify a commit editor in your configuration"
1393 ui.write(_(" (specify a commit editor in your configuration"
1386 " file)\n"))
1394 " file)\n"))
1387 else:
1395 else:
1388 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1396 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1389 ui.write(_(" (specify a commit editor in your configuration"
1397 ui.write(_(" (specify a commit editor in your configuration"
1390 " file)\n"))
1398 " file)\n"))
1391 problems += 1
1399 problems += 1
1392
1400
1393 # check username
1401 # check username
1394 ui.status(_("Checking username...\n"))
1402 ui.status(_("Checking username...\n"))
1395 try:
1403 try:
1396 ui.username()
1404 ui.username()
1397 except util.Abort, e:
1405 except util.Abort, e:
1398 ui.write(" %s\n" % e)
1406 ui.write(" %s\n" % e)
1399 ui.write(_(" (specify a username in your configuration file)\n"))
1407 ui.write(_(" (specify a username in your configuration file)\n"))
1400 problems += 1
1408 problems += 1
1401
1409
1402 if not problems:
1410 if not problems:
1403 ui.status(_("No problems detected\n"))
1411 ui.status(_("No problems detected\n"))
1404 else:
1412 else:
1405 ui.write(_("%s problems detected,"
1413 ui.write(_("%s problems detected,"
1406 " please check your install!\n") % problems)
1414 " please check your install!\n") % problems)
1407
1415
1408 return problems
1416 return problems
1409
1417
1410 def debugrename(ui, repo, file1, *pats, **opts):
1418 def debugrename(ui, repo, file1, *pats, **opts):
1411 """dump rename information"""
1419 """dump rename information"""
1412
1420
1413 ctx = repo[opts.get('rev')]
1421 ctx = repo[opts.get('rev')]
1414 m = cmdutil.match(repo, (file1,) + pats, opts)
1422 m = cmdutil.match(repo, (file1,) + pats, opts)
1415 for abs in ctx.walk(m):
1423 for abs in ctx.walk(m):
1416 fctx = ctx[abs]
1424 fctx = ctx[abs]
1417 o = fctx.filelog().renamed(fctx.filenode())
1425 o = fctx.filelog().renamed(fctx.filenode())
1418 rel = m.rel(abs)
1426 rel = m.rel(abs)
1419 if o:
1427 if o:
1420 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1428 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1421 else:
1429 else:
1422 ui.write(_("%s not renamed\n") % rel)
1430 ui.write(_("%s not renamed\n") % rel)
1423
1431
1424 def debugwalk(ui, repo, *pats, **opts):
1432 def debugwalk(ui, repo, *pats, **opts):
1425 """show how files match on given patterns"""
1433 """show how files match on given patterns"""
1426 m = cmdutil.match(repo, pats, opts)
1434 m = cmdutil.match(repo, pats, opts)
1427 items = list(repo.walk(m))
1435 items = list(repo.walk(m))
1428 if not items:
1436 if not items:
1429 return
1437 return
1430 fmt = 'f %%-%ds %%-%ds %%s' % (
1438 fmt = 'f %%-%ds %%-%ds %%s' % (
1431 max([len(abs) for abs in items]),
1439 max([len(abs) for abs in items]),
1432 max([len(m.rel(abs)) for abs in items]))
1440 max([len(m.rel(abs)) for abs in items]))
1433 for abs in items:
1441 for abs in items:
1434 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1442 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1435 ui.write("%s\n" % line.rstrip())
1443 ui.write("%s\n" % line.rstrip())
1436
1444
1437 def diff(ui, repo, *pats, **opts):
1445 def diff(ui, repo, *pats, **opts):
1438 """diff repository (or selected files)
1446 """diff repository (or selected files)
1439
1447
1440 Show differences between revisions for the specified files.
1448 Show differences between revisions for the specified files.
1441
1449
1442 Differences between files are shown using the unified diff format.
1450 Differences between files are shown using the unified diff format.
1443
1451
1444 .. note::
1452 .. note::
1445 diff may generate unexpected results for merges, as it will
1453 diff may generate unexpected results for merges, as it will
1446 default to comparing against the working directory's first
1454 default to comparing against the working directory's first
1447 parent changeset if no revisions are specified.
1455 parent changeset if no revisions are specified.
1448
1456
1449 When two revision arguments are given, then changes are shown
1457 When two revision arguments are given, then changes are shown
1450 between those revisions. If only one revision is specified then
1458 between those revisions. If only one revision is specified then
1451 that revision is compared to the working directory, and, when no
1459 that revision is compared to the working directory, and, when no
1452 revisions are specified, the working directory files are compared
1460 revisions are specified, the working directory files are compared
1453 to its parent.
1461 to its parent.
1454
1462
1455 Alternatively you can specify -c/--change with a revision to see
1463 Alternatively you can specify -c/--change with a revision to see
1456 the changes in that changeset relative to its first parent.
1464 the changes in that changeset relative to its first parent.
1457
1465
1458 Without the -a/--text option, diff will avoid generating diffs of
1466 Without the -a/--text option, diff will avoid generating diffs of
1459 files it detects as binary. With -a, diff will generate a diff
1467 files it detects as binary. With -a, diff will generate a diff
1460 anyway, probably with undesirable results.
1468 anyway, probably with undesirable results.
1461
1469
1462 Use the -g/--git option to generate diffs in the git extended diff
1470 Use the -g/--git option to generate diffs in the git extended diff
1463 format. For more information, read :hg:`help diffs`.
1471 format. For more information, read :hg:`help diffs`.
1464
1472
1465 Returns 0 on success.
1473 Returns 0 on success.
1466 """
1474 """
1467
1475
1468 revs = opts.get('rev')
1476 revs = opts.get('rev')
1469 change = opts.get('change')
1477 change = opts.get('change')
1470 stat = opts.get('stat')
1478 stat = opts.get('stat')
1471 reverse = opts.get('reverse')
1479 reverse = opts.get('reverse')
1472
1480
1473 if revs and change:
1481 if revs and change:
1474 msg = _('cannot specify --rev and --change at the same time')
1482 msg = _('cannot specify --rev and --change at the same time')
1475 raise util.Abort(msg)
1483 raise util.Abort(msg)
1476 elif change:
1484 elif change:
1477 node2 = repo.lookup(change)
1485 node2 = repo.lookup(change)
1478 node1 = repo[node2].parents()[0].node()
1486 node1 = repo[node2].parents()[0].node()
1479 else:
1487 else:
1480 node1, node2 = cmdutil.revpair(repo, revs)
1488 node1, node2 = cmdutil.revpair(repo, revs)
1481
1489
1482 if reverse:
1490 if reverse:
1483 node1, node2 = node2, node1
1491 node1, node2 = node2, node1
1484
1492
1485 diffopts = patch.diffopts(ui, opts)
1493 diffopts = patch.diffopts(ui, opts)
1486 m = cmdutil.match(repo, pats, opts)
1494 m = cmdutil.match(repo, pats, opts)
1487 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1495 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1488 listsubrepos=opts.get('subrepos'))
1496 listsubrepos=opts.get('subrepos'))
1489
1497
1490 def export(ui, repo, *changesets, **opts):
1498 def export(ui, repo, *changesets, **opts):
1491 """dump the header and diffs for one or more changesets
1499 """dump the header and diffs for one or more changesets
1492
1500
1493 Print the changeset header and diffs for one or more revisions.
1501 Print the changeset header and diffs for one or more revisions.
1494
1502
1495 The information shown in the changeset header is: author, date,
1503 The information shown in the changeset header is: author, date,
1496 branch name (if non-default), changeset hash, parent(s) and commit
1504 branch name (if non-default), changeset hash, parent(s) and commit
1497 comment.
1505 comment.
1498
1506
1499 .. note::
1507 .. note::
1500 export may generate unexpected diff output for merge
1508 export may generate unexpected diff output for merge
1501 changesets, as it will compare the merge changeset against its
1509 changesets, as it will compare the merge changeset against its
1502 first parent only.
1510 first parent only.
1503
1511
1504 Output may be to a file, in which case the name of the file is
1512 Output may be to a file, in which case the name of the file is
1505 given using a format string. The formatting rules are as follows:
1513 given using a format string. The formatting rules are as follows:
1506
1514
1507 :``%%``: literal "%" character
1515 :``%%``: literal "%" character
1508 :``%H``: changeset hash (40 hexadecimal digits)
1516 :``%H``: changeset hash (40 hexadecimal digits)
1509 :``%N``: number of patches being generated
1517 :``%N``: number of patches being generated
1510 :``%R``: changeset revision number
1518 :``%R``: changeset revision number
1511 :``%b``: basename of the exporting repository
1519 :``%b``: basename of the exporting repository
1512 :``%h``: short-form changeset hash (12 hexadecimal digits)
1520 :``%h``: short-form changeset hash (12 hexadecimal digits)
1513 :``%n``: zero-padded sequence number, starting at 1
1521 :``%n``: zero-padded sequence number, starting at 1
1514 :``%r``: zero-padded changeset revision number
1522 :``%r``: zero-padded changeset revision number
1515
1523
1516 Without the -a/--text option, export will avoid generating diffs
1524 Without the -a/--text option, export will avoid generating diffs
1517 of files it detects as binary. With -a, export will generate a
1525 of files it detects as binary. With -a, export will generate a
1518 diff anyway, probably with undesirable results.
1526 diff anyway, probably with undesirable results.
1519
1527
1520 Use the -g/--git option to generate diffs in the git extended diff
1528 Use the -g/--git option to generate diffs in the git extended diff
1521 format. See :hg:`help diffs` for more information.
1529 format. See :hg:`help diffs` for more information.
1522
1530
1523 With the --switch-parent option, the diff will be against the
1531 With the --switch-parent option, the diff will be against the
1524 second parent. It can be useful to review a merge.
1532 second parent. It can be useful to review a merge.
1525
1533
1526 Returns 0 on success.
1534 Returns 0 on success.
1527 """
1535 """
1528 changesets += tuple(opts.get('rev', []))
1536 changesets += tuple(opts.get('rev', []))
1529 if not changesets:
1537 if not changesets:
1530 raise util.Abort(_("export requires at least one changeset"))
1538 raise util.Abort(_("export requires at least one changeset"))
1531 revs = cmdutil.revrange(repo, changesets)
1539 revs = cmdutil.revrange(repo, changesets)
1532 if len(revs) > 1:
1540 if len(revs) > 1:
1533 ui.note(_('exporting patches:\n'))
1541 ui.note(_('exporting patches:\n'))
1534 else:
1542 else:
1535 ui.note(_('exporting patch:\n'))
1543 ui.note(_('exporting patch:\n'))
1536 cmdutil.export(repo, revs, template=opts.get('output'),
1544 cmdutil.export(repo, revs, template=opts.get('output'),
1537 switch_parent=opts.get('switch_parent'),
1545 switch_parent=opts.get('switch_parent'),
1538 opts=patch.diffopts(ui, opts))
1546 opts=patch.diffopts(ui, opts))
1539
1547
1540 def forget(ui, repo, *pats, **opts):
1548 def forget(ui, repo, *pats, **opts):
1541 """forget the specified files on the next commit
1549 """forget the specified files on the next commit
1542
1550
1543 Mark the specified files so they will no longer be tracked
1551 Mark the specified files so they will no longer be tracked
1544 after the next commit.
1552 after the next commit.
1545
1553
1546 This only removes files from the current branch, not from the
1554 This only removes files from the current branch, not from the
1547 entire project history, and it does not delete them from the
1555 entire project history, and it does not delete them from the
1548 working directory.
1556 working directory.
1549
1557
1550 To undo a forget before the next commit, see :hg:`add`.
1558 To undo a forget before the next commit, see :hg:`add`.
1551
1559
1552 Returns 0 on success.
1560 Returns 0 on success.
1553 """
1561 """
1554
1562
1555 if not pats:
1563 if not pats:
1556 raise util.Abort(_('no files specified'))
1564 raise util.Abort(_('no files specified'))
1557
1565
1558 m = cmdutil.match(repo, pats, opts)
1566 m = cmdutil.match(repo, pats, opts)
1559 s = repo.status(match=m, clean=True)
1567 s = repo.status(match=m, clean=True)
1560 forget = sorted(s[0] + s[1] + s[3] + s[6])
1568 forget = sorted(s[0] + s[1] + s[3] + s[6])
1561 errs = 0
1569 errs = 0
1562
1570
1563 for f in m.files():
1571 for f in m.files():
1564 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1572 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1565 ui.warn(_('not removing %s: file is already untracked\n')
1573 ui.warn(_('not removing %s: file is already untracked\n')
1566 % m.rel(f))
1574 % m.rel(f))
1567 errs = 1
1575 errs = 1
1568
1576
1569 for f in forget:
1577 for f in forget:
1570 if ui.verbose or not m.exact(f):
1578 if ui.verbose or not m.exact(f):
1571 ui.status(_('removing %s\n') % m.rel(f))
1579 ui.status(_('removing %s\n') % m.rel(f))
1572
1580
1573 repo[None].remove(forget, unlink=False)
1581 repo[None].remove(forget, unlink=False)
1574 return errs
1582 return errs
1575
1583
1576 def grep(ui, repo, pattern, *pats, **opts):
1584 def grep(ui, repo, pattern, *pats, **opts):
1577 """search for a pattern in specified files and revisions
1585 """search for a pattern in specified files and revisions
1578
1586
1579 Search revisions of files for a regular expression.
1587 Search revisions of files for a regular expression.
1580
1588
1581 This command behaves differently than Unix grep. It only accepts
1589 This command behaves differently than Unix grep. It only accepts
1582 Python/Perl regexps. It searches repository history, not the
1590 Python/Perl regexps. It searches repository history, not the
1583 working directory. It always prints the revision number in which a
1591 working directory. It always prints the revision number in which a
1584 match appears.
1592 match appears.
1585
1593
1586 By default, grep only prints output for the first revision of a
1594 By default, grep only prints output for the first revision of a
1587 file in which it finds a match. To get it to print every revision
1595 file in which it finds a match. To get it to print every revision
1588 that contains a change in match status ("-" for a match that
1596 that contains a change in match status ("-" for a match that
1589 becomes a non-match, or "+" for a non-match that becomes a match),
1597 becomes a non-match, or "+" for a non-match that becomes a match),
1590 use the --all flag.
1598 use the --all flag.
1591
1599
1592 Returns 0 if a match is found, 1 otherwise.
1600 Returns 0 if a match is found, 1 otherwise.
1593 """
1601 """
1594 reflags = 0
1602 reflags = 0
1595 if opts.get('ignore_case'):
1603 if opts.get('ignore_case'):
1596 reflags |= re.I
1604 reflags |= re.I
1597 try:
1605 try:
1598 regexp = re.compile(pattern, reflags)
1606 regexp = re.compile(pattern, reflags)
1599 except re.error, inst:
1607 except re.error, inst:
1600 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1608 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1601 return 1
1609 return 1
1602 sep, eol = ':', '\n'
1610 sep, eol = ':', '\n'
1603 if opts.get('print0'):
1611 if opts.get('print0'):
1604 sep = eol = '\0'
1612 sep = eol = '\0'
1605
1613
1606 getfile = util.lrucachefunc(repo.file)
1614 getfile = util.lrucachefunc(repo.file)
1607
1615
1608 def matchlines(body):
1616 def matchlines(body):
1609 begin = 0
1617 begin = 0
1610 linenum = 0
1618 linenum = 0
1611 while True:
1619 while True:
1612 match = regexp.search(body, begin)
1620 match = regexp.search(body, begin)
1613 if not match:
1621 if not match:
1614 break
1622 break
1615 mstart, mend = match.span()
1623 mstart, mend = match.span()
1616 linenum += body.count('\n', begin, mstart) + 1
1624 linenum += body.count('\n', begin, mstart) + 1
1617 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1625 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1618 begin = body.find('\n', mend) + 1 or len(body)
1626 begin = body.find('\n', mend) + 1 or len(body)
1619 lend = begin - 1
1627 lend = begin - 1
1620 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1628 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1621
1629
1622 class linestate(object):
1630 class linestate(object):
1623 def __init__(self, line, linenum, colstart, colend):
1631 def __init__(self, line, linenum, colstart, colend):
1624 self.line = line
1632 self.line = line
1625 self.linenum = linenum
1633 self.linenum = linenum
1626 self.colstart = colstart
1634 self.colstart = colstart
1627 self.colend = colend
1635 self.colend = colend
1628
1636
1629 def __hash__(self):
1637 def __hash__(self):
1630 return hash((self.linenum, self.line))
1638 return hash((self.linenum, self.line))
1631
1639
1632 def __eq__(self, other):
1640 def __eq__(self, other):
1633 return self.line == other.line
1641 return self.line == other.line
1634
1642
1635 matches = {}
1643 matches = {}
1636 copies = {}
1644 copies = {}
1637 def grepbody(fn, rev, body):
1645 def grepbody(fn, rev, body):
1638 matches[rev].setdefault(fn, [])
1646 matches[rev].setdefault(fn, [])
1639 m = matches[rev][fn]
1647 m = matches[rev][fn]
1640 for lnum, cstart, cend, line in matchlines(body):
1648 for lnum, cstart, cend, line in matchlines(body):
1641 s = linestate(line, lnum, cstart, cend)
1649 s = linestate(line, lnum, cstart, cend)
1642 m.append(s)
1650 m.append(s)
1643
1651
1644 def difflinestates(a, b):
1652 def difflinestates(a, b):
1645 sm = difflib.SequenceMatcher(None, a, b)
1653 sm = difflib.SequenceMatcher(None, a, b)
1646 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1654 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1647 if tag == 'insert':
1655 if tag == 'insert':
1648 for i in xrange(blo, bhi):
1656 for i in xrange(blo, bhi):
1649 yield ('+', b[i])
1657 yield ('+', b[i])
1650 elif tag == 'delete':
1658 elif tag == 'delete':
1651 for i in xrange(alo, ahi):
1659 for i in xrange(alo, ahi):
1652 yield ('-', a[i])
1660 yield ('-', a[i])
1653 elif tag == 'replace':
1661 elif tag == 'replace':
1654 for i in xrange(alo, ahi):
1662 for i in xrange(alo, ahi):
1655 yield ('-', a[i])
1663 yield ('-', a[i])
1656 for i in xrange(blo, bhi):
1664 for i in xrange(blo, bhi):
1657 yield ('+', b[i])
1665 yield ('+', b[i])
1658
1666
1659 def display(fn, ctx, pstates, states):
1667 def display(fn, ctx, pstates, states):
1660 rev = ctx.rev()
1668 rev = ctx.rev()
1661 datefunc = ui.quiet and util.shortdate or util.datestr
1669 datefunc = ui.quiet and util.shortdate or util.datestr
1662 found = False
1670 found = False
1663 filerevmatches = {}
1671 filerevmatches = {}
1664 if opts.get('all'):
1672 if opts.get('all'):
1665 iter = difflinestates(pstates, states)
1673 iter = difflinestates(pstates, states)
1666 else:
1674 else:
1667 iter = [('', l) for l in states]
1675 iter = [('', l) for l in states]
1668 for change, l in iter:
1676 for change, l in iter:
1669 cols = [fn, str(rev)]
1677 cols = [fn, str(rev)]
1670 before, match, after = None, None, None
1678 before, match, after = None, None, None
1671 if opts.get('line_number'):
1679 if opts.get('line_number'):
1672 cols.append(str(l.linenum))
1680 cols.append(str(l.linenum))
1673 if opts.get('all'):
1681 if opts.get('all'):
1674 cols.append(change)
1682 cols.append(change)
1675 if opts.get('user'):
1683 if opts.get('user'):
1676 cols.append(ui.shortuser(ctx.user()))
1684 cols.append(ui.shortuser(ctx.user()))
1677 if opts.get('date'):
1685 if opts.get('date'):
1678 cols.append(datefunc(ctx.date()))
1686 cols.append(datefunc(ctx.date()))
1679 if opts.get('files_with_matches'):
1687 if opts.get('files_with_matches'):
1680 c = (fn, rev)
1688 c = (fn, rev)
1681 if c in filerevmatches:
1689 if c in filerevmatches:
1682 continue
1690 continue
1683 filerevmatches[c] = 1
1691 filerevmatches[c] = 1
1684 else:
1692 else:
1685 before = l.line[:l.colstart]
1693 before = l.line[:l.colstart]
1686 match = l.line[l.colstart:l.colend]
1694 match = l.line[l.colstart:l.colend]
1687 after = l.line[l.colend:]
1695 after = l.line[l.colend:]
1688 ui.write(sep.join(cols))
1696 ui.write(sep.join(cols))
1689 if before is not None:
1697 if before is not None:
1690 ui.write(sep + before)
1698 ui.write(sep + before)
1691 ui.write(match, label='grep.match')
1699 ui.write(match, label='grep.match')
1692 ui.write(after)
1700 ui.write(after)
1693 ui.write(eol)
1701 ui.write(eol)
1694 found = True
1702 found = True
1695 return found
1703 return found
1696
1704
1697 skip = {}
1705 skip = {}
1698 revfiles = {}
1706 revfiles = {}
1699 matchfn = cmdutil.match(repo, pats, opts)
1707 matchfn = cmdutil.match(repo, pats, opts)
1700 found = False
1708 found = False
1701 follow = opts.get('follow')
1709 follow = opts.get('follow')
1702
1710
1703 def prep(ctx, fns):
1711 def prep(ctx, fns):
1704 rev = ctx.rev()
1712 rev = ctx.rev()
1705 pctx = ctx.parents()[0]
1713 pctx = ctx.parents()[0]
1706 parent = pctx.rev()
1714 parent = pctx.rev()
1707 matches.setdefault(rev, {})
1715 matches.setdefault(rev, {})
1708 matches.setdefault(parent, {})
1716 matches.setdefault(parent, {})
1709 files = revfiles.setdefault(rev, [])
1717 files = revfiles.setdefault(rev, [])
1710 for fn in fns:
1718 for fn in fns:
1711 flog = getfile(fn)
1719 flog = getfile(fn)
1712 try:
1720 try:
1713 fnode = ctx.filenode(fn)
1721 fnode = ctx.filenode(fn)
1714 except error.LookupError:
1722 except error.LookupError:
1715 continue
1723 continue
1716
1724
1717 copied = flog.renamed(fnode)
1725 copied = flog.renamed(fnode)
1718 copy = follow and copied and copied[0]
1726 copy = follow and copied and copied[0]
1719 if copy:
1727 if copy:
1720 copies.setdefault(rev, {})[fn] = copy
1728 copies.setdefault(rev, {})[fn] = copy
1721 if fn in skip:
1729 if fn in skip:
1722 if copy:
1730 if copy:
1723 skip[copy] = True
1731 skip[copy] = True
1724 continue
1732 continue
1725 files.append(fn)
1733 files.append(fn)
1726
1734
1727 if fn not in matches[rev]:
1735 if fn not in matches[rev]:
1728 grepbody(fn, rev, flog.read(fnode))
1736 grepbody(fn, rev, flog.read(fnode))
1729
1737
1730 pfn = copy or fn
1738 pfn = copy or fn
1731 if pfn not in matches[parent]:
1739 if pfn not in matches[parent]:
1732 try:
1740 try:
1733 fnode = pctx.filenode(pfn)
1741 fnode = pctx.filenode(pfn)
1734 grepbody(pfn, parent, flog.read(fnode))
1742 grepbody(pfn, parent, flog.read(fnode))
1735 except error.LookupError:
1743 except error.LookupError:
1736 pass
1744 pass
1737
1745
1738 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1746 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1739 rev = ctx.rev()
1747 rev = ctx.rev()
1740 parent = ctx.parents()[0].rev()
1748 parent = ctx.parents()[0].rev()
1741 for fn in sorted(revfiles.get(rev, [])):
1749 for fn in sorted(revfiles.get(rev, [])):
1742 states = matches[rev][fn]
1750 states = matches[rev][fn]
1743 copy = copies.get(rev, {}).get(fn)
1751 copy = copies.get(rev, {}).get(fn)
1744 if fn in skip:
1752 if fn in skip:
1745 if copy:
1753 if copy:
1746 skip[copy] = True
1754 skip[copy] = True
1747 continue
1755 continue
1748 pstates = matches.get(parent, {}).get(copy or fn, [])
1756 pstates = matches.get(parent, {}).get(copy or fn, [])
1749 if pstates or states:
1757 if pstates or states:
1750 r = display(fn, ctx, pstates, states)
1758 r = display(fn, ctx, pstates, states)
1751 found = found or r
1759 found = found or r
1752 if r and not opts.get('all'):
1760 if r and not opts.get('all'):
1753 skip[fn] = True
1761 skip[fn] = True
1754 if copy:
1762 if copy:
1755 skip[copy] = True
1763 skip[copy] = True
1756 del matches[rev]
1764 del matches[rev]
1757 del revfiles[rev]
1765 del revfiles[rev]
1758
1766
1759 return not found
1767 return not found
1760
1768
1761 def heads(ui, repo, *branchrevs, **opts):
1769 def heads(ui, repo, *branchrevs, **opts):
1762 """show current repository heads or show branch heads
1770 """show current repository heads or show branch heads
1763
1771
1764 With no arguments, show all repository branch heads.
1772 With no arguments, show all repository branch heads.
1765
1773
1766 Repository "heads" are changesets with no child changesets. They are
1774 Repository "heads" are changesets with no child changesets. They are
1767 where development generally takes place and are the usual targets
1775 where development generally takes place and are the usual targets
1768 for update and merge operations. Branch heads are changesets that have
1776 for update and merge operations. Branch heads are changesets that have
1769 no child changeset on the same branch.
1777 no child changeset on the same branch.
1770
1778
1771 If one or more REVs are given, only branch heads on the branches
1779 If one or more REVs are given, only branch heads on the branches
1772 associated with the specified changesets are shown.
1780 associated with the specified changesets are shown.
1773
1781
1774 If -c/--closed is specified, also show branch heads marked closed
1782 If -c/--closed is specified, also show branch heads marked closed
1775 (see :hg:`commit --close-branch`).
1783 (see :hg:`commit --close-branch`).
1776
1784
1777 If STARTREV is specified, only those heads that are descendants of
1785 If STARTREV is specified, only those heads that are descendants of
1778 STARTREV will be displayed.
1786 STARTREV will be displayed.
1779
1787
1780 If -t/--topo is specified, named branch mechanics will be ignored and only
1788 If -t/--topo is specified, named branch mechanics will be ignored and only
1781 changesets without children will be shown.
1789 changesets without children will be shown.
1782
1790
1783 Returns 0 if matching heads are found, 1 if not.
1791 Returns 0 if matching heads are found, 1 if not.
1784 """
1792 """
1785
1793
1786 if opts.get('rev'):
1794 if opts.get('rev'):
1787 start = repo.lookup(opts['rev'])
1795 start = repo.lookup(opts['rev'])
1788 else:
1796 else:
1789 start = None
1797 start = None
1790
1798
1791 if opts.get('topo'):
1799 if opts.get('topo'):
1792 heads = [repo[h] for h in repo.heads(start)]
1800 heads = [repo[h] for h in repo.heads(start)]
1793 else:
1801 else:
1794 heads = []
1802 heads = []
1795 for b, ls in repo.branchmap().iteritems():
1803 for b, ls in repo.branchmap().iteritems():
1796 if start is None:
1804 if start is None:
1797 heads += [repo[h] for h in ls]
1805 heads += [repo[h] for h in ls]
1798 continue
1806 continue
1799 startrev = repo.changelog.rev(start)
1807 startrev = repo.changelog.rev(start)
1800 descendants = set(repo.changelog.descendants(startrev))
1808 descendants = set(repo.changelog.descendants(startrev))
1801 descendants.add(startrev)
1809 descendants.add(startrev)
1802 rev = repo.changelog.rev
1810 rev = repo.changelog.rev
1803 heads += [repo[h] for h in ls if rev(h) in descendants]
1811 heads += [repo[h] for h in ls if rev(h) in descendants]
1804
1812
1805 if branchrevs:
1813 if branchrevs:
1806 decode, encode = encoding.fromlocal, encoding.tolocal
1814 decode, encode = encoding.fromlocal, encoding.tolocal
1807 branches = set(repo[decode(br)].branch() for br in branchrevs)
1815 branches = set(repo[decode(br)].branch() for br in branchrevs)
1808 heads = [h for h in heads if h.branch() in branches]
1816 heads = [h for h in heads if h.branch() in branches]
1809
1817
1810 if not opts.get('closed'):
1818 if not opts.get('closed'):
1811 heads = [h for h in heads if not h.extra().get('close')]
1819 heads = [h for h in heads if not h.extra().get('close')]
1812
1820
1813 if opts.get('active') and branchrevs:
1821 if opts.get('active') and branchrevs:
1814 dagheads = repo.heads(start)
1822 dagheads = repo.heads(start)
1815 heads = [h for h in heads if h.node() in dagheads]
1823 heads = [h for h in heads if h.node() in dagheads]
1816
1824
1817 if branchrevs:
1825 if branchrevs:
1818 haveheads = set(h.branch() for h in heads)
1826 haveheads = set(h.branch() for h in heads)
1819 if branches - haveheads:
1827 if branches - haveheads:
1820 headless = ', '.join(encode(b) for b in branches - haveheads)
1828 headless = ', '.join(encode(b) for b in branches - haveheads)
1821 msg = _('no open branch heads found on branches %s')
1829 msg = _('no open branch heads found on branches %s')
1822 if opts.get('rev'):
1830 if opts.get('rev'):
1823 msg += _(' (started at %s)' % opts['rev'])
1831 msg += _(' (started at %s)' % opts['rev'])
1824 ui.warn((msg + '\n') % headless)
1832 ui.warn((msg + '\n') % headless)
1825
1833
1826 if not heads:
1834 if not heads:
1827 return 1
1835 return 1
1828
1836
1829 heads = sorted(heads, key=lambda x: -x.rev())
1837 heads = sorted(heads, key=lambda x: -x.rev())
1830 displayer = cmdutil.show_changeset(ui, repo, opts)
1838 displayer = cmdutil.show_changeset(ui, repo, opts)
1831 for ctx in heads:
1839 for ctx in heads:
1832 displayer.show(ctx)
1840 displayer.show(ctx)
1833 displayer.close()
1841 displayer.close()
1834
1842
1835 def help_(ui, name=None, with_version=False, unknowncmd=False):
1843 def help_(ui, name=None, with_version=False, unknowncmd=False):
1836 """show help for a given topic or a help overview
1844 """show help for a given topic or a help overview
1837
1845
1838 With no arguments, print a list of commands with short help messages.
1846 With no arguments, print a list of commands with short help messages.
1839
1847
1840 Given a topic, extension, or command name, print help for that
1848 Given a topic, extension, or command name, print help for that
1841 topic.
1849 topic.
1842
1850
1843 Returns 0 if successful.
1851 Returns 0 if successful.
1844 """
1852 """
1845 option_lists = []
1853 option_lists = []
1846 textwidth = ui.termwidth() - 2
1854 textwidth = ui.termwidth() - 2
1847
1855
1848 def addglobalopts(aliases):
1856 def addglobalopts(aliases):
1849 if ui.verbose:
1857 if ui.verbose:
1850 option_lists.append((_("global options:"), globalopts))
1858 option_lists.append((_("global options:"), globalopts))
1851 if name == 'shortlist':
1859 if name == 'shortlist':
1852 option_lists.append((_('use "hg help" for the full list '
1860 option_lists.append((_('use "hg help" for the full list '
1853 'of commands'), ()))
1861 'of commands'), ()))
1854 else:
1862 else:
1855 if name == 'shortlist':
1863 if name == 'shortlist':
1856 msg = _('use "hg help" for the full list of commands '
1864 msg = _('use "hg help" for the full list of commands '
1857 'or "hg -v" for details')
1865 'or "hg -v" for details')
1858 elif aliases:
1866 elif aliases:
1859 msg = _('use "hg -v help%s" to show aliases and '
1867 msg = _('use "hg -v help%s" to show aliases and '
1860 'global options') % (name and " " + name or "")
1868 'global options') % (name and " " + name or "")
1861 else:
1869 else:
1862 msg = _('use "hg -v help %s" to show global options') % name
1870 msg = _('use "hg -v help %s" to show global options') % name
1863 option_lists.append((msg, ()))
1871 option_lists.append((msg, ()))
1864
1872
1865 def helpcmd(name):
1873 def helpcmd(name):
1866 if with_version:
1874 if with_version:
1867 version_(ui)
1875 version_(ui)
1868 ui.write('\n')
1876 ui.write('\n')
1869
1877
1870 try:
1878 try:
1871 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1879 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
1872 except error.AmbiguousCommand, inst:
1880 except error.AmbiguousCommand, inst:
1873 # py3k fix: except vars can't be used outside the scope of the
1881 # py3k fix: except vars can't be used outside the scope of the
1874 # except block, nor can be used inside a lambda. python issue4617
1882 # except block, nor can be used inside a lambda. python issue4617
1875 prefix = inst.args[0]
1883 prefix = inst.args[0]
1876 select = lambda c: c.lstrip('^').startswith(prefix)
1884 select = lambda c: c.lstrip('^').startswith(prefix)
1877 helplist(_('list of commands:\n\n'), select)
1885 helplist(_('list of commands:\n\n'), select)
1878 return
1886 return
1879
1887
1880 # check if it's an invalid alias and display its error if it is
1888 # check if it's an invalid alias and display its error if it is
1881 if getattr(entry[0], 'badalias', False):
1889 if getattr(entry[0], 'badalias', False):
1882 if not unknowncmd:
1890 if not unknowncmd:
1883 entry[0](ui)
1891 entry[0](ui)
1884 return
1892 return
1885
1893
1886 # synopsis
1894 # synopsis
1887 if len(entry) > 2:
1895 if len(entry) > 2:
1888 if entry[2].startswith('hg'):
1896 if entry[2].startswith('hg'):
1889 ui.write("%s\n" % entry[2])
1897 ui.write("%s\n" % entry[2])
1890 else:
1898 else:
1891 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1899 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
1892 else:
1900 else:
1893 ui.write('hg %s\n' % aliases[0])
1901 ui.write('hg %s\n' % aliases[0])
1894
1902
1895 # aliases
1903 # aliases
1896 if not ui.quiet and len(aliases) > 1:
1904 if not ui.quiet and len(aliases) > 1:
1897 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1905 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1898
1906
1899 # description
1907 # description
1900 doc = gettext(entry[0].__doc__)
1908 doc = gettext(entry[0].__doc__)
1901 if not doc:
1909 if not doc:
1902 doc = _("(no help text available)")
1910 doc = _("(no help text available)")
1903 if hasattr(entry[0], 'definition'): # aliased command
1911 if hasattr(entry[0], 'definition'): # aliased command
1904 if entry[0].definition.startswith('!'): # shell alias
1912 if entry[0].definition.startswith('!'): # shell alias
1905 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1913 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
1906 else:
1914 else:
1907 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1915 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
1908 if ui.quiet:
1916 if ui.quiet:
1909 doc = doc.splitlines()[0]
1917 doc = doc.splitlines()[0]
1910 keep = ui.verbose and ['verbose'] or []
1918 keep = ui.verbose and ['verbose'] or []
1911 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1919 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
1912 ui.write("\n%s\n" % formatted)
1920 ui.write("\n%s\n" % formatted)
1913 if pruned:
1921 if pruned:
1914 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1922 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
1915
1923
1916 if not ui.quiet:
1924 if not ui.quiet:
1917 # options
1925 # options
1918 if entry[1]:
1926 if entry[1]:
1919 option_lists.append((_("options:\n"), entry[1]))
1927 option_lists.append((_("options:\n"), entry[1]))
1920
1928
1921 addglobalopts(False)
1929 addglobalopts(False)
1922
1930
1923 def helplist(header, select=None):
1931 def helplist(header, select=None):
1924 h = {}
1932 h = {}
1925 cmds = {}
1933 cmds = {}
1926 for c, e in table.iteritems():
1934 for c, e in table.iteritems():
1927 f = c.split("|", 1)[0]
1935 f = c.split("|", 1)[0]
1928 if select and not select(f):
1936 if select and not select(f):
1929 continue
1937 continue
1930 if (not select and name != 'shortlist' and
1938 if (not select and name != 'shortlist' and
1931 e[0].__module__ != __name__):
1939 e[0].__module__ != __name__):
1932 continue
1940 continue
1933 if name == "shortlist" and not f.startswith("^"):
1941 if name == "shortlist" and not f.startswith("^"):
1934 continue
1942 continue
1935 f = f.lstrip("^")
1943 f = f.lstrip("^")
1936 if not ui.debugflag and f.startswith("debug"):
1944 if not ui.debugflag and f.startswith("debug"):
1937 continue
1945 continue
1938 doc = e[0].__doc__
1946 doc = e[0].__doc__
1939 if doc and 'DEPRECATED' in doc and not ui.verbose:
1947 if doc and 'DEPRECATED' in doc and not ui.verbose:
1940 continue
1948 continue
1941 doc = gettext(doc)
1949 doc = gettext(doc)
1942 if not doc:
1950 if not doc:
1943 doc = _("(no help text available)")
1951 doc = _("(no help text available)")
1944 h[f] = doc.splitlines()[0].rstrip()
1952 h[f] = doc.splitlines()[0].rstrip()
1945 cmds[f] = c.lstrip("^")
1953 cmds[f] = c.lstrip("^")
1946
1954
1947 if not h:
1955 if not h:
1948 ui.status(_('no commands defined\n'))
1956 ui.status(_('no commands defined\n'))
1949 return
1957 return
1950
1958
1951 ui.status(header)
1959 ui.status(header)
1952 fns = sorted(h)
1960 fns = sorted(h)
1953 m = max(map(len, fns))
1961 m = max(map(len, fns))
1954 for f in fns:
1962 for f in fns:
1955 if ui.verbose:
1963 if ui.verbose:
1956 commands = cmds[f].replace("|",", ")
1964 commands = cmds[f].replace("|",", ")
1957 ui.write(" %s:\n %s\n"%(commands, h[f]))
1965 ui.write(" %s:\n %s\n"%(commands, h[f]))
1958 else:
1966 else:
1959 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1967 ui.write('%s\n' % (util.wrap(h[f], textwidth,
1960 initindent=' %-*s ' % (m, f),
1968 initindent=' %-*s ' % (m, f),
1961 hangindent=' ' * (m + 4))))
1969 hangindent=' ' * (m + 4))))
1962
1970
1963 if not ui.quiet:
1971 if not ui.quiet:
1964 addglobalopts(True)
1972 addglobalopts(True)
1965
1973
1966 def helptopic(name):
1974 def helptopic(name):
1967 for names, header, doc in help.helptable:
1975 for names, header, doc in help.helptable:
1968 if name in names:
1976 if name in names:
1969 break
1977 break
1970 else:
1978 else:
1971 raise error.UnknownCommand(name)
1979 raise error.UnknownCommand(name)
1972
1980
1973 # description
1981 # description
1974 if not doc:
1982 if not doc:
1975 doc = _("(no help text available)")
1983 doc = _("(no help text available)")
1976 if hasattr(doc, '__call__'):
1984 if hasattr(doc, '__call__'):
1977 doc = doc()
1985 doc = doc()
1978
1986
1979 ui.write("%s\n\n" % header)
1987 ui.write("%s\n\n" % header)
1980 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1988 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
1981
1989
1982 def helpext(name):
1990 def helpext(name):
1983 try:
1991 try:
1984 mod = extensions.find(name)
1992 mod = extensions.find(name)
1985 doc = gettext(mod.__doc__) or _('no help text available')
1993 doc = gettext(mod.__doc__) or _('no help text available')
1986 except KeyError:
1994 except KeyError:
1987 mod = None
1995 mod = None
1988 doc = extensions.disabledext(name)
1996 doc = extensions.disabledext(name)
1989 if not doc:
1997 if not doc:
1990 raise error.UnknownCommand(name)
1998 raise error.UnknownCommand(name)
1991
1999
1992 if '\n' not in doc:
2000 if '\n' not in doc:
1993 head, tail = doc, ""
2001 head, tail = doc, ""
1994 else:
2002 else:
1995 head, tail = doc.split('\n', 1)
2003 head, tail = doc.split('\n', 1)
1996 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2004 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
1997 if tail:
2005 if tail:
1998 ui.write(minirst.format(tail, textwidth))
2006 ui.write(minirst.format(tail, textwidth))
1999 ui.status('\n\n')
2007 ui.status('\n\n')
2000
2008
2001 if mod:
2009 if mod:
2002 try:
2010 try:
2003 ct = mod.cmdtable
2011 ct = mod.cmdtable
2004 except AttributeError:
2012 except AttributeError:
2005 ct = {}
2013 ct = {}
2006 modcmds = set([c.split('|', 1)[0] for c in ct])
2014 modcmds = set([c.split('|', 1)[0] for c in ct])
2007 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2015 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2008 else:
2016 else:
2009 ui.write(_('use "hg help extensions" for information on enabling '
2017 ui.write(_('use "hg help extensions" for information on enabling '
2010 'extensions\n'))
2018 'extensions\n'))
2011
2019
2012 def helpextcmd(name):
2020 def helpextcmd(name):
2013 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2021 cmd, ext, mod = extensions.disabledcmd(name, ui.config('ui', 'strict'))
2014 doc = gettext(mod.__doc__).splitlines()[0]
2022 doc = gettext(mod.__doc__).splitlines()[0]
2015
2023
2016 msg = help.listexts(_("'%s' is provided by the following "
2024 msg = help.listexts(_("'%s' is provided by the following "
2017 "extension:") % cmd, {ext: doc}, len(ext),
2025 "extension:") % cmd, {ext: doc}, len(ext),
2018 indent=4)
2026 indent=4)
2019 ui.write(minirst.format(msg, textwidth))
2027 ui.write(minirst.format(msg, textwidth))
2020 ui.write('\n\n')
2028 ui.write('\n\n')
2021 ui.write(_('use "hg help extensions" for information on enabling '
2029 ui.write(_('use "hg help extensions" for information on enabling '
2022 'extensions\n'))
2030 'extensions\n'))
2023
2031
2024 if name and name != 'shortlist':
2032 if name and name != 'shortlist':
2025 i = None
2033 i = None
2026 if unknowncmd:
2034 if unknowncmd:
2027 queries = (helpextcmd,)
2035 queries = (helpextcmd,)
2028 else:
2036 else:
2029 queries = (helptopic, helpcmd, helpext, helpextcmd)
2037 queries = (helptopic, helpcmd, helpext, helpextcmd)
2030 for f in queries:
2038 for f in queries:
2031 try:
2039 try:
2032 f(name)
2040 f(name)
2033 i = None
2041 i = None
2034 break
2042 break
2035 except error.UnknownCommand, inst:
2043 except error.UnknownCommand, inst:
2036 i = inst
2044 i = inst
2037 if i:
2045 if i:
2038 raise i
2046 raise i
2039
2047
2040 else:
2048 else:
2041 # program name
2049 # program name
2042 if ui.verbose or with_version:
2050 if ui.verbose or with_version:
2043 version_(ui)
2051 version_(ui)
2044 else:
2052 else:
2045 ui.status(_("Mercurial Distributed SCM\n"))
2053 ui.status(_("Mercurial Distributed SCM\n"))
2046 ui.status('\n')
2054 ui.status('\n')
2047
2055
2048 # list of commands
2056 # list of commands
2049 if name == "shortlist":
2057 if name == "shortlist":
2050 header = _('basic commands:\n\n')
2058 header = _('basic commands:\n\n')
2051 else:
2059 else:
2052 header = _('list of commands:\n\n')
2060 header = _('list of commands:\n\n')
2053
2061
2054 helplist(header)
2062 helplist(header)
2055 if name != 'shortlist':
2063 if name != 'shortlist':
2056 exts, maxlength = extensions.enabled()
2064 exts, maxlength = extensions.enabled()
2057 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2065 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2058 if text:
2066 if text:
2059 ui.write("\n%s\n" % minirst.format(text, textwidth))
2067 ui.write("\n%s\n" % minirst.format(text, textwidth))
2060
2068
2061 # list all option lists
2069 # list all option lists
2062 opt_output = []
2070 opt_output = []
2063 multioccur = False
2071 multioccur = False
2064 for title, options in option_lists:
2072 for title, options in option_lists:
2065 opt_output.append(("\n%s" % title, None))
2073 opt_output.append(("\n%s" % title, None))
2066 for option in options:
2074 for option in options:
2067 if len(option) == 5:
2075 if len(option) == 5:
2068 shortopt, longopt, default, desc, optlabel = option
2076 shortopt, longopt, default, desc, optlabel = option
2069 else:
2077 else:
2070 shortopt, longopt, default, desc = option
2078 shortopt, longopt, default, desc = option
2071 optlabel = _("VALUE") # default label
2079 optlabel = _("VALUE") # default label
2072
2080
2073 if _("DEPRECATED") in desc and not ui.verbose:
2081 if _("DEPRECATED") in desc and not ui.verbose:
2074 continue
2082 continue
2075 if isinstance(default, list):
2083 if isinstance(default, list):
2076 numqualifier = " %s [+]" % optlabel
2084 numqualifier = " %s [+]" % optlabel
2077 multioccur = True
2085 multioccur = True
2078 elif (default is not None) and not isinstance(default, bool):
2086 elif (default is not None) and not isinstance(default, bool):
2079 numqualifier = " %s" % optlabel
2087 numqualifier = " %s" % optlabel
2080 else:
2088 else:
2081 numqualifier = ""
2089 numqualifier = ""
2082 opt_output.append(("%2s%s" %
2090 opt_output.append(("%2s%s" %
2083 (shortopt and "-%s" % shortopt,
2091 (shortopt and "-%s" % shortopt,
2084 longopt and " --%s%s" %
2092 longopt and " --%s%s" %
2085 (longopt, numqualifier)),
2093 (longopt, numqualifier)),
2086 "%s%s" % (desc,
2094 "%s%s" % (desc,
2087 default
2095 default
2088 and _(" (default: %s)") % default
2096 and _(" (default: %s)") % default
2089 or "")))
2097 or "")))
2090 if multioccur:
2098 if multioccur:
2091 msg = _("\n[+] marked option can be specified multiple times")
2099 msg = _("\n[+] marked option can be specified multiple times")
2092 if ui.verbose and name != 'shortlist':
2100 if ui.verbose and name != 'shortlist':
2093 opt_output.append((msg, None))
2101 opt_output.append((msg, None))
2094 else:
2102 else:
2095 opt_output.insert(-1, (msg, None))
2103 opt_output.insert(-1, (msg, None))
2096
2104
2097 if not name:
2105 if not name:
2098 ui.write(_("\nadditional help topics:\n\n"))
2106 ui.write(_("\nadditional help topics:\n\n"))
2099 topics = []
2107 topics = []
2100 for names, header, doc in help.helptable:
2108 for names, header, doc in help.helptable:
2101 topics.append((sorted(names, key=len, reverse=True)[0], header))
2109 topics.append((sorted(names, key=len, reverse=True)[0], header))
2102 topics_len = max([len(s[0]) for s in topics])
2110 topics_len = max([len(s[0]) for s in topics])
2103 for t, desc in topics:
2111 for t, desc in topics:
2104 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2112 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2105
2113
2106 if opt_output:
2114 if opt_output:
2107 colwidth = encoding.colwidth
2115 colwidth = encoding.colwidth
2108 # normalize: (opt or message, desc or None, width of opt)
2116 # normalize: (opt or message, desc or None, width of opt)
2109 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2117 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2110 for opt, desc in opt_output]
2118 for opt, desc in opt_output]
2111 hanging = max([e[2] for e in entries])
2119 hanging = max([e[2] for e in entries])
2112 for opt, desc, width in entries:
2120 for opt, desc, width in entries:
2113 if desc:
2121 if desc:
2114 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2122 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2115 hangindent = ' ' * (hanging + 3)
2123 hangindent = ' ' * (hanging + 3)
2116 ui.write('%s\n' % (util.wrap(desc, textwidth,
2124 ui.write('%s\n' % (util.wrap(desc, textwidth,
2117 initindent=initindent,
2125 initindent=initindent,
2118 hangindent=hangindent)))
2126 hangindent=hangindent)))
2119 else:
2127 else:
2120 ui.write("%s\n" % opt)
2128 ui.write("%s\n" % opt)
2121
2129
2122 def identify(ui, repo, source=None,
2130 def identify(ui, repo, source=None,
2123 rev=None, num=None, id=None, branch=None, tags=None):
2131 rev=None, num=None, id=None, branch=None, tags=None):
2124 """identify the working copy or specified revision
2132 """identify the working copy or specified revision
2125
2133
2126 With no revision, print a summary of the current state of the
2134 With no revision, print a summary of the current state of the
2127 repository.
2135 repository.
2128
2136
2129 Specifying a path to a repository root or Mercurial bundle will
2137 Specifying a path to a repository root or Mercurial bundle will
2130 cause lookup to operate on that repository/bundle.
2138 cause lookup to operate on that repository/bundle.
2131
2139
2132 This summary identifies the repository state using one or two
2140 This summary identifies the repository state using one or two
2133 parent hash identifiers, followed by a "+" if there are
2141 parent hash identifiers, followed by a "+" if there are
2134 uncommitted changes in the working directory, a list of tags for
2142 uncommitted changes in the working directory, a list of tags for
2135 this revision and a branch name for non-default branches.
2143 this revision and a branch name for non-default branches.
2136
2144
2137 Returns 0 if successful.
2145 Returns 0 if successful.
2138 """
2146 """
2139
2147
2140 if not repo and not source:
2148 if not repo and not source:
2141 raise util.Abort(_("there is no Mercurial repository here "
2149 raise util.Abort(_("there is no Mercurial repository here "
2142 "(.hg not found)"))
2150 "(.hg not found)"))
2143
2151
2144 hexfunc = ui.debugflag and hex or short
2152 hexfunc = ui.debugflag and hex or short
2145 default = not (num or id or branch or tags)
2153 default = not (num or id or branch or tags)
2146 output = []
2154 output = []
2147
2155
2148 revs = []
2156 revs = []
2149 if source:
2157 if source:
2150 source, branches = hg.parseurl(ui.expandpath(source))
2158 source, branches = hg.parseurl(ui.expandpath(source))
2151 repo = hg.repository(ui, source)
2159 repo = hg.repository(ui, source)
2152 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2160 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2153
2161
2154 if not repo.local():
2162 if not repo.local():
2155 if not rev and revs:
2163 if not rev and revs:
2156 rev = revs[0]
2164 rev = revs[0]
2157 if not rev:
2165 if not rev:
2158 rev = "tip"
2166 rev = "tip"
2159 if num or branch or tags:
2167 if num or branch or tags:
2160 raise util.Abort(
2168 raise util.Abort(
2161 "can't query remote revision number, branch, or tags")
2169 "can't query remote revision number, branch, or tags")
2162 output = [hexfunc(repo.lookup(rev))]
2170 output = [hexfunc(repo.lookup(rev))]
2163 elif not rev:
2171 elif not rev:
2164 ctx = repo[None]
2172 ctx = repo[None]
2165 parents = ctx.parents()
2173 parents = ctx.parents()
2166 changed = False
2174 changed = False
2167 if default or id or num:
2175 if default or id or num:
2168 changed = util.any(repo.status())
2176 changed = util.any(repo.status())
2169 if default or id:
2177 if default or id:
2170 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2178 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
2171 (changed) and "+" or "")]
2179 (changed) and "+" or "")]
2172 if num:
2180 if num:
2173 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2181 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
2174 (changed) and "+" or ""))
2182 (changed) and "+" or ""))
2175 else:
2183 else:
2176 ctx = repo[rev]
2184 ctx = repo[rev]
2177 if default or id:
2185 if default or id:
2178 output = [hexfunc(ctx.node())]
2186 output = [hexfunc(ctx.node())]
2179 if num:
2187 if num:
2180 output.append(str(ctx.rev()))
2188 output.append(str(ctx.rev()))
2181
2189
2182 if repo.local() and default and not ui.quiet:
2190 if repo.local() and default and not ui.quiet:
2183 b = encoding.tolocal(ctx.branch())
2191 b = encoding.tolocal(ctx.branch())
2184 if b != 'default':
2192 if b != 'default':
2185 output.append("(%s)" % b)
2193 output.append("(%s)" % b)
2186
2194
2187 # multiple tags for a single parent separated by '/'
2195 # multiple tags for a single parent separated by '/'
2188 t = "/".join(ctx.tags())
2196 t = "/".join(ctx.tags())
2189 if t:
2197 if t:
2190 output.append(t)
2198 output.append(t)
2191
2199
2192 if branch:
2200 if branch:
2193 output.append(encoding.tolocal(ctx.branch()))
2201 output.append(encoding.tolocal(ctx.branch()))
2194
2202
2195 if tags:
2203 if tags:
2196 output.extend(ctx.tags())
2204 output.extend(ctx.tags())
2197
2205
2198 ui.write("%s\n" % ' '.join(output))
2206 ui.write("%s\n" % ' '.join(output))
2199
2207
2200 def import_(ui, repo, patch1, *patches, **opts):
2208 def import_(ui, repo, patch1, *patches, **opts):
2201 """import an ordered set of patches
2209 """import an ordered set of patches
2202
2210
2203 Import a list of patches and commit them individually (unless
2211 Import a list of patches and commit them individually (unless
2204 --no-commit is specified).
2212 --no-commit is specified).
2205
2213
2206 If there are outstanding changes in the working directory, import
2214 If there are outstanding changes in the working directory, import
2207 will abort unless given the -f/--force flag.
2215 will abort unless given the -f/--force flag.
2208
2216
2209 You can import a patch straight from a mail message. Even patches
2217 You can import a patch straight from a mail message. Even patches
2210 as attachments work (to use the body part, it must have type
2218 as attachments work (to use the body part, it must have type
2211 text/plain or text/x-patch). From and Subject headers of email
2219 text/plain or text/x-patch). From and Subject headers of email
2212 message are used as default committer and commit message. All
2220 message are used as default committer and commit message. All
2213 text/plain body parts before first diff are added to commit
2221 text/plain body parts before first diff are added to commit
2214 message.
2222 message.
2215
2223
2216 If the imported patch was generated by :hg:`export`, user and
2224 If the imported patch was generated by :hg:`export`, user and
2217 description from patch override values from message headers and
2225 description from patch override values from message headers and
2218 body. Values given on command line with -m/--message and -u/--user
2226 body. Values given on command line with -m/--message and -u/--user
2219 override these.
2227 override these.
2220
2228
2221 If --exact is specified, import will set the working directory to
2229 If --exact is specified, import will set the working directory to
2222 the parent of each patch before applying it, and will abort if the
2230 the parent of each patch before applying it, and will abort if the
2223 resulting changeset has a different ID than the one recorded in
2231 resulting changeset has a different ID than the one recorded in
2224 the patch. This may happen due to character set problems or other
2232 the patch. This may happen due to character set problems or other
2225 deficiencies in the text patch format.
2233 deficiencies in the text patch format.
2226
2234
2227 With -s/--similarity, hg will attempt to discover renames and
2235 With -s/--similarity, hg will attempt to discover renames and
2228 copies in the patch in the same way as 'addremove'.
2236 copies in the patch in the same way as 'addremove'.
2229
2237
2230 To read a patch from standard input, use "-" as the patch name. If
2238 To read a patch from standard input, use "-" as the patch name. If
2231 a URL is specified, the patch will be downloaded from it.
2239 a URL is specified, the patch will be downloaded from it.
2232 See :hg:`help dates` for a list of formats valid for -d/--date.
2240 See :hg:`help dates` for a list of formats valid for -d/--date.
2233
2241
2234 Returns 0 on success.
2242 Returns 0 on success.
2235 """
2243 """
2236 patches = (patch1,) + patches
2244 patches = (patch1,) + patches
2237
2245
2238 date = opts.get('date')
2246 date = opts.get('date')
2239 if date:
2247 if date:
2240 opts['date'] = util.parsedate(date)
2248 opts['date'] = util.parsedate(date)
2241
2249
2242 try:
2250 try:
2243 sim = float(opts.get('similarity') or 0)
2251 sim = float(opts.get('similarity') or 0)
2244 except ValueError:
2252 except ValueError:
2245 raise util.Abort(_('similarity must be a number'))
2253 raise util.Abort(_('similarity must be a number'))
2246 if sim < 0 or sim > 100:
2254 if sim < 0 or sim > 100:
2247 raise util.Abort(_('similarity must be between 0 and 100'))
2255 raise util.Abort(_('similarity must be between 0 and 100'))
2248
2256
2249 if opts.get('exact') or not opts.get('force'):
2257 if opts.get('exact') or not opts.get('force'):
2250 cmdutil.bail_if_changed(repo)
2258 cmdutil.bail_if_changed(repo)
2251
2259
2252 d = opts["base"]
2260 d = opts["base"]
2253 strip = opts["strip"]
2261 strip = opts["strip"]
2254 wlock = lock = None
2262 wlock = lock = None
2255
2263
2256 def tryone(ui, hunk):
2264 def tryone(ui, hunk):
2257 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2265 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2258 patch.extract(ui, hunk)
2266 patch.extract(ui, hunk)
2259
2267
2260 if not tmpname:
2268 if not tmpname:
2261 return None
2269 return None
2262 commitid = _('to working directory')
2270 commitid = _('to working directory')
2263
2271
2264 try:
2272 try:
2265 cmdline_message = cmdutil.logmessage(opts)
2273 cmdline_message = cmdutil.logmessage(opts)
2266 if cmdline_message:
2274 if cmdline_message:
2267 # pickup the cmdline msg
2275 # pickup the cmdline msg
2268 message = cmdline_message
2276 message = cmdline_message
2269 elif message:
2277 elif message:
2270 # pickup the patch msg
2278 # pickup the patch msg
2271 message = message.strip()
2279 message = message.strip()
2272 else:
2280 else:
2273 # launch the editor
2281 # launch the editor
2274 message = None
2282 message = None
2275 ui.debug('message:\n%s\n' % message)
2283 ui.debug('message:\n%s\n' % message)
2276
2284
2277 wp = repo.parents()
2285 wp = repo.parents()
2278 if opts.get('exact'):
2286 if opts.get('exact'):
2279 if not nodeid or not p1:
2287 if not nodeid or not p1:
2280 raise util.Abort(_('not a Mercurial patch'))
2288 raise util.Abort(_('not a Mercurial patch'))
2281 p1 = repo.lookup(p1)
2289 p1 = repo.lookup(p1)
2282 p2 = repo.lookup(p2 or hex(nullid))
2290 p2 = repo.lookup(p2 or hex(nullid))
2283
2291
2284 if p1 != wp[0].node():
2292 if p1 != wp[0].node():
2285 hg.clean(repo, p1)
2293 hg.clean(repo, p1)
2286 repo.dirstate.setparents(p1, p2)
2294 repo.dirstate.setparents(p1, p2)
2287 elif p2:
2295 elif p2:
2288 try:
2296 try:
2289 p1 = repo.lookup(p1)
2297 p1 = repo.lookup(p1)
2290 p2 = repo.lookup(p2)
2298 p2 = repo.lookup(p2)
2291 if p1 == wp[0].node():
2299 if p1 == wp[0].node():
2292 repo.dirstate.setparents(p1, p2)
2300 repo.dirstate.setparents(p1, p2)
2293 except error.RepoError:
2301 except error.RepoError:
2294 pass
2302 pass
2295 if opts.get('exact') or opts.get('import_branch'):
2303 if opts.get('exact') or opts.get('import_branch'):
2296 repo.dirstate.setbranch(branch or 'default')
2304 repo.dirstate.setbranch(branch or 'default')
2297
2305
2298 files = {}
2306 files = {}
2299 try:
2307 try:
2300 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2308 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2301 files=files, eolmode=None)
2309 files=files, eolmode=None)
2302 finally:
2310 finally:
2303 files = cmdutil.updatedir(ui, repo, files,
2311 files = cmdutil.updatedir(ui, repo, files,
2304 similarity=sim / 100.0)
2312 similarity=sim / 100.0)
2305 if not opts.get('no_commit'):
2313 if not opts.get('no_commit'):
2306 if opts.get('exact'):
2314 if opts.get('exact'):
2307 m = None
2315 m = None
2308 else:
2316 else:
2309 m = cmdutil.matchfiles(repo, files or [])
2317 m = cmdutil.matchfiles(repo, files or [])
2310 n = repo.commit(message, opts.get('user') or user,
2318 n = repo.commit(message, opts.get('user') or user,
2311 opts.get('date') or date, match=m,
2319 opts.get('date') or date, match=m,
2312 editor=cmdutil.commiteditor)
2320 editor=cmdutil.commiteditor)
2313 if opts.get('exact'):
2321 if opts.get('exact'):
2314 if hex(n) != nodeid:
2322 if hex(n) != nodeid:
2315 repo.rollback()
2323 repo.rollback()
2316 raise util.Abort(_('patch is damaged'
2324 raise util.Abort(_('patch is damaged'
2317 ' or loses information'))
2325 ' or loses information'))
2318 # Force a dirstate write so that the next transaction
2326 # Force a dirstate write so that the next transaction
2319 # backups an up-do-date file.
2327 # backups an up-do-date file.
2320 repo.dirstate.write()
2328 repo.dirstate.write()
2321 if n:
2329 if n:
2322 commitid = short(n)
2330 commitid = short(n)
2323
2331
2324 return commitid
2332 return commitid
2325 finally:
2333 finally:
2326 os.unlink(tmpname)
2334 os.unlink(tmpname)
2327
2335
2328 try:
2336 try:
2329 wlock = repo.wlock()
2337 wlock = repo.wlock()
2330 lock = repo.lock()
2338 lock = repo.lock()
2331 lastcommit = None
2339 lastcommit = None
2332 for p in patches:
2340 for p in patches:
2333 pf = os.path.join(d, p)
2341 pf = os.path.join(d, p)
2334
2342
2335 if pf == '-':
2343 if pf == '-':
2336 ui.status(_("applying patch from stdin\n"))
2344 ui.status(_("applying patch from stdin\n"))
2337 pf = sys.stdin
2345 pf = sys.stdin
2338 else:
2346 else:
2339 ui.status(_("applying %s\n") % p)
2347 ui.status(_("applying %s\n") % p)
2340 pf = url.open(ui, pf)
2348 pf = url.open(ui, pf)
2341
2349
2342 haspatch = False
2350 haspatch = False
2343 for hunk in patch.split(pf):
2351 for hunk in patch.split(pf):
2344 commitid = tryone(ui, hunk)
2352 commitid = tryone(ui, hunk)
2345 if commitid:
2353 if commitid:
2346 haspatch = True
2354 haspatch = True
2347 if lastcommit:
2355 if lastcommit:
2348 ui.status(_('applied %s\n') % lastcommit)
2356 ui.status(_('applied %s\n') % lastcommit)
2349 lastcommit = commitid
2357 lastcommit = commitid
2350
2358
2351 if not haspatch:
2359 if not haspatch:
2352 raise util.Abort(_('no diffs found'))
2360 raise util.Abort(_('no diffs found'))
2353
2361
2354 finally:
2362 finally:
2355 release(lock, wlock)
2363 release(lock, wlock)
2356
2364
2357 def incoming(ui, repo, source="default", **opts):
2365 def incoming(ui, repo, source="default", **opts):
2358 """show new changesets found in source
2366 """show new changesets found in source
2359
2367
2360 Show new changesets found in the specified path/URL or the default
2368 Show new changesets found in the specified path/URL or the default
2361 pull location. These are the changesets that would have been pulled
2369 pull location. These are the changesets that would have been pulled
2362 if a pull at the time you issued this command.
2370 if a pull at the time you issued this command.
2363
2371
2364 For remote repository, using --bundle avoids downloading the
2372 For remote repository, using --bundle avoids downloading the
2365 changesets twice if the incoming is followed by a pull.
2373 changesets twice if the incoming is followed by a pull.
2366
2374
2367 See pull for valid source format details.
2375 See pull for valid source format details.
2368
2376
2369 Returns 0 if there are incoming changes, 1 otherwise.
2377 Returns 0 if there are incoming changes, 1 otherwise.
2370 """
2378 """
2371 if opts.get('bundle') and opts.get('subrepos'):
2379 if opts.get('bundle') and opts.get('subrepos'):
2372 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2380 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2373
2381
2374 ret = hg.incoming(ui, repo, source, opts)
2382 ret = hg.incoming(ui, repo, source, opts)
2375 return ret
2383 return ret
2376
2384
2377 def init(ui, dest=".", **opts):
2385 def init(ui, dest=".", **opts):
2378 """create a new repository in the given directory
2386 """create a new repository in the given directory
2379
2387
2380 Initialize a new repository in the given directory. If the given
2388 Initialize a new repository in the given directory. If the given
2381 directory does not exist, it will be created.
2389 directory does not exist, it will be created.
2382
2390
2383 If no directory is given, the current directory is used.
2391 If no directory is given, the current directory is used.
2384
2392
2385 It is possible to specify an ``ssh://`` URL as the destination.
2393 It is possible to specify an ``ssh://`` URL as the destination.
2386 See :hg:`help urls` for more information.
2394 See :hg:`help urls` for more information.
2387
2395
2388 Returns 0 on success.
2396 Returns 0 on success.
2389 """
2397 """
2390 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2398 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2391
2399
2392 def locate(ui, repo, *pats, **opts):
2400 def locate(ui, repo, *pats, **opts):
2393 """locate files matching specific patterns
2401 """locate files matching specific patterns
2394
2402
2395 Print files under Mercurial control in the working directory whose
2403 Print files under Mercurial control in the working directory whose
2396 names match the given patterns.
2404 names match the given patterns.
2397
2405
2398 By default, this command searches all directories in the working
2406 By default, this command searches all directories in the working
2399 directory. To search just the current directory and its
2407 directory. To search just the current directory and its
2400 subdirectories, use "--include .".
2408 subdirectories, use "--include .".
2401
2409
2402 If no patterns are given to match, this command prints the names
2410 If no patterns are given to match, this command prints the names
2403 of all files under Mercurial control in the working directory.
2411 of all files under Mercurial control in the working directory.
2404
2412
2405 If you want to feed the output of this command into the "xargs"
2413 If you want to feed the output of this command into the "xargs"
2406 command, use the -0 option to both this command and "xargs". This
2414 command, use the -0 option to both this command and "xargs". This
2407 will avoid the problem of "xargs" treating single filenames that
2415 will avoid the problem of "xargs" treating single filenames that
2408 contain whitespace as multiple filenames.
2416 contain whitespace as multiple filenames.
2409
2417
2410 Returns 0 if a match is found, 1 otherwise.
2418 Returns 0 if a match is found, 1 otherwise.
2411 """
2419 """
2412 end = opts.get('print0') and '\0' or '\n'
2420 end = opts.get('print0') and '\0' or '\n'
2413 rev = opts.get('rev') or None
2421 rev = opts.get('rev') or None
2414
2422
2415 ret = 1
2423 ret = 1
2416 m = cmdutil.match(repo, pats, opts, default='relglob')
2424 m = cmdutil.match(repo, pats, opts, default='relglob')
2417 m.bad = lambda x, y: False
2425 m.bad = lambda x, y: False
2418 for abs in repo[rev].walk(m):
2426 for abs in repo[rev].walk(m):
2419 if not rev and abs not in repo.dirstate:
2427 if not rev and abs not in repo.dirstate:
2420 continue
2428 continue
2421 if opts.get('fullpath'):
2429 if opts.get('fullpath'):
2422 ui.write(repo.wjoin(abs), end)
2430 ui.write(repo.wjoin(abs), end)
2423 else:
2431 else:
2424 ui.write(((pats and m.rel(abs)) or abs), end)
2432 ui.write(((pats and m.rel(abs)) or abs), end)
2425 ret = 0
2433 ret = 0
2426
2434
2427 return ret
2435 return ret
2428
2436
2429 def log(ui, repo, *pats, **opts):
2437 def log(ui, repo, *pats, **opts):
2430 """show revision history of entire repository or files
2438 """show revision history of entire repository or files
2431
2439
2432 Print the revision history of the specified files or the entire
2440 Print the revision history of the specified files or the entire
2433 project.
2441 project.
2434
2442
2435 File history is shown without following rename or copy history of
2443 File history is shown without following rename or copy history of
2436 files. Use -f/--follow with a filename to follow history across
2444 files. Use -f/--follow with a filename to follow history across
2437 renames and copies. --follow without a filename will only show
2445 renames and copies. --follow without a filename will only show
2438 ancestors or descendants of the starting revision. --follow-first
2446 ancestors or descendants of the starting revision. --follow-first
2439 only follows the first parent of merge revisions.
2447 only follows the first parent of merge revisions.
2440
2448
2441 If no revision range is specified, the default is tip:0 unless
2449 If no revision range is specified, the default is ``tip:0`` unless
2442 --follow is set, in which case the working directory parent is
2450 --follow is set, in which case the working directory parent is
2443 used as the starting revision. You can specify a revision set for
2451 used as the starting revision. You can specify a revision set for
2444 log, see :hg:`help revsets` for more information.
2452 log, see :hg:`help revsets` for more information.
2445
2453
2446 See :hg:`help dates` for a list of formats valid for -d/--date.
2454 See :hg:`help dates` for a list of formats valid for -d/--date.
2447
2455
2448 By default this command prints revision number and changeset id,
2456 By default this command prints revision number and changeset id,
2449 tags, non-trivial parents, user, date and time, and a summary for
2457 tags, non-trivial parents, user, date and time, and a summary for
2450 each commit. When the -v/--verbose switch is used, the list of
2458 each commit. When the -v/--verbose switch is used, the list of
2451 changed files and full commit message are shown.
2459 changed files and full commit message are shown.
2452
2460
2453 .. note::
2461 .. note::
2454 log -p/--patch may generate unexpected diff output for merge
2462 log -p/--patch may generate unexpected diff output for merge
2455 changesets, as it will only compare the merge changeset against
2463 changesets, as it will only compare the merge changeset against
2456 its first parent. Also, only files different from BOTH parents
2464 its first parent. Also, only files different from BOTH parents
2457 will appear in files:.
2465 will appear in files:.
2458
2466
2459 Returns 0 on success.
2467 Returns 0 on success.
2460 """
2468 """
2461
2469
2462 matchfn = cmdutil.match(repo, pats, opts)
2470 matchfn = cmdutil.match(repo, pats, opts)
2463 limit = cmdutil.loglimit(opts)
2471 limit = cmdutil.loglimit(opts)
2464 count = 0
2472 count = 0
2465
2473
2466 endrev = None
2474 endrev = None
2467 if opts.get('copies') and opts.get('rev'):
2475 if opts.get('copies') and opts.get('rev'):
2468 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2476 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2469
2477
2470 df = False
2478 df = False
2471 if opts["date"]:
2479 if opts["date"]:
2472 df = util.matchdate(opts["date"])
2480 df = util.matchdate(opts["date"])
2473
2481
2474 branches = opts.get('branch', []) + opts.get('only_branch', [])
2482 branches = opts.get('branch', []) + opts.get('only_branch', [])
2475 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2483 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2476
2484
2477 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2485 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2478 def prep(ctx, fns):
2486 def prep(ctx, fns):
2479 rev = ctx.rev()
2487 rev = ctx.rev()
2480 parents = [p for p in repo.changelog.parentrevs(rev)
2488 parents = [p for p in repo.changelog.parentrevs(rev)
2481 if p != nullrev]
2489 if p != nullrev]
2482 if opts.get('no_merges') and len(parents) == 2:
2490 if opts.get('no_merges') and len(parents) == 2:
2483 return
2491 return
2484 if opts.get('only_merges') and len(parents) != 2:
2492 if opts.get('only_merges') and len(parents) != 2:
2485 return
2493 return
2486 if opts.get('branch') and ctx.branch() not in opts['branch']:
2494 if opts.get('branch') and ctx.branch() not in opts['branch']:
2487 return
2495 return
2488 if df and not df(ctx.date()[0]):
2496 if df and not df(ctx.date()[0]):
2489 return
2497 return
2490 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2498 if opts['user'] and not [k for k in opts['user'] if k in ctx.user()]:
2491 return
2499 return
2492 if opts.get('keyword'):
2500 if opts.get('keyword'):
2493 for k in [kw.lower() for kw in opts['keyword']]:
2501 for k in [kw.lower() for kw in opts['keyword']]:
2494 if (k in ctx.user().lower() or
2502 if (k in ctx.user().lower() or
2495 k in ctx.description().lower() or
2503 k in ctx.description().lower() or
2496 k in " ".join(ctx.files()).lower()):
2504 k in " ".join(ctx.files()).lower()):
2497 break
2505 break
2498 else:
2506 else:
2499 return
2507 return
2500
2508
2501 copies = None
2509 copies = None
2502 if opts.get('copies') and rev:
2510 if opts.get('copies') and rev:
2503 copies = []
2511 copies = []
2504 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2512 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2505 for fn in ctx.files():
2513 for fn in ctx.files():
2506 rename = getrenamed(fn, rev)
2514 rename = getrenamed(fn, rev)
2507 if rename:
2515 if rename:
2508 copies.append((fn, rename[0]))
2516 copies.append((fn, rename[0]))
2509
2517
2510 revmatchfn = None
2518 revmatchfn = None
2511 if opts.get('patch') or opts.get('stat'):
2519 if opts.get('patch') or opts.get('stat'):
2512 if opts.get('follow') or opts.get('follow_first'):
2520 if opts.get('follow') or opts.get('follow_first'):
2513 # note: this might be wrong when following through merges
2521 # note: this might be wrong when following through merges
2514 revmatchfn = cmdutil.match(repo, fns, default='path')
2522 revmatchfn = cmdutil.match(repo, fns, default='path')
2515 else:
2523 else:
2516 revmatchfn = matchfn
2524 revmatchfn = matchfn
2517
2525
2518 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2526 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2519
2527
2520 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2528 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2521 if count == limit:
2529 if count == limit:
2522 break
2530 break
2523 if displayer.flush(ctx.rev()):
2531 if displayer.flush(ctx.rev()):
2524 count += 1
2532 count += 1
2525 displayer.close()
2533 displayer.close()
2526
2534
2527 def manifest(ui, repo, node=None, rev=None):
2535 def manifest(ui, repo, node=None, rev=None):
2528 """output the current or given revision of the project manifest
2536 """output the current or given revision of the project manifest
2529
2537
2530 Print a list of version controlled files for the given revision.
2538 Print a list of version controlled files for the given revision.
2531 If no revision is given, the first parent of the working directory
2539 If no revision is given, the first parent of the working directory
2532 is used, or the null revision if no revision is checked out.
2540 is used, or the null revision if no revision is checked out.
2533
2541
2534 With -v, print file permissions, symlink and executable bits.
2542 With -v, print file permissions, symlink and executable bits.
2535 With --debug, print file revision hashes.
2543 With --debug, print file revision hashes.
2536
2544
2537 Returns 0 on success.
2545 Returns 0 on success.
2538 """
2546 """
2539
2547
2540 if rev and node:
2548 if rev and node:
2541 raise util.Abort(_("please specify just one revision"))
2549 raise util.Abort(_("please specify just one revision"))
2542
2550
2543 if not node:
2551 if not node:
2544 node = rev
2552 node = rev
2545
2553
2546 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2554 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2547 ctx = repo[node]
2555 ctx = repo[node]
2548 for f in ctx:
2556 for f in ctx:
2549 if ui.debugflag:
2557 if ui.debugflag:
2550 ui.write("%40s " % hex(ctx.manifest()[f]))
2558 ui.write("%40s " % hex(ctx.manifest()[f]))
2551 if ui.verbose:
2559 if ui.verbose:
2552 ui.write(decor[ctx.flags(f)])
2560 ui.write(decor[ctx.flags(f)])
2553 ui.write("%s\n" % f)
2561 ui.write("%s\n" % f)
2554
2562
2555 def merge(ui, repo, node=None, **opts):
2563 def merge(ui, repo, node=None, **opts):
2556 """merge working directory with another revision
2564 """merge working directory with another revision
2557
2565
2558 The current working directory is updated with all changes made in
2566 The current working directory is updated with all changes made in
2559 the requested revision since the last common predecessor revision.
2567 the requested revision since the last common predecessor revision.
2560
2568
2561 Files that changed between either parent are marked as changed for
2569 Files that changed between either parent are marked as changed for
2562 the next commit and a commit must be performed before any further
2570 the next commit and a commit must be performed before any further
2563 updates to the repository are allowed. The next commit will have
2571 updates to the repository are allowed. The next commit will have
2564 two parents.
2572 two parents.
2565
2573
2566 ``--tool`` can be used to specify the merge tool used for file
2574 ``--tool`` can be used to specify the merge tool used for file
2567 merges. It overrides the HGMERGE environment variable and your
2575 merges. It overrides the HGMERGE environment variable and your
2568 configuration files.
2576 configuration files.
2569
2577
2570 If no revision is specified, the working directory's parent is a
2578 If no revision is specified, the working directory's parent is a
2571 head revision, and the current branch contains exactly one other
2579 head revision, and the current branch contains exactly one other
2572 head, the other head is merged with by default. Otherwise, an
2580 head, the other head is merged with by default. Otherwise, an
2573 explicit revision with which to merge with must be provided.
2581 explicit revision with which to merge with must be provided.
2574
2582
2575 :hg:`resolve` must be used to resolve unresolved files.
2583 :hg:`resolve` must be used to resolve unresolved files.
2576
2584
2577 To undo an uncommitted merge, use :hg:`update --clean .` which
2585 To undo an uncommitted merge, use :hg:`update --clean .` which
2578 will check out a clean copy of the original merge parent, losing
2586 will check out a clean copy of the original merge parent, losing
2579 all changes.
2587 all changes.
2580
2588
2581 Returns 0 on success, 1 if there are unresolved files.
2589 Returns 0 on success, 1 if there are unresolved files.
2582 """
2590 """
2583
2591
2584 if opts.get('rev') and node:
2592 if opts.get('rev') and node:
2585 raise util.Abort(_("please specify just one revision"))
2593 raise util.Abort(_("please specify just one revision"))
2586 if not node:
2594 if not node:
2587 node = opts.get('rev')
2595 node = opts.get('rev')
2588
2596
2589 if not node:
2597 if not node:
2590 branch = repo.changectx(None).branch()
2598 branch = repo.changectx(None).branch()
2591 bheads = repo.branchheads(branch)
2599 bheads = repo.branchheads(branch)
2592 if len(bheads) > 2:
2600 if len(bheads) > 2:
2593 raise util.Abort(_(
2601 raise util.Abort(_(
2594 'branch \'%s\' has %d heads - '
2602 'branch \'%s\' has %d heads - '
2595 'please merge with an explicit rev\n'
2603 'please merge with an explicit rev\n'
2596 '(run \'hg heads .\' to see heads)')
2604 '(run \'hg heads .\' to see heads)')
2597 % (branch, len(bheads)))
2605 % (branch, len(bheads)))
2598
2606
2599 parent = repo.dirstate.parents()[0]
2607 parent = repo.dirstate.parents()[0]
2600 if len(bheads) == 1:
2608 if len(bheads) == 1:
2601 if len(repo.heads()) > 1:
2609 if len(repo.heads()) > 1:
2602 raise util.Abort(_(
2610 raise util.Abort(_(
2603 'branch \'%s\' has one head - '
2611 'branch \'%s\' has one head - '
2604 'please merge with an explicit rev\n'
2612 'please merge with an explicit rev\n'
2605 '(run \'hg heads\' to see all heads)')
2613 '(run \'hg heads\' to see all heads)')
2606 % branch)
2614 % branch)
2607 msg = _('there is nothing to merge')
2615 msg = _('there is nothing to merge')
2608 if parent != repo.lookup(repo[None].branch()):
2616 if parent != repo.lookup(repo[None].branch()):
2609 msg = _('%s - use "hg update" instead') % msg
2617 msg = _('%s - use "hg update" instead') % msg
2610 raise util.Abort(msg)
2618 raise util.Abort(msg)
2611
2619
2612 if parent not in bheads:
2620 if parent not in bheads:
2613 raise util.Abort(_('working dir not at a head rev - '
2621 raise util.Abort(_('working dir not at a head rev - '
2614 'use "hg update" or merge with an explicit rev'))
2622 'use "hg update" or merge with an explicit rev'))
2615 node = parent == bheads[0] and bheads[-1] or bheads[0]
2623 node = parent == bheads[0] and bheads[-1] or bheads[0]
2616
2624
2617 if opts.get('preview'):
2625 if opts.get('preview'):
2618 # find nodes that are ancestors of p2 but not of p1
2626 # find nodes that are ancestors of p2 but not of p1
2619 p1 = repo.lookup('.')
2627 p1 = repo.lookup('.')
2620 p2 = repo.lookup(node)
2628 p2 = repo.lookup(node)
2621 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2629 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2622
2630
2623 displayer = cmdutil.show_changeset(ui, repo, opts)
2631 displayer = cmdutil.show_changeset(ui, repo, opts)
2624 for node in nodes:
2632 for node in nodes:
2625 displayer.show(repo[node])
2633 displayer.show(repo[node])
2626 displayer.close()
2634 displayer.close()
2627 return 0
2635 return 0
2628
2636
2629 try:
2637 try:
2630 # ui.forcemerge is an internal variable, do not document
2638 # ui.forcemerge is an internal variable, do not document
2631 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2639 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2632 return hg.merge(repo, node, force=opts.get('force'))
2640 return hg.merge(repo, node, force=opts.get('force'))
2633 finally:
2641 finally:
2634 ui.setconfig('ui', 'forcemerge', '')
2642 ui.setconfig('ui', 'forcemerge', '')
2635
2643
2636 def outgoing(ui, repo, dest=None, **opts):
2644 def outgoing(ui, repo, dest=None, **opts):
2637 """show changesets not found in the destination
2645 """show changesets not found in the destination
2638
2646
2639 Show changesets not found in the specified destination repository
2647 Show changesets not found in the specified destination repository
2640 or the default push location. These are the changesets that would
2648 or the default push location. These are the changesets that would
2641 be pushed if a push was requested.
2649 be pushed if a push was requested.
2642
2650
2643 See pull for details of valid destination formats.
2651 See pull for details of valid destination formats.
2644
2652
2645 Returns 0 if there are outgoing changes, 1 otherwise.
2653 Returns 0 if there are outgoing changes, 1 otherwise.
2646 """
2654 """
2647 ret = hg.outgoing(ui, repo, dest, opts)
2655 ret = hg.outgoing(ui, repo, dest, opts)
2648 return ret
2656 return ret
2649
2657
2650 def parents(ui, repo, file_=None, **opts):
2658 def parents(ui, repo, file_=None, **opts):
2651 """show the parents of the working directory or revision
2659 """show the parents of the working directory or revision
2652
2660
2653 Print the working directory's parent revisions. If a revision is
2661 Print the working directory's parent revisions. If a revision is
2654 given via -r/--rev, the parent of that revision will be printed.
2662 given via -r/--rev, the parent of that revision will be printed.
2655 If a file argument is given, the revision in which the file was
2663 If a file argument is given, the revision in which the file was
2656 last changed (before the working directory revision or the
2664 last changed (before the working directory revision or the
2657 argument to --rev if given) is printed.
2665 argument to --rev if given) is printed.
2658
2666
2659 Returns 0 on success.
2667 Returns 0 on success.
2660 """
2668 """
2661 rev = opts.get('rev')
2669 rev = opts.get('rev')
2662 if rev:
2670 if rev:
2663 ctx = repo[rev]
2671 ctx = repo[rev]
2664 else:
2672 else:
2665 ctx = repo[None]
2673 ctx = repo[None]
2666
2674
2667 if file_:
2675 if file_:
2668 m = cmdutil.match(repo, (file_,), opts)
2676 m = cmdutil.match(repo, (file_,), opts)
2669 if m.anypats() or len(m.files()) != 1:
2677 if m.anypats() or len(m.files()) != 1:
2670 raise util.Abort(_('can only specify an explicit filename'))
2678 raise util.Abort(_('can only specify an explicit filename'))
2671 file_ = m.files()[0]
2679 file_ = m.files()[0]
2672 filenodes = []
2680 filenodes = []
2673 for cp in ctx.parents():
2681 for cp in ctx.parents():
2674 if not cp:
2682 if not cp:
2675 continue
2683 continue
2676 try:
2684 try:
2677 filenodes.append(cp.filenode(file_))
2685 filenodes.append(cp.filenode(file_))
2678 except error.LookupError:
2686 except error.LookupError:
2679 pass
2687 pass
2680 if not filenodes:
2688 if not filenodes:
2681 raise util.Abort(_("'%s' not found in manifest!") % file_)
2689 raise util.Abort(_("'%s' not found in manifest!") % file_)
2682 fl = repo.file(file_)
2690 fl = repo.file(file_)
2683 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2691 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2684 else:
2692 else:
2685 p = [cp.node() for cp in ctx.parents()]
2693 p = [cp.node() for cp in ctx.parents()]
2686
2694
2687 displayer = cmdutil.show_changeset(ui, repo, opts)
2695 displayer = cmdutil.show_changeset(ui, repo, opts)
2688 for n in p:
2696 for n in p:
2689 if n != nullid:
2697 if n != nullid:
2690 displayer.show(repo[n])
2698 displayer.show(repo[n])
2691 displayer.close()
2699 displayer.close()
2692
2700
2693 def paths(ui, repo, search=None):
2701 def paths(ui, repo, search=None):
2694 """show aliases for remote repositories
2702 """show aliases for remote repositories
2695
2703
2696 Show definition of symbolic path name NAME. If no name is given,
2704 Show definition of symbolic path name NAME. If no name is given,
2697 show definition of all available names.
2705 show definition of all available names.
2698
2706
2699 Path names are defined in the [paths] section of your
2707 Path names are defined in the [paths] section of your
2700 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2708 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2701 repository, ``.hg/hgrc`` is used, too.
2709 repository, ``.hg/hgrc`` is used, too.
2702
2710
2703 The path names ``default`` and ``default-push`` have a special
2711 The path names ``default`` and ``default-push`` have a special
2704 meaning. When performing a push or pull operation, they are used
2712 meaning. When performing a push or pull operation, they are used
2705 as fallbacks if no location is specified on the command-line.
2713 as fallbacks if no location is specified on the command-line.
2706 When ``default-push`` is set, it will be used for push and
2714 When ``default-push`` is set, it will be used for push and
2707 ``default`` will be used for pull; otherwise ``default`` is used
2715 ``default`` will be used for pull; otherwise ``default`` is used
2708 as the fallback for both. When cloning a repository, the clone
2716 as the fallback for both. When cloning a repository, the clone
2709 source is written as ``default`` in ``.hg/hgrc``. Note that
2717 source is written as ``default`` in ``.hg/hgrc``. Note that
2710 ``default`` and ``default-push`` apply to all inbound (e.g.
2718 ``default`` and ``default-push`` apply to all inbound (e.g.
2711 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2719 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2712 :hg:`bundle`) operations.
2720 :hg:`bundle`) operations.
2713
2721
2714 See :hg:`help urls` for more information.
2722 See :hg:`help urls` for more information.
2715
2723
2716 Returns 0 on success.
2724 Returns 0 on success.
2717 """
2725 """
2718 if search:
2726 if search:
2719 for name, path in ui.configitems("paths"):
2727 for name, path in ui.configitems("paths"):
2720 if name == search:
2728 if name == search:
2721 ui.write("%s\n" % url.hidepassword(path))
2729 ui.write("%s\n" % url.hidepassword(path))
2722 return
2730 return
2723 ui.warn(_("not found!\n"))
2731 ui.warn(_("not found!\n"))
2724 return 1
2732 return 1
2725 else:
2733 else:
2726 for name, path in ui.configitems("paths"):
2734 for name, path in ui.configitems("paths"):
2727 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2735 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2728
2736
2729 def postincoming(ui, repo, modheads, optupdate, checkout):
2737 def postincoming(ui, repo, modheads, optupdate, checkout):
2730 if modheads == 0:
2738 if modheads == 0:
2731 return
2739 return
2732 if optupdate:
2740 if optupdate:
2733 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2741 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2734 return hg.update(repo, checkout)
2742 return hg.update(repo, checkout)
2735 else:
2743 else:
2736 ui.status(_("not updating, since new heads added\n"))
2744 ui.status(_("not updating, since new heads added\n"))
2737 if modheads > 1:
2745 if modheads > 1:
2738 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2746 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2739 else:
2747 else:
2740 ui.status(_("(run 'hg update' to get a working copy)\n"))
2748 ui.status(_("(run 'hg update' to get a working copy)\n"))
2741
2749
2742 def pull(ui, repo, source="default", **opts):
2750 def pull(ui, repo, source="default", **opts):
2743 """pull changes from the specified source
2751 """pull changes from the specified source
2744
2752
2745 Pull changes from a remote repository to a local one.
2753 Pull changes from a remote repository to a local one.
2746
2754
2747 This finds all changes from the repository at the specified path
2755 This finds all changes from the repository at the specified path
2748 or URL and adds them to a local repository (the current one unless
2756 or URL and adds them to a local repository (the current one unless
2749 -R is specified). By default, this does not update the copy of the
2757 -R is specified). By default, this does not update the copy of the
2750 project in the working directory.
2758 project in the working directory.
2751
2759
2752 Use :hg:`incoming` if you want to see what would have been added
2760 Use :hg:`incoming` if you want to see what would have been added
2753 by a pull at the time you issued this command. If you then decide
2761 by a pull at the time you issued this command. If you then decide
2754 to add those changes to the repository, you should use :hg:`pull
2762 to add those changes to the repository, you should use :hg:`pull
2755 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2763 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
2756
2764
2757 If SOURCE is omitted, the 'default' path will be used.
2765 If SOURCE is omitted, the 'default' path will be used.
2758 See :hg:`help urls` for more information.
2766 See :hg:`help urls` for more information.
2759
2767
2760 Returns 0 on success, 1 if an update had unresolved files.
2768 Returns 0 on success, 1 if an update had unresolved files.
2761 """
2769 """
2762 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2770 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
2763 other = hg.repository(hg.remoteui(repo, opts), source)
2771 other = hg.repository(hg.remoteui(repo, opts), source)
2764 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2772 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2765 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2773 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
2766 if revs:
2774 if revs:
2767 try:
2775 try:
2768 revs = [other.lookup(rev) for rev in revs]
2776 revs = [other.lookup(rev) for rev in revs]
2769 except error.CapabilityError:
2777 except error.CapabilityError:
2770 err = _("other repository doesn't support revision lookup, "
2778 err = _("other repository doesn't support revision lookup, "
2771 "so a rev cannot be specified.")
2779 "so a rev cannot be specified.")
2772 raise util.Abort(err)
2780 raise util.Abort(err)
2773
2781
2774 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2782 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2775 if checkout:
2783 if checkout:
2776 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2784 checkout = str(repo.changelog.rev(other.lookup(checkout)))
2777 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2785 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2778
2786
2779 def push(ui, repo, dest=None, **opts):
2787 def push(ui, repo, dest=None, **opts):
2780 """push changes to the specified destination
2788 """push changes to the specified destination
2781
2789
2782 Push changesets from the local repository to the specified
2790 Push changesets from the local repository to the specified
2783 destination.
2791 destination.
2784
2792
2785 This operation is symmetrical to pull: it is identical to a pull
2793 This operation is symmetrical to pull: it is identical to a pull
2786 in the destination repository from the current one.
2794 in the destination repository from the current one.
2787
2795
2788 By default, push will not allow creation of new heads at the
2796 By default, push will not allow creation of new heads at the
2789 destination, since multiple heads would make it unclear which head
2797 destination, since multiple heads would make it unclear which head
2790 to use. In this situation, it is recommended to pull and merge
2798 to use. In this situation, it is recommended to pull and merge
2791 before pushing.
2799 before pushing.
2792
2800
2793 Use --new-branch if you want to allow push to create a new named
2801 Use --new-branch if you want to allow push to create a new named
2794 branch that is not present at the destination. This allows you to
2802 branch that is not present at the destination. This allows you to
2795 only create a new branch without forcing other changes.
2803 only create a new branch without forcing other changes.
2796
2804
2797 Use -f/--force to override the default behavior and push all
2805 Use -f/--force to override the default behavior and push all
2798 changesets on all branches.
2806 changesets on all branches.
2799
2807
2800 If -r/--rev is used, the specified revision and all its ancestors
2808 If -r/--rev is used, the specified revision and all its ancestors
2801 will be pushed to the remote repository.
2809 will be pushed to the remote repository.
2802
2810
2803 Please see :hg:`help urls` for important details about ``ssh://``
2811 Please see :hg:`help urls` for important details about ``ssh://``
2804 URLs. If DESTINATION is omitted, a default path will be used.
2812 URLs. If DESTINATION is omitted, a default path will be used.
2805
2813
2806 Returns 0 if push was successful, 1 if nothing to push.
2814 Returns 0 if push was successful, 1 if nothing to push.
2807 """
2815 """
2808 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2816 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2809 dest, branches = hg.parseurl(dest, opts.get('branch'))
2817 dest, branches = hg.parseurl(dest, opts.get('branch'))
2810 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2818 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
2811 other = hg.repository(hg.remoteui(repo, opts), dest)
2819 other = hg.repository(hg.remoteui(repo, opts), dest)
2812 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2820 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2813 if revs:
2821 if revs:
2814 revs = [repo.lookup(rev) for rev in revs]
2822 revs = [repo.lookup(rev) for rev in revs]
2815
2823
2816 # push subrepos depth-first for coherent ordering
2824 # push subrepos depth-first for coherent ordering
2817 c = repo['']
2825 c = repo['']
2818 subs = c.substate # only repos that are committed
2826 subs = c.substate # only repos that are committed
2819 for s in sorted(subs):
2827 for s in sorted(subs):
2820 if not c.sub(s).push(opts.get('force')):
2828 if not c.sub(s).push(opts.get('force')):
2821 return False
2829 return False
2822
2830
2823 r = repo.push(other, opts.get('force'), revs=revs,
2831 r = repo.push(other, opts.get('force'), revs=revs,
2824 newbranch=opts.get('new_branch'))
2832 newbranch=opts.get('new_branch'))
2825 return r == 0
2833 return r == 0
2826
2834
2827 def recover(ui, repo):
2835 def recover(ui, repo):
2828 """roll back an interrupted transaction
2836 """roll back an interrupted transaction
2829
2837
2830 Recover from an interrupted commit or pull.
2838 Recover from an interrupted commit or pull.
2831
2839
2832 This command tries to fix the repository status after an
2840 This command tries to fix the repository status after an
2833 interrupted operation. It should only be necessary when Mercurial
2841 interrupted operation. It should only be necessary when Mercurial
2834 suggests it.
2842 suggests it.
2835
2843
2836 Returns 0 if successful, 1 if nothing to recover or verify fails.
2844 Returns 0 if successful, 1 if nothing to recover or verify fails.
2837 """
2845 """
2838 if repo.recover():
2846 if repo.recover():
2839 return hg.verify(repo)
2847 return hg.verify(repo)
2840 return 1
2848 return 1
2841
2849
2842 def remove(ui, repo, *pats, **opts):
2850 def remove(ui, repo, *pats, **opts):
2843 """remove the specified files on the next commit
2851 """remove the specified files on the next commit
2844
2852
2845 Schedule the indicated files for removal from the repository.
2853 Schedule the indicated files for removal from the repository.
2846
2854
2847 This only removes files from the current branch, not from the
2855 This only removes files from the current branch, not from the
2848 entire project history. -A/--after can be used to remove only
2856 entire project history. -A/--after can be used to remove only
2849 files that have already been deleted, -f/--force can be used to
2857 files that have already been deleted, -f/--force can be used to
2850 force deletion, and -Af can be used to remove files from the next
2858 force deletion, and -Af can be used to remove files from the next
2851 revision without deleting them from the working directory.
2859 revision without deleting them from the working directory.
2852
2860
2853 The following table details the behavior of remove for different
2861 The following table details the behavior of remove for different
2854 file states (columns) and option combinations (rows). The file
2862 file states (columns) and option combinations (rows). The file
2855 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2863 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
2856 reported by :hg:`status`). The actions are Warn, Remove (from
2864 reported by :hg:`status`). The actions are Warn, Remove (from
2857 branch) and Delete (from disk)::
2865 branch) and Delete (from disk)::
2858
2866
2859 A C M !
2867 A C M !
2860 none W RD W R
2868 none W RD W R
2861 -f R RD RD R
2869 -f R RD RD R
2862 -A W W W R
2870 -A W W W R
2863 -Af R R R R
2871 -Af R R R R
2864
2872
2865 This command schedules the files to be removed at the next commit.
2873 This command schedules the files to be removed at the next commit.
2866 To undo a remove before that, see :hg:`revert`.
2874 To undo a remove before that, see :hg:`revert`.
2867
2875
2868 Returns 0 on success, 1 if any warnings encountered.
2876 Returns 0 on success, 1 if any warnings encountered.
2869 """
2877 """
2870
2878
2871 ret = 0
2879 ret = 0
2872 after, force = opts.get('after'), opts.get('force')
2880 after, force = opts.get('after'), opts.get('force')
2873 if not pats and not after:
2881 if not pats and not after:
2874 raise util.Abort(_('no files specified'))
2882 raise util.Abort(_('no files specified'))
2875
2883
2876 m = cmdutil.match(repo, pats, opts)
2884 m = cmdutil.match(repo, pats, opts)
2877 s = repo.status(match=m, clean=True)
2885 s = repo.status(match=m, clean=True)
2878 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2886 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2879
2887
2880 for f in m.files():
2888 for f in m.files():
2881 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2889 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2882 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2890 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
2883 ret = 1
2891 ret = 1
2884
2892
2885 if force:
2893 if force:
2886 remove, forget = modified + deleted + clean, added
2894 remove, forget = modified + deleted + clean, added
2887 elif after:
2895 elif after:
2888 remove, forget = deleted, []
2896 remove, forget = deleted, []
2889 for f in modified + added + clean:
2897 for f in modified + added + clean:
2890 ui.warn(_('not removing %s: file still exists (use -f'
2898 ui.warn(_('not removing %s: file still exists (use -f'
2891 ' to force removal)\n') % m.rel(f))
2899 ' to force removal)\n') % m.rel(f))
2892 ret = 1
2900 ret = 1
2893 else:
2901 else:
2894 remove, forget = deleted + clean, []
2902 remove, forget = deleted + clean, []
2895 for f in modified:
2903 for f in modified:
2896 ui.warn(_('not removing %s: file is modified (use -f'
2904 ui.warn(_('not removing %s: file is modified (use -f'
2897 ' to force removal)\n') % m.rel(f))
2905 ' to force removal)\n') % m.rel(f))
2898 ret = 1
2906 ret = 1
2899 for f in added:
2907 for f in added:
2900 ui.warn(_('not removing %s: file has been marked for add (use -f'
2908 ui.warn(_('not removing %s: file has been marked for add (use -f'
2901 ' to force removal)\n') % m.rel(f))
2909 ' to force removal)\n') % m.rel(f))
2902 ret = 1
2910 ret = 1
2903
2911
2904 for f in sorted(remove + forget):
2912 for f in sorted(remove + forget):
2905 if ui.verbose or not m.exact(f):
2913 if ui.verbose or not m.exact(f):
2906 ui.status(_('removing %s\n') % m.rel(f))
2914 ui.status(_('removing %s\n') % m.rel(f))
2907
2915
2908 repo[None].forget(forget)
2916 repo[None].forget(forget)
2909 repo[None].remove(remove, unlink=not after)
2917 repo[None].remove(remove, unlink=not after)
2910 return ret
2918 return ret
2911
2919
2912 def rename(ui, repo, *pats, **opts):
2920 def rename(ui, repo, *pats, **opts):
2913 """rename files; equivalent of copy + remove
2921 """rename files; equivalent of copy + remove
2914
2922
2915 Mark dest as copies of sources; mark sources for deletion. If dest
2923 Mark dest as copies of sources; mark sources for deletion. If dest
2916 is a directory, copies are put in that directory. If dest is a
2924 is a directory, copies are put in that directory. If dest is a
2917 file, there can only be one source.
2925 file, there can only be one source.
2918
2926
2919 By default, this command copies the contents of files as they
2927 By default, this command copies the contents of files as they
2920 exist in the working directory. If invoked with -A/--after, the
2928 exist in the working directory. If invoked with -A/--after, the
2921 operation is recorded, but no copying is performed.
2929 operation is recorded, but no copying is performed.
2922
2930
2923 This command takes effect at the next commit. To undo a rename
2931 This command takes effect at the next commit. To undo a rename
2924 before that, see :hg:`revert`.
2932 before that, see :hg:`revert`.
2925
2933
2926 Returns 0 on success, 1 if errors are encountered.
2934 Returns 0 on success, 1 if errors are encountered.
2927 """
2935 """
2928 wlock = repo.wlock(False)
2936 wlock = repo.wlock(False)
2929 try:
2937 try:
2930 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2938 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2931 finally:
2939 finally:
2932 wlock.release()
2940 wlock.release()
2933
2941
2934 def resolve(ui, repo, *pats, **opts):
2942 def resolve(ui, repo, *pats, **opts):
2935 """redo merges or set/view the merge status of files
2943 """redo merges or set/view the merge status of files
2936
2944
2937 Merges with unresolved conflicts are often the result of
2945 Merges with unresolved conflicts are often the result of
2938 non-interactive merging using the ``internal:merge`` configuration
2946 non-interactive merging using the ``internal:merge`` configuration
2939 setting, or a command-line merge tool like ``diff3``. The resolve
2947 setting, or a command-line merge tool like ``diff3``. The resolve
2940 command is used to manage the files involved in a merge, after
2948 command is used to manage the files involved in a merge, after
2941 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2949 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
2942 working directory must have two parents).
2950 working directory must have two parents).
2943
2951
2944 The resolve command can be used in the following ways:
2952 The resolve command can be used in the following ways:
2945
2953
2946 - :hg:`resolve [--tool] FILE...`: attempt to re-merge the specified
2954 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
2947 files, discarding any previous merge attempts. Re-merging is not
2955 files, discarding any previous merge attempts. Re-merging is not
2948 performed for files already marked as resolved. Use ``--all/-a``
2956 performed for files already marked as resolved. Use ``--all/-a``
2949 to selects all unresolved files. ``--tool`` can be used to specify
2957 to selects all unresolved files. ``--tool`` can be used to specify
2950 the merge tool used for the given files. It overrides the HGMERGE
2958 the merge tool used for the given files. It overrides the HGMERGE
2951 environment variable and your configuration files.
2959 environment variable and your configuration files.
2952
2960
2953 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2961 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
2954 (e.g. after having manually fixed-up the files). The default is
2962 (e.g. after having manually fixed-up the files). The default is
2955 to mark all unresolved files.
2963 to mark all unresolved files.
2956
2964
2957 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2965 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
2958 default is to mark all resolved files.
2966 default is to mark all resolved files.
2959
2967
2960 - :hg:`resolve -l`: list files which had or still have conflicts.
2968 - :hg:`resolve -l`: list files which had or still have conflicts.
2961 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2969 In the printed list, ``U`` = unresolved and ``R`` = resolved.
2962
2970
2963 Note that Mercurial will not let you commit files with unresolved
2971 Note that Mercurial will not let you commit files with unresolved
2964 merge conflicts. You must use :hg:`resolve -m ...` before you can
2972 merge conflicts. You must use :hg:`resolve -m ...` before you can
2965 commit after a conflicting merge.
2973 commit after a conflicting merge.
2966
2974
2967 Returns 0 on success, 1 if any files fail a resolve attempt.
2975 Returns 0 on success, 1 if any files fail a resolve attempt.
2968 """
2976 """
2969
2977
2970 all, mark, unmark, show, nostatus = \
2978 all, mark, unmark, show, nostatus = \
2971 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2979 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
2972
2980
2973 if (show and (mark or unmark)) or (mark and unmark):
2981 if (show and (mark or unmark)) or (mark and unmark):
2974 raise util.Abort(_("too many options specified"))
2982 raise util.Abort(_("too many options specified"))
2975 if pats and all:
2983 if pats and all:
2976 raise util.Abort(_("can't specify --all and patterns"))
2984 raise util.Abort(_("can't specify --all and patterns"))
2977 if not (all or pats or show or mark or unmark):
2985 if not (all or pats or show or mark or unmark):
2978 raise util.Abort(_('no files or directories specified; '
2986 raise util.Abort(_('no files or directories specified; '
2979 'use --all to remerge all files'))
2987 'use --all to remerge all files'))
2980
2988
2981 ms = mergemod.mergestate(repo)
2989 ms = mergemod.mergestate(repo)
2982 m = cmdutil.match(repo, pats, opts)
2990 m = cmdutil.match(repo, pats, opts)
2983 ret = 0
2991 ret = 0
2984
2992
2985 for f in ms:
2993 for f in ms:
2986 if m(f):
2994 if m(f):
2987 if show:
2995 if show:
2988 if nostatus:
2996 if nostatus:
2989 ui.write("%s\n" % f)
2997 ui.write("%s\n" % f)
2990 else:
2998 else:
2991 ui.write("%s %s\n" % (ms[f].upper(), f),
2999 ui.write("%s %s\n" % (ms[f].upper(), f),
2992 label='resolve.' +
3000 label='resolve.' +
2993 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3001 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
2994 elif mark:
3002 elif mark:
2995 ms.mark(f, "r")
3003 ms.mark(f, "r")
2996 elif unmark:
3004 elif unmark:
2997 ms.mark(f, "u")
3005 ms.mark(f, "u")
2998 else:
3006 else:
2999 wctx = repo[None]
3007 wctx = repo[None]
3000 mctx = wctx.parents()[-1]
3008 mctx = wctx.parents()[-1]
3001
3009
3002 # backup pre-resolve (merge uses .orig for its own purposes)
3010 # backup pre-resolve (merge uses .orig for its own purposes)
3003 a = repo.wjoin(f)
3011 a = repo.wjoin(f)
3004 util.copyfile(a, a + ".resolve")
3012 util.copyfile(a, a + ".resolve")
3005
3013
3006 try:
3014 try:
3007 # resolve file
3015 # resolve file
3008 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3016 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3009 if ms.resolve(f, wctx, mctx):
3017 if ms.resolve(f, wctx, mctx):
3010 ret = 1
3018 ret = 1
3011 finally:
3019 finally:
3012 ui.setconfig('ui', 'forcemerge', '')
3020 ui.setconfig('ui', 'forcemerge', '')
3013
3021
3014 # replace filemerge's .orig file with our resolve file
3022 # replace filemerge's .orig file with our resolve file
3015 util.rename(a + ".resolve", a + ".orig")
3023 util.rename(a + ".resolve", a + ".orig")
3016
3024
3017 ms.commit()
3025 ms.commit()
3018 return ret
3026 return ret
3019
3027
3020 def revert(ui, repo, *pats, **opts):
3028 def revert(ui, repo, *pats, **opts):
3021 """restore individual files or directories to an earlier state
3029 """restore individual files or directories to an earlier state
3022
3030
3023 .. note::
3031 .. note::
3024 This command is most likely not what you are looking for.
3032 This command is most likely not what you are looking for.
3025 Revert will partially overwrite content in the working
3033 Revert will partially overwrite content in the working
3026 directory without changing the working directory parents. Use
3034 directory without changing the working directory parents. Use
3027 :hg:`update -r rev` to check out earlier revisions, or
3035 :hg:`update -r rev` to check out earlier revisions, or
3028 :hg:`update --clean .` to undo a merge which has added another
3036 :hg:`update --clean .` to undo a merge which has added another
3029 parent.
3037 parent.
3030
3038
3031 With no revision specified, revert the named files or directories
3039 With no revision specified, revert the named files or directories
3032 to the contents they had in the parent of the working directory.
3040 to the contents they had in the parent of the working directory.
3033 This restores the contents of the affected files to an unmodified
3041 This restores the contents of the affected files to an unmodified
3034 state and unschedules adds, removes, copies, and renames. If the
3042 state and unschedules adds, removes, copies, and renames. If the
3035 working directory has two parents, you must explicitly specify a
3043 working directory has two parents, you must explicitly specify a
3036 revision.
3044 revision.
3037
3045
3038 Using the -r/--rev option, revert the given files or directories
3046 Using the -r/--rev option, revert the given files or directories
3039 to their contents as of a specific revision. This can be helpful
3047 to their contents as of a specific revision. This can be helpful
3040 to "roll back" some or all of an earlier change. See :hg:`help
3048 to "roll back" some or all of an earlier change. See :hg:`help
3041 dates` for a list of formats valid for -d/--date.
3049 dates` for a list of formats valid for -d/--date.
3042
3050
3043 Revert modifies the working directory. It does not commit any
3051 Revert modifies the working directory. It does not commit any
3044 changes, or change the parent of the working directory. If you
3052 changes, or change the parent of the working directory. If you
3045 revert to a revision other than the parent of the working
3053 revert to a revision other than the parent of the working
3046 directory, the reverted files will thus appear modified
3054 directory, the reverted files will thus appear modified
3047 afterwards.
3055 afterwards.
3048
3056
3049 If a file has been deleted, it is restored. If the executable mode
3057 If a file has been deleted, it is restored. If the executable mode
3050 of a file was changed, it is reset.
3058 of a file was changed, it is reset.
3051
3059
3052 If names are given, all files matching the names are reverted.
3060 If names are given, all files matching the names are reverted.
3053 If no arguments are given, no files are reverted.
3061 If no arguments are given, no files are reverted.
3054
3062
3055 Modified files are saved with a .orig suffix before reverting.
3063 Modified files are saved with a .orig suffix before reverting.
3056 To disable these backups, use --no-backup.
3064 To disable these backups, use --no-backup.
3057
3065
3058 Returns 0 on success.
3066 Returns 0 on success.
3059 """
3067 """
3060
3068
3061 if opts.get("date"):
3069 if opts.get("date"):
3062 if opts.get("rev"):
3070 if opts.get("rev"):
3063 raise util.Abort(_("you can't specify a revision and a date"))
3071 raise util.Abort(_("you can't specify a revision and a date"))
3064 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3072 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3065
3073
3066 if not pats and not opts.get('all'):
3074 if not pats and not opts.get('all'):
3067 raise util.Abort(_('no files or directories specified; '
3075 raise util.Abort(_('no files or directories specified; '
3068 'use --all to revert the whole repo'))
3076 'use --all to revert the whole repo'))
3069
3077
3070 parent, p2 = repo.dirstate.parents()
3078 parent, p2 = repo.dirstate.parents()
3071 if not opts.get('rev') and p2 != nullid:
3079 if not opts.get('rev') and p2 != nullid:
3072 raise util.Abort(_('uncommitted merge - please provide a '
3080 raise util.Abort(_('uncommitted merge - please provide a '
3073 'specific revision'))
3081 'specific revision'))
3074 ctx = repo[opts.get('rev')]
3082 ctx = repo[opts.get('rev')]
3075 node = ctx.node()
3083 node = ctx.node()
3076 mf = ctx.manifest()
3084 mf = ctx.manifest()
3077 if node == parent:
3085 if node == parent:
3078 pmf = mf
3086 pmf = mf
3079 else:
3087 else:
3080 pmf = None
3088 pmf = None
3081
3089
3082 # need all matching names in dirstate and manifest of target rev,
3090 # need all matching names in dirstate and manifest of target rev,
3083 # so have to walk both. do not print errors if files exist in one
3091 # so have to walk both. do not print errors if files exist in one
3084 # but not other.
3092 # but not other.
3085
3093
3086 names = {}
3094 names = {}
3087
3095
3088 wlock = repo.wlock()
3096 wlock = repo.wlock()
3089 try:
3097 try:
3090 # walk dirstate.
3098 # walk dirstate.
3091
3099
3092 m = cmdutil.match(repo, pats, opts)
3100 m = cmdutil.match(repo, pats, opts)
3093 m.bad = lambda x, y: False
3101 m.bad = lambda x, y: False
3094 for abs in repo.walk(m):
3102 for abs in repo.walk(m):
3095 names[abs] = m.rel(abs), m.exact(abs)
3103 names[abs] = m.rel(abs), m.exact(abs)
3096
3104
3097 # walk target manifest.
3105 # walk target manifest.
3098
3106
3099 def badfn(path, msg):
3107 def badfn(path, msg):
3100 if path in names:
3108 if path in names:
3101 return
3109 return
3102 path_ = path + '/'
3110 path_ = path + '/'
3103 for f in names:
3111 for f in names:
3104 if f.startswith(path_):
3112 if f.startswith(path_):
3105 return
3113 return
3106 ui.warn("%s: %s\n" % (m.rel(path), msg))
3114 ui.warn("%s: %s\n" % (m.rel(path), msg))
3107
3115
3108 m = cmdutil.match(repo, pats, opts)
3116 m = cmdutil.match(repo, pats, opts)
3109 m.bad = badfn
3117 m.bad = badfn
3110 for abs in repo[node].walk(m):
3118 for abs in repo[node].walk(m):
3111 if abs not in names:
3119 if abs not in names:
3112 names[abs] = m.rel(abs), m.exact(abs)
3120 names[abs] = m.rel(abs), m.exact(abs)
3113
3121
3114 m = cmdutil.matchfiles(repo, names)
3122 m = cmdutil.matchfiles(repo, names)
3115 changes = repo.status(match=m)[:4]
3123 changes = repo.status(match=m)[:4]
3116 modified, added, removed, deleted = map(set, changes)
3124 modified, added, removed, deleted = map(set, changes)
3117
3125
3118 # if f is a rename, also revert the source
3126 # if f is a rename, also revert the source
3119 cwd = repo.getcwd()
3127 cwd = repo.getcwd()
3120 for f in added:
3128 for f in added:
3121 src = repo.dirstate.copied(f)
3129 src = repo.dirstate.copied(f)
3122 if src and src not in names and repo.dirstate[src] == 'r':
3130 if src and src not in names and repo.dirstate[src] == 'r':
3123 removed.add(src)
3131 removed.add(src)
3124 names[src] = (repo.pathto(src, cwd), True)
3132 names[src] = (repo.pathto(src, cwd), True)
3125
3133
3126 def removeforget(abs):
3134 def removeforget(abs):
3127 if repo.dirstate[abs] == 'a':
3135 if repo.dirstate[abs] == 'a':
3128 return _('forgetting %s\n')
3136 return _('forgetting %s\n')
3129 return _('removing %s\n')
3137 return _('removing %s\n')
3130
3138
3131 revert = ([], _('reverting %s\n'))
3139 revert = ([], _('reverting %s\n'))
3132 add = ([], _('adding %s\n'))
3140 add = ([], _('adding %s\n'))
3133 remove = ([], removeforget)
3141 remove = ([], removeforget)
3134 undelete = ([], _('undeleting %s\n'))
3142 undelete = ([], _('undeleting %s\n'))
3135
3143
3136 disptable = (
3144 disptable = (
3137 # dispatch table:
3145 # dispatch table:
3138 # file state
3146 # file state
3139 # action if in target manifest
3147 # action if in target manifest
3140 # action if not in target manifest
3148 # action if not in target manifest
3141 # make backup if in target manifest
3149 # make backup if in target manifest
3142 # make backup if not in target manifest
3150 # make backup if not in target manifest
3143 (modified, revert, remove, True, True),
3151 (modified, revert, remove, True, True),
3144 (added, revert, remove, True, False),
3152 (added, revert, remove, True, False),
3145 (removed, undelete, None, False, False),
3153 (removed, undelete, None, False, False),
3146 (deleted, revert, remove, False, False),
3154 (deleted, revert, remove, False, False),
3147 )
3155 )
3148
3156
3149 for abs, (rel, exact) in sorted(names.items()):
3157 for abs, (rel, exact) in sorted(names.items()):
3150 mfentry = mf.get(abs)
3158 mfentry = mf.get(abs)
3151 target = repo.wjoin(abs)
3159 target = repo.wjoin(abs)
3152 def handle(xlist, dobackup):
3160 def handle(xlist, dobackup):
3153 xlist[0].append(abs)
3161 xlist[0].append(abs)
3154 if (dobackup and not opts.get('no_backup') and
3162 if (dobackup and not opts.get('no_backup') and
3155 os.path.lexists(target)):
3163 os.path.lexists(target)):
3156 bakname = "%s.orig" % rel
3164 bakname = "%s.orig" % rel
3157 ui.note(_('saving current version of %s as %s\n') %
3165 ui.note(_('saving current version of %s as %s\n') %
3158 (rel, bakname))
3166 (rel, bakname))
3159 if not opts.get('dry_run'):
3167 if not opts.get('dry_run'):
3160 util.rename(target, bakname)
3168 util.rename(target, bakname)
3161 if ui.verbose or not exact:
3169 if ui.verbose or not exact:
3162 msg = xlist[1]
3170 msg = xlist[1]
3163 if not isinstance(msg, basestring):
3171 if not isinstance(msg, basestring):
3164 msg = msg(abs)
3172 msg = msg(abs)
3165 ui.status(msg % rel)
3173 ui.status(msg % rel)
3166 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3174 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3167 if abs not in table:
3175 if abs not in table:
3168 continue
3176 continue
3169 # file has changed in dirstate
3177 # file has changed in dirstate
3170 if mfentry:
3178 if mfentry:
3171 handle(hitlist, backuphit)
3179 handle(hitlist, backuphit)
3172 elif misslist is not None:
3180 elif misslist is not None:
3173 handle(misslist, backupmiss)
3181 handle(misslist, backupmiss)
3174 break
3182 break
3175 else:
3183 else:
3176 if abs not in repo.dirstate:
3184 if abs not in repo.dirstate:
3177 if mfentry:
3185 if mfentry:
3178 handle(add, True)
3186 handle(add, True)
3179 elif exact:
3187 elif exact:
3180 ui.warn(_('file not managed: %s\n') % rel)
3188 ui.warn(_('file not managed: %s\n') % rel)
3181 continue
3189 continue
3182 # file has not changed in dirstate
3190 # file has not changed in dirstate
3183 if node == parent:
3191 if node == parent:
3184 if exact:
3192 if exact:
3185 ui.warn(_('no changes needed to %s\n') % rel)
3193 ui.warn(_('no changes needed to %s\n') % rel)
3186 continue
3194 continue
3187 if pmf is None:
3195 if pmf is None:
3188 # only need parent manifest in this unlikely case,
3196 # only need parent manifest in this unlikely case,
3189 # so do not read by default
3197 # so do not read by default
3190 pmf = repo[parent].manifest()
3198 pmf = repo[parent].manifest()
3191 if abs in pmf:
3199 if abs in pmf:
3192 if mfentry:
3200 if mfentry:
3193 # if version of file is same in parent and target
3201 # if version of file is same in parent and target
3194 # manifests, do nothing
3202 # manifests, do nothing
3195 if (pmf[abs] != mfentry or
3203 if (pmf[abs] != mfentry or
3196 pmf.flags(abs) != mf.flags(abs)):
3204 pmf.flags(abs) != mf.flags(abs)):
3197 handle(revert, False)
3205 handle(revert, False)
3198 else:
3206 else:
3199 handle(remove, False)
3207 handle(remove, False)
3200
3208
3201 if not opts.get('dry_run'):
3209 if not opts.get('dry_run'):
3202 def checkout(f):
3210 def checkout(f):
3203 fc = ctx[f]
3211 fc = ctx[f]
3204 repo.wwrite(f, fc.data(), fc.flags())
3212 repo.wwrite(f, fc.data(), fc.flags())
3205
3213
3206 audit_path = util.path_auditor(repo.root)
3214 audit_path = util.path_auditor(repo.root)
3207 for f in remove[0]:
3215 for f in remove[0]:
3208 if repo.dirstate[f] == 'a':
3216 if repo.dirstate[f] == 'a':
3209 repo.dirstate.forget(f)
3217 repo.dirstate.forget(f)
3210 continue
3218 continue
3211 audit_path(f)
3219 audit_path(f)
3212 try:
3220 try:
3213 util.unlink(repo.wjoin(f))
3221 util.unlink(repo.wjoin(f))
3214 except OSError:
3222 except OSError:
3215 pass
3223 pass
3216 repo.dirstate.remove(f)
3224 repo.dirstate.remove(f)
3217
3225
3218 normal = None
3226 normal = None
3219 if node == parent:
3227 if node == parent:
3220 # We're reverting to our parent. If possible, we'd like status
3228 # We're reverting to our parent. If possible, we'd like status
3221 # to report the file as clean. We have to use normallookup for
3229 # to report the file as clean. We have to use normallookup for
3222 # merges to avoid losing information about merged/dirty files.
3230 # merges to avoid losing information about merged/dirty files.
3223 if p2 != nullid:
3231 if p2 != nullid:
3224 normal = repo.dirstate.normallookup
3232 normal = repo.dirstate.normallookup
3225 else:
3233 else:
3226 normal = repo.dirstate.normal
3234 normal = repo.dirstate.normal
3227 for f in revert[0]:
3235 for f in revert[0]:
3228 checkout(f)
3236 checkout(f)
3229 if normal:
3237 if normal:
3230 normal(f)
3238 normal(f)
3231
3239
3232 for f in add[0]:
3240 for f in add[0]:
3233 checkout(f)
3241 checkout(f)
3234 repo.dirstate.add(f)
3242 repo.dirstate.add(f)
3235
3243
3236 normal = repo.dirstate.normallookup
3244 normal = repo.dirstate.normallookup
3237 if node == parent and p2 == nullid:
3245 if node == parent and p2 == nullid:
3238 normal = repo.dirstate.normal
3246 normal = repo.dirstate.normal
3239 for f in undelete[0]:
3247 for f in undelete[0]:
3240 checkout(f)
3248 checkout(f)
3241 normal(f)
3249 normal(f)
3242
3250
3243 finally:
3251 finally:
3244 wlock.release()
3252 wlock.release()
3245
3253
3246 def rollback(ui, repo, **opts):
3254 def rollback(ui, repo, **opts):
3247 """roll back the last transaction (dangerous)
3255 """roll back the last transaction (dangerous)
3248
3256
3249 This command should be used with care. There is only one level of
3257 This command should be used with care. There is only one level of
3250 rollback, and there is no way to undo a rollback. It will also
3258 rollback, and there is no way to undo a rollback. It will also
3251 restore the dirstate at the time of the last transaction, losing
3259 restore the dirstate at the time of the last transaction, losing
3252 any dirstate changes since that time. This command does not alter
3260 any dirstate changes since that time. This command does not alter
3253 the working directory.
3261 the working directory.
3254
3262
3255 Transactions are used to encapsulate the effects of all commands
3263 Transactions are used to encapsulate the effects of all commands
3256 that create new changesets or propagate existing changesets into a
3264 that create new changesets or propagate existing changesets into a
3257 repository. For example, the following commands are transactional,
3265 repository. For example, the following commands are transactional,
3258 and their effects can be rolled back:
3266 and their effects can be rolled back:
3259
3267
3260 - commit
3268 - commit
3261 - import
3269 - import
3262 - pull
3270 - pull
3263 - push (with this repository as the destination)
3271 - push (with this repository as the destination)
3264 - unbundle
3272 - unbundle
3265
3273
3266 This command is not intended for use on public repositories. Once
3274 This command is not intended for use on public repositories. Once
3267 changes are visible for pull by other users, rolling a transaction
3275 changes are visible for pull by other users, rolling a transaction
3268 back locally is ineffective (someone else may already have pulled
3276 back locally is ineffective (someone else may already have pulled
3269 the changes). Furthermore, a race is possible with readers of the
3277 the changes). Furthermore, a race is possible with readers of the
3270 repository; for example an in-progress pull from the repository
3278 repository; for example an in-progress pull from the repository
3271 may fail if a rollback is performed.
3279 may fail if a rollback is performed.
3272
3280
3273 Returns 0 on success, 1 if no rollback data is available.
3281 Returns 0 on success, 1 if no rollback data is available.
3274 """
3282 """
3275 return repo.rollback(opts.get('dry_run'))
3283 return repo.rollback(opts.get('dry_run'))
3276
3284
3277 def root(ui, repo):
3285 def root(ui, repo):
3278 """print the root (top) of the current working directory
3286 """print the root (top) of the current working directory
3279
3287
3280 Print the root directory of the current repository.
3288 Print the root directory of the current repository.
3281
3289
3282 Returns 0 on success.
3290 Returns 0 on success.
3283 """
3291 """
3284 ui.write(repo.root + "\n")
3292 ui.write(repo.root + "\n")
3285
3293
3286 def serve(ui, repo, **opts):
3294 def serve(ui, repo, **opts):
3287 """start stand-alone webserver
3295 """start stand-alone webserver
3288
3296
3289 Start a local HTTP repository browser and pull server. You can use
3297 Start a local HTTP repository browser and pull server. You can use
3290 this for ad-hoc sharing and browing of repositories. It is
3298 this for ad-hoc sharing and browing of repositories. It is
3291 recommended to use a real web server to serve a repository for
3299 recommended to use a real web server to serve a repository for
3292 longer periods of time.
3300 longer periods of time.
3293
3301
3294 Please note that the server does not implement access control.
3302 Please note that the server does not implement access control.
3295 This means that, by default, anybody can read from the server and
3303 This means that, by default, anybody can read from the server and
3296 nobody can write to it by default. Set the ``web.allow_push``
3304 nobody can write to it by default. Set the ``web.allow_push``
3297 option to ``*`` to allow everybody to push to the server. You
3305 option to ``*`` to allow everybody to push to the server. You
3298 should use a real web server if you need to authenticate users.
3306 should use a real web server if you need to authenticate users.
3299
3307
3300 By default, the server logs accesses to stdout and errors to
3308 By default, the server logs accesses to stdout and errors to
3301 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3309 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3302 files.
3310 files.
3303
3311
3304 To have the server choose a free port number to listen on, specify
3312 To have the server choose a free port number to listen on, specify
3305 a port number of 0; in this case, the server will print the port
3313 a port number of 0; in this case, the server will print the port
3306 number it uses.
3314 number it uses.
3307
3315
3308 Returns 0 on success.
3316 Returns 0 on success.
3309 """
3317 """
3310
3318
3311 if opts["stdio"]:
3319 if opts["stdio"]:
3312 if repo is None:
3320 if repo is None:
3313 raise error.RepoError(_("There is no Mercurial repository here"
3321 raise error.RepoError(_("There is no Mercurial repository here"
3314 " (.hg not found)"))
3322 " (.hg not found)"))
3315 s = sshserver.sshserver(ui, repo)
3323 s = sshserver.sshserver(ui, repo)
3316 s.serve_forever()
3324 s.serve_forever()
3317
3325
3318 # this way we can check if something was given in the command-line
3326 # this way we can check if something was given in the command-line
3319 if opts.get('port'):
3327 if opts.get('port'):
3320 opts['port'] = util.getport(opts.get('port'))
3328 opts['port'] = util.getport(opts.get('port'))
3321
3329
3322 baseui = repo and repo.baseui or ui
3330 baseui = repo and repo.baseui or ui
3323 optlist = ("name templates style address port prefix ipv6"
3331 optlist = ("name templates style address port prefix ipv6"
3324 " accesslog errorlog certificate encoding")
3332 " accesslog errorlog certificate encoding")
3325 for o in optlist.split():
3333 for o in optlist.split():
3326 val = opts.get(o, '')
3334 val = opts.get(o, '')
3327 if val in (None, ''): # should check against default options instead
3335 if val in (None, ''): # should check against default options instead
3328 continue
3336 continue
3329 baseui.setconfig("web", o, val)
3337 baseui.setconfig("web", o, val)
3330 if repo and repo.ui != baseui:
3338 if repo and repo.ui != baseui:
3331 repo.ui.setconfig("web", o, val)
3339 repo.ui.setconfig("web", o, val)
3332
3340
3333 o = opts.get('web_conf') or opts.get('webdir_conf')
3341 o = opts.get('web_conf') or opts.get('webdir_conf')
3334 if not o:
3342 if not o:
3335 if not repo:
3343 if not repo:
3336 raise error.RepoError(_("There is no Mercurial repository"
3344 raise error.RepoError(_("There is no Mercurial repository"
3337 " here (.hg not found)"))
3345 " here (.hg not found)"))
3338 o = repo.root
3346 o = repo.root
3339
3347
3340 app = hgweb.hgweb(o, baseui=ui)
3348 app = hgweb.hgweb(o, baseui=ui)
3341
3349
3342 class service(object):
3350 class service(object):
3343 def init(self):
3351 def init(self):
3344 util.set_signal_handler()
3352 util.set_signal_handler()
3345 self.httpd = hgweb.server.create_server(ui, app)
3353 self.httpd = hgweb.server.create_server(ui, app)
3346
3354
3347 if opts['port'] and not ui.verbose:
3355 if opts['port'] and not ui.verbose:
3348 return
3356 return
3349
3357
3350 if self.httpd.prefix:
3358 if self.httpd.prefix:
3351 prefix = self.httpd.prefix.strip('/') + '/'
3359 prefix = self.httpd.prefix.strip('/') + '/'
3352 else:
3360 else:
3353 prefix = ''
3361 prefix = ''
3354
3362
3355 port = ':%d' % self.httpd.port
3363 port = ':%d' % self.httpd.port
3356 if port == ':80':
3364 if port == ':80':
3357 port = ''
3365 port = ''
3358
3366
3359 bindaddr = self.httpd.addr
3367 bindaddr = self.httpd.addr
3360 if bindaddr == '0.0.0.0':
3368 if bindaddr == '0.0.0.0':
3361 bindaddr = '*'
3369 bindaddr = '*'
3362 elif ':' in bindaddr: # IPv6
3370 elif ':' in bindaddr: # IPv6
3363 bindaddr = '[%s]' % bindaddr
3371 bindaddr = '[%s]' % bindaddr
3364
3372
3365 fqaddr = self.httpd.fqaddr
3373 fqaddr = self.httpd.fqaddr
3366 if ':' in fqaddr:
3374 if ':' in fqaddr:
3367 fqaddr = '[%s]' % fqaddr
3375 fqaddr = '[%s]' % fqaddr
3368 if opts['port']:
3376 if opts['port']:
3369 write = ui.status
3377 write = ui.status
3370 else:
3378 else:
3371 write = ui.write
3379 write = ui.write
3372 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3380 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3373 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3381 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3374
3382
3375 def run(self):
3383 def run(self):
3376 self.httpd.serve_forever()
3384 self.httpd.serve_forever()
3377
3385
3378 service = service()
3386 service = service()
3379
3387
3380 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3388 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3381
3389
3382 def status(ui, repo, *pats, **opts):
3390 def status(ui, repo, *pats, **opts):
3383 """show changed files in the working directory
3391 """show changed files in the working directory
3384
3392
3385 Show status of files in the repository. If names are given, only
3393 Show status of files in the repository. If names are given, only
3386 files that match are shown. Files that are clean or ignored or
3394 files that match are shown. Files that are clean or ignored or
3387 the source of a copy/move operation, are not listed unless
3395 the source of a copy/move operation, are not listed unless
3388 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3396 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3389 Unless options described with "show only ..." are given, the
3397 Unless options described with "show only ..." are given, the
3390 options -mardu are used.
3398 options -mardu are used.
3391
3399
3392 Option -q/--quiet hides untracked (unknown and ignored) files
3400 Option -q/--quiet hides untracked (unknown and ignored) files
3393 unless explicitly requested with -u/--unknown or -i/--ignored.
3401 unless explicitly requested with -u/--unknown or -i/--ignored.
3394
3402
3395 .. note::
3403 .. note::
3396 status may appear to disagree with diff if permissions have
3404 status may appear to disagree with diff if permissions have
3397 changed or a merge has occurred. The standard diff format does
3405 changed or a merge has occurred. The standard diff format does
3398 not report permission changes and diff only reports changes
3406 not report permission changes and diff only reports changes
3399 relative to one merge parent.
3407 relative to one merge parent.
3400
3408
3401 If one revision is given, it is used as the base revision.
3409 If one revision is given, it is used as the base revision.
3402 If two revisions are given, the differences between them are
3410 If two revisions are given, the differences between them are
3403 shown. The --change option can also be used as a shortcut to list
3411 shown. The --change option can also be used as a shortcut to list
3404 the changed files of a revision from its first parent.
3412 the changed files of a revision from its first parent.
3405
3413
3406 The codes used to show the status of files are::
3414 The codes used to show the status of files are::
3407
3415
3408 M = modified
3416 M = modified
3409 A = added
3417 A = added
3410 R = removed
3418 R = removed
3411 C = clean
3419 C = clean
3412 ! = missing (deleted by non-hg command, but still tracked)
3420 ! = missing (deleted by non-hg command, but still tracked)
3413 ? = not tracked
3421 ? = not tracked
3414 I = ignored
3422 I = ignored
3415 = origin of the previous file listed as A (added)
3423 = origin of the previous file listed as A (added)
3416
3424
3417 Returns 0 on success.
3425 Returns 0 on success.
3418 """
3426 """
3419
3427
3420 revs = opts.get('rev')
3428 revs = opts.get('rev')
3421 change = opts.get('change')
3429 change = opts.get('change')
3422
3430
3423 if revs and change:
3431 if revs and change:
3424 msg = _('cannot specify --rev and --change at the same time')
3432 msg = _('cannot specify --rev and --change at the same time')
3425 raise util.Abort(msg)
3433 raise util.Abort(msg)
3426 elif change:
3434 elif change:
3427 node2 = repo.lookup(change)
3435 node2 = repo.lookup(change)
3428 node1 = repo[node2].parents()[0].node()
3436 node1 = repo[node2].parents()[0].node()
3429 else:
3437 else:
3430 node1, node2 = cmdutil.revpair(repo, revs)
3438 node1, node2 = cmdutil.revpair(repo, revs)
3431
3439
3432 cwd = (pats and repo.getcwd()) or ''
3440 cwd = (pats and repo.getcwd()) or ''
3433 end = opts.get('print0') and '\0' or '\n'
3441 end = opts.get('print0') and '\0' or '\n'
3434 copy = {}
3442 copy = {}
3435 states = 'modified added removed deleted unknown ignored clean'.split()
3443 states = 'modified added removed deleted unknown ignored clean'.split()
3436 show = [k for k in states if opts.get(k)]
3444 show = [k for k in states if opts.get(k)]
3437 if opts.get('all'):
3445 if opts.get('all'):
3438 show += ui.quiet and (states[:4] + ['clean']) or states
3446 show += ui.quiet and (states[:4] + ['clean']) or states
3439 if not show:
3447 if not show:
3440 show = ui.quiet and states[:4] or states[:5]
3448 show = ui.quiet and states[:4] or states[:5]
3441
3449
3442 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3450 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3443 'ignored' in show, 'clean' in show, 'unknown' in show,
3451 'ignored' in show, 'clean' in show, 'unknown' in show,
3444 opts.get('subrepos'))
3452 opts.get('subrepos'))
3445 changestates = zip(states, 'MAR!?IC', stat)
3453 changestates = zip(states, 'MAR!?IC', stat)
3446
3454
3447 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3455 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3448 ctxn = repo[nullid]
3456 ctxn = repo[nullid]
3449 ctx1 = repo[node1]
3457 ctx1 = repo[node1]
3450 ctx2 = repo[node2]
3458 ctx2 = repo[node2]
3451 added = stat[1]
3459 added = stat[1]
3452 if node2 is None:
3460 if node2 is None:
3453 added = stat[0] + stat[1] # merged?
3461 added = stat[0] + stat[1] # merged?
3454
3462
3455 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3463 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3456 if k in added:
3464 if k in added:
3457 copy[k] = v
3465 copy[k] = v
3458 elif v in added:
3466 elif v in added:
3459 copy[v] = k
3467 copy[v] = k
3460
3468
3461 for state, char, files in changestates:
3469 for state, char, files in changestates:
3462 if state in show:
3470 if state in show:
3463 format = "%s %%s%s" % (char, end)
3471 format = "%s %%s%s" % (char, end)
3464 if opts.get('no_status'):
3472 if opts.get('no_status'):
3465 format = "%%s%s" % end
3473 format = "%%s%s" % end
3466
3474
3467 for f in files:
3475 for f in files:
3468 ui.write(format % repo.pathto(f, cwd),
3476 ui.write(format % repo.pathto(f, cwd),
3469 label='status.' + state)
3477 label='status.' + state)
3470 if f in copy:
3478 if f in copy:
3471 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3479 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3472 label='status.copied')
3480 label='status.copied')
3473
3481
3474 def summary(ui, repo, **opts):
3482 def summary(ui, repo, **opts):
3475 """summarize working directory state
3483 """summarize working directory state
3476
3484
3477 This generates a brief summary of the working directory state,
3485 This generates a brief summary of the working directory state,
3478 including parents, branch, commit status, and available updates.
3486 including parents, branch, commit status, and available updates.
3479
3487
3480 With the --remote option, this will check the default paths for
3488 With the --remote option, this will check the default paths for
3481 incoming and outgoing changes. This can be time-consuming.
3489 incoming and outgoing changes. This can be time-consuming.
3482
3490
3483 Returns 0 on success.
3491 Returns 0 on success.
3484 """
3492 """
3485
3493
3486 ctx = repo[None]
3494 ctx = repo[None]
3487 parents = ctx.parents()
3495 parents = ctx.parents()
3488 pnode = parents[0].node()
3496 pnode = parents[0].node()
3489
3497
3490 for p in parents:
3498 for p in parents:
3491 # label with log.changeset (instead of log.parent) since this
3499 # label with log.changeset (instead of log.parent) since this
3492 # shows a working directory parent *changeset*:
3500 # shows a working directory parent *changeset*:
3493 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3501 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3494 label='log.changeset')
3502 label='log.changeset')
3495 ui.write(' '.join(p.tags()), label='log.tag')
3503 ui.write(' '.join(p.tags()), label='log.tag')
3496 if p.rev() == -1:
3504 if p.rev() == -1:
3497 if not len(repo):
3505 if not len(repo):
3498 ui.write(_(' (empty repository)'))
3506 ui.write(_(' (empty repository)'))
3499 else:
3507 else:
3500 ui.write(_(' (no revision checked out)'))
3508 ui.write(_(' (no revision checked out)'))
3501 ui.write('\n')
3509 ui.write('\n')
3502 if p.description():
3510 if p.description():
3503 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3511 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3504 label='log.summary')
3512 label='log.summary')
3505
3513
3506 branch = ctx.branch()
3514 branch = ctx.branch()
3507 bheads = repo.branchheads(branch)
3515 bheads = repo.branchheads(branch)
3508 m = _('branch: %s\n') % branch
3516 m = _('branch: %s\n') % branch
3509 if branch != 'default':
3517 if branch != 'default':
3510 ui.write(m, label='log.branch')
3518 ui.write(m, label='log.branch')
3511 else:
3519 else:
3512 ui.status(m, label='log.branch')
3520 ui.status(m, label='log.branch')
3513
3521
3514 st = list(repo.status(unknown=True))[:6]
3522 st = list(repo.status(unknown=True))[:6]
3515
3523
3516 c = repo.dirstate.copies()
3524 c = repo.dirstate.copies()
3517 copied, renamed = [], []
3525 copied, renamed = [], []
3518 for d, s in c.iteritems():
3526 for d, s in c.iteritems():
3519 if s in st[2]:
3527 if s in st[2]:
3520 st[2].remove(s)
3528 st[2].remove(s)
3521 renamed.append(d)
3529 renamed.append(d)
3522 else:
3530 else:
3523 copied.append(d)
3531 copied.append(d)
3524 if d in st[1]:
3532 if d in st[1]:
3525 st[1].remove(d)
3533 st[1].remove(d)
3526 st.insert(3, renamed)
3534 st.insert(3, renamed)
3527 st.insert(4, copied)
3535 st.insert(4, copied)
3528
3536
3529 ms = mergemod.mergestate(repo)
3537 ms = mergemod.mergestate(repo)
3530 st.append([f for f in ms if ms[f] == 'u'])
3538 st.append([f for f in ms if ms[f] == 'u'])
3531
3539
3532 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3540 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3533 st.append(subs)
3541 st.append(subs)
3534
3542
3535 labels = [ui.label(_('%d modified'), 'status.modified'),
3543 labels = [ui.label(_('%d modified'), 'status.modified'),
3536 ui.label(_('%d added'), 'status.added'),
3544 ui.label(_('%d added'), 'status.added'),
3537 ui.label(_('%d removed'), 'status.removed'),
3545 ui.label(_('%d removed'), 'status.removed'),
3538 ui.label(_('%d renamed'), 'status.copied'),
3546 ui.label(_('%d renamed'), 'status.copied'),
3539 ui.label(_('%d copied'), 'status.copied'),
3547 ui.label(_('%d copied'), 'status.copied'),
3540 ui.label(_('%d deleted'), 'status.deleted'),
3548 ui.label(_('%d deleted'), 'status.deleted'),
3541 ui.label(_('%d unknown'), 'status.unknown'),
3549 ui.label(_('%d unknown'), 'status.unknown'),
3542 ui.label(_('%d ignored'), 'status.ignored'),
3550 ui.label(_('%d ignored'), 'status.ignored'),
3543 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3551 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3544 ui.label(_('%d subrepos'), 'status.modified')]
3552 ui.label(_('%d subrepos'), 'status.modified')]
3545 t = []
3553 t = []
3546 for s, l in zip(st, labels):
3554 for s, l in zip(st, labels):
3547 if s:
3555 if s:
3548 t.append(l % len(s))
3556 t.append(l % len(s))
3549
3557
3550 t = ', '.join(t)
3558 t = ', '.join(t)
3551 cleanworkdir = False
3559 cleanworkdir = False
3552
3560
3553 if len(parents) > 1:
3561 if len(parents) > 1:
3554 t += _(' (merge)')
3562 t += _(' (merge)')
3555 elif branch != parents[0].branch():
3563 elif branch != parents[0].branch():
3556 t += _(' (new branch)')
3564 t += _(' (new branch)')
3557 elif (parents[0].extra().get('close') and
3565 elif (parents[0].extra().get('close') and
3558 pnode in repo.branchheads(branch, closed=True)):
3566 pnode in repo.branchheads(branch, closed=True)):
3559 t += _(' (head closed)')
3567 t += _(' (head closed)')
3560 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3568 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3561 t += _(' (clean)')
3569 t += _(' (clean)')
3562 cleanworkdir = True
3570 cleanworkdir = True
3563 elif pnode not in bheads:
3571 elif pnode not in bheads:
3564 t += _(' (new branch head)')
3572 t += _(' (new branch head)')
3565
3573
3566 if cleanworkdir:
3574 if cleanworkdir:
3567 ui.status(_('commit: %s\n') % t.strip())
3575 ui.status(_('commit: %s\n') % t.strip())
3568 else:
3576 else:
3569 ui.write(_('commit: %s\n') % t.strip())
3577 ui.write(_('commit: %s\n') % t.strip())
3570
3578
3571 # all ancestors of branch heads - all ancestors of parent = new csets
3579 # all ancestors of branch heads - all ancestors of parent = new csets
3572 new = [0] * len(repo)
3580 new = [0] * len(repo)
3573 cl = repo.changelog
3581 cl = repo.changelog
3574 for a in [cl.rev(n) for n in bheads]:
3582 for a in [cl.rev(n) for n in bheads]:
3575 new[a] = 1
3583 new[a] = 1
3576 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3584 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3577 new[a] = 1
3585 new[a] = 1
3578 for a in [p.rev() for p in parents]:
3586 for a in [p.rev() for p in parents]:
3579 if a >= 0:
3587 if a >= 0:
3580 new[a] = 0
3588 new[a] = 0
3581 for a in cl.ancestors(*[p.rev() for p in parents]):
3589 for a in cl.ancestors(*[p.rev() for p in parents]):
3582 new[a] = 0
3590 new[a] = 0
3583 new = sum(new)
3591 new = sum(new)
3584
3592
3585 if new == 0:
3593 if new == 0:
3586 ui.status(_('update: (current)\n'))
3594 ui.status(_('update: (current)\n'))
3587 elif pnode not in bheads:
3595 elif pnode not in bheads:
3588 ui.write(_('update: %d new changesets (update)\n') % new)
3596 ui.write(_('update: %d new changesets (update)\n') % new)
3589 else:
3597 else:
3590 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3598 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3591 (new, len(bheads)))
3599 (new, len(bheads)))
3592
3600
3593 if opts.get('remote'):
3601 if opts.get('remote'):
3594 t = []
3602 t = []
3595 source, branches = hg.parseurl(ui.expandpath('default'))
3603 source, branches = hg.parseurl(ui.expandpath('default'))
3596 other = hg.repository(hg.remoteui(repo, {}), source)
3604 other = hg.repository(hg.remoteui(repo, {}), source)
3597 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3605 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3598 ui.debug('comparing with %s\n' % url.hidepassword(source))
3606 ui.debug('comparing with %s\n' % url.hidepassword(source))
3599 repo.ui.pushbuffer()
3607 repo.ui.pushbuffer()
3600 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3608 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3601 repo.ui.popbuffer()
3609 repo.ui.popbuffer()
3602 if incoming:
3610 if incoming:
3603 t.append(_('1 or more incoming'))
3611 t.append(_('1 or more incoming'))
3604
3612
3605 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3613 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3606 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3614 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3607 other = hg.repository(hg.remoteui(repo, {}), dest)
3615 other = hg.repository(hg.remoteui(repo, {}), dest)
3608 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3616 ui.debug('comparing with %s\n' % url.hidepassword(dest))
3609 repo.ui.pushbuffer()
3617 repo.ui.pushbuffer()
3610 o = discovery.findoutgoing(repo, other)
3618 o = discovery.findoutgoing(repo, other)
3611 repo.ui.popbuffer()
3619 repo.ui.popbuffer()
3612 o = repo.changelog.nodesbetween(o, None)[0]
3620 o = repo.changelog.nodesbetween(o, None)[0]
3613 if o:
3621 if o:
3614 t.append(_('%d outgoing') % len(o))
3622 t.append(_('%d outgoing') % len(o))
3615
3623
3616 if t:
3624 if t:
3617 ui.write(_('remote: %s\n') % (', '.join(t)))
3625 ui.write(_('remote: %s\n') % (', '.join(t)))
3618 else:
3626 else:
3619 ui.status(_('remote: (synced)\n'))
3627 ui.status(_('remote: (synced)\n'))
3620
3628
3621 def tag(ui, repo, name1, *names, **opts):
3629 def tag(ui, repo, name1, *names, **opts):
3622 """add one or more tags for the current or given revision
3630 """add one or more tags for the current or given revision
3623
3631
3624 Name a particular revision using <name>.
3632 Name a particular revision using <name>.
3625
3633
3626 Tags are used to name particular revisions of the repository and are
3634 Tags are used to name particular revisions of the repository and are
3627 very useful to compare different revisions, to go back to significant
3635 very useful to compare different revisions, to go back to significant
3628 earlier versions or to mark branch points as releases, etc.
3636 earlier versions or to mark branch points as releases, etc.
3629
3637
3630 If no revision is given, the parent of the working directory is
3638 If no revision is given, the parent of the working directory is
3631 used, or tip if no revision is checked out.
3639 used, or tip if no revision is checked out.
3632
3640
3633 To facilitate version control, distribution, and merging of tags,
3641 To facilitate version control, distribution, and merging of tags,
3634 they are stored as a file named ".hgtags" which is managed
3642 they are stored as a file named ".hgtags" which is managed
3635 similarly to other project files and can be hand-edited if
3643 similarly to other project files and can be hand-edited if
3636 necessary. The file '.hg/localtags' is used for local tags (not
3644 necessary. The file '.hg/localtags' is used for local tags (not
3637 shared among repositories).
3645 shared among repositories).
3638
3646
3639 See :hg:`help dates` for a list of formats valid for -d/--date.
3647 See :hg:`help dates` for a list of formats valid for -d/--date.
3640
3648
3641 Since tag names have priority over branch names during revision
3649 Since tag names have priority over branch names during revision
3642 lookup, using an existing branch name as a tag name is discouraged.
3650 lookup, using an existing branch name as a tag name is discouraged.
3643
3651
3644 Returns 0 on success.
3652 Returns 0 on success.
3645 """
3653 """
3646
3654
3647 rev_ = "."
3655 rev_ = "."
3648 names = [t.strip() for t in (name1,) + names]
3656 names = [t.strip() for t in (name1,) + names]
3649 if len(names) != len(set(names)):
3657 if len(names) != len(set(names)):
3650 raise util.Abort(_('tag names must be unique'))
3658 raise util.Abort(_('tag names must be unique'))
3651 for n in names:
3659 for n in names:
3652 if n in ['tip', '.', 'null']:
3660 if n in ['tip', '.', 'null']:
3653 raise util.Abort(_('the name \'%s\' is reserved') % n)
3661 raise util.Abort(_('the name \'%s\' is reserved') % n)
3654 if not n:
3662 if not n:
3655 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3663 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3656 if opts.get('rev') and opts.get('remove'):
3664 if opts.get('rev') and opts.get('remove'):
3657 raise util.Abort(_("--rev and --remove are incompatible"))
3665 raise util.Abort(_("--rev and --remove are incompatible"))
3658 if opts.get('rev'):
3666 if opts.get('rev'):
3659 rev_ = opts['rev']
3667 rev_ = opts['rev']
3660 message = opts.get('message')
3668 message = opts.get('message')
3661 if opts.get('remove'):
3669 if opts.get('remove'):
3662 expectedtype = opts.get('local') and 'local' or 'global'
3670 expectedtype = opts.get('local') and 'local' or 'global'
3663 for n in names:
3671 for n in names:
3664 if not repo.tagtype(n):
3672 if not repo.tagtype(n):
3665 raise util.Abort(_('tag \'%s\' does not exist') % n)
3673 raise util.Abort(_('tag \'%s\' does not exist') % n)
3666 if repo.tagtype(n) != expectedtype:
3674 if repo.tagtype(n) != expectedtype:
3667 if expectedtype == 'global':
3675 if expectedtype == 'global':
3668 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3676 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
3669 else:
3677 else:
3670 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3678 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
3671 rev_ = nullid
3679 rev_ = nullid
3672 if not message:
3680 if not message:
3673 # we don't translate commit messages
3681 # we don't translate commit messages
3674 message = 'Removed tag %s' % ', '.join(names)
3682 message = 'Removed tag %s' % ', '.join(names)
3675 elif not opts.get('force'):
3683 elif not opts.get('force'):
3676 for n in names:
3684 for n in names:
3677 if n in repo.tags():
3685 if n in repo.tags():
3678 raise util.Abort(_('tag \'%s\' already exists '
3686 raise util.Abort(_('tag \'%s\' already exists '
3679 '(use -f to force)') % n)
3687 '(use -f to force)') % n)
3680 if not rev_ and repo.dirstate.parents()[1] != nullid:
3688 if not rev_ and repo.dirstate.parents()[1] != nullid:
3681 raise util.Abort(_('uncommitted merge - please provide a '
3689 raise util.Abort(_('uncommitted merge - please provide a '
3682 'specific revision'))
3690 'specific revision'))
3683 r = repo[rev_].node()
3691 r = repo[rev_].node()
3684
3692
3685 if not message:
3693 if not message:
3686 # we don't translate commit messages
3694 # we don't translate commit messages
3687 message = ('Added tag %s for changeset %s' %
3695 message = ('Added tag %s for changeset %s' %
3688 (', '.join(names), short(r)))
3696 (', '.join(names), short(r)))
3689
3697
3690 date = opts.get('date')
3698 date = opts.get('date')
3691 if date:
3699 if date:
3692 date = util.parsedate(date)
3700 date = util.parsedate(date)
3693
3701
3694 if opts.get('edit'):
3702 if opts.get('edit'):
3695 message = ui.edit(message, ui.username())
3703 message = ui.edit(message, ui.username())
3696
3704
3697 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3705 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
3698
3706
3699 def tags(ui, repo):
3707 def tags(ui, repo):
3700 """list repository tags
3708 """list repository tags
3701
3709
3702 This lists both regular and local tags. When the -v/--verbose
3710 This lists both regular and local tags. When the -v/--verbose
3703 switch is used, a third column "local" is printed for local tags.
3711 switch is used, a third column "local" is printed for local tags.
3704
3712
3705 Returns 0 on success.
3713 Returns 0 on success.
3706 """
3714 """
3707
3715
3708 hexfunc = ui.debugflag and hex or short
3716 hexfunc = ui.debugflag and hex or short
3709 tagtype = ""
3717 tagtype = ""
3710
3718
3711 for t, n in reversed(repo.tagslist()):
3719 for t, n in reversed(repo.tagslist()):
3712 if ui.quiet:
3720 if ui.quiet:
3713 ui.write("%s\n" % t)
3721 ui.write("%s\n" % t)
3714 continue
3722 continue
3715
3723
3716 try:
3724 try:
3717 hn = hexfunc(n)
3725 hn = hexfunc(n)
3718 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3726 r = "%5d:%s" % (repo.changelog.rev(n), hn)
3719 except error.LookupError:
3727 except error.LookupError:
3720 r = " ?:%s" % hn
3728 r = " ?:%s" % hn
3721 else:
3729 else:
3722 spaces = " " * (30 - encoding.colwidth(t))
3730 spaces = " " * (30 - encoding.colwidth(t))
3723 if ui.verbose:
3731 if ui.verbose:
3724 if repo.tagtype(t) == 'local':
3732 if repo.tagtype(t) == 'local':
3725 tagtype = " local"
3733 tagtype = " local"
3726 else:
3734 else:
3727 tagtype = ""
3735 tagtype = ""
3728 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3736 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
3729
3737
3730 def tip(ui, repo, **opts):
3738 def tip(ui, repo, **opts):
3731 """show the tip revision
3739 """show the tip revision
3732
3740
3733 The tip revision (usually just called the tip) is the changeset
3741 The tip revision (usually just called the tip) is the changeset
3734 most recently added to the repository (and therefore the most
3742 most recently added to the repository (and therefore the most
3735 recently changed head).
3743 recently changed head).
3736
3744
3737 If you have just made a commit, that commit will be the tip. If
3745 If you have just made a commit, that commit will be the tip. If
3738 you have just pulled changes from another repository, the tip of
3746 you have just pulled changes from another repository, the tip of
3739 that repository becomes the current tip. The "tip" tag is special
3747 that repository becomes the current tip. The "tip" tag is special
3740 and cannot be renamed or assigned to a different changeset.
3748 and cannot be renamed or assigned to a different changeset.
3741
3749
3742 Returns 0 on success.
3750 Returns 0 on success.
3743 """
3751 """
3744 displayer = cmdutil.show_changeset(ui, repo, opts)
3752 displayer = cmdutil.show_changeset(ui, repo, opts)
3745 displayer.show(repo[len(repo) - 1])
3753 displayer.show(repo[len(repo) - 1])
3746 displayer.close()
3754 displayer.close()
3747
3755
3748 def unbundle(ui, repo, fname1, *fnames, **opts):
3756 def unbundle(ui, repo, fname1, *fnames, **opts):
3749 """apply one or more changegroup files
3757 """apply one or more changegroup files
3750
3758
3751 Apply one or more compressed changegroup files generated by the
3759 Apply one or more compressed changegroup files generated by the
3752 bundle command.
3760 bundle command.
3753
3761
3754 Returns 0 on success, 1 if an update has unresolved files.
3762 Returns 0 on success, 1 if an update has unresolved files.
3755 """
3763 """
3756 fnames = (fname1,) + fnames
3764 fnames = (fname1,) + fnames
3757
3765
3758 lock = repo.lock()
3766 lock = repo.lock()
3759 try:
3767 try:
3760 for fname in fnames:
3768 for fname in fnames:
3761 f = url.open(ui, fname)
3769 f = url.open(ui, fname)
3762 gen = changegroup.readbundle(f, fname)
3770 gen = changegroup.readbundle(f, fname)
3763 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3771 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
3764 lock=lock)
3772 lock=lock)
3765 finally:
3773 finally:
3766 lock.release()
3774 lock.release()
3767
3775
3768 return postincoming(ui, repo, modheads, opts.get('update'), None)
3776 return postincoming(ui, repo, modheads, opts.get('update'), None)
3769
3777
3770 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3778 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
3771 """update working directory (or switch revisions)
3779 """update working directory (or switch revisions)
3772
3780
3773 Update the repository's working directory to the specified
3781 Update the repository's working directory to the specified
3774 changeset. If no changeset is specified, update to the tip of the
3782 changeset. If no changeset is specified, update to the tip of the
3775 current named branch.
3783 current named branch.
3776
3784
3777 If the changeset is not a descendant of the working directory's
3785 If the changeset is not a descendant of the working directory's
3778 parent, the update is aborted. With the -c/--check option, the
3786 parent, the update is aborted. With the -c/--check option, the
3779 working directory is checked for uncommitted changes; if none are
3787 working directory is checked for uncommitted changes; if none are
3780 found, the working directory is updated to the specified
3788 found, the working directory is updated to the specified
3781 changeset.
3789 changeset.
3782
3790
3783 The following rules apply when the working directory contains
3791 The following rules apply when the working directory contains
3784 uncommitted changes:
3792 uncommitted changes:
3785
3793
3786 1. If neither -c/--check nor -C/--clean is specified, and if
3794 1. If neither -c/--check nor -C/--clean is specified, and if
3787 the requested changeset is an ancestor or descendant of
3795 the requested changeset is an ancestor or descendant of
3788 the working directory's parent, the uncommitted changes
3796 the working directory's parent, the uncommitted changes
3789 are merged into the requested changeset and the merged
3797 are merged into the requested changeset and the merged
3790 result is left uncommitted. If the requested changeset is
3798 result is left uncommitted. If the requested changeset is
3791 not an ancestor or descendant (that is, it is on another
3799 not an ancestor or descendant (that is, it is on another
3792 branch), the update is aborted and the uncommitted changes
3800 branch), the update is aborted and the uncommitted changes
3793 are preserved.
3801 are preserved.
3794
3802
3795 2. With the -c/--check option, the update is aborted and the
3803 2. With the -c/--check option, the update is aborted and the
3796 uncommitted changes are preserved.
3804 uncommitted changes are preserved.
3797
3805
3798 3. With the -C/--clean option, uncommitted changes are discarded and
3806 3. With the -C/--clean option, uncommitted changes are discarded and
3799 the working directory is updated to the requested changeset.
3807 the working directory is updated to the requested changeset.
3800
3808
3801 Use null as the changeset to remove the working directory (like
3809 Use null as the changeset to remove the working directory (like
3802 :hg:`clone -U`).
3810 :hg:`clone -U`).
3803
3811
3804 If you want to update just one file to an older changeset, use
3812 If you want to update just one file to an older changeset, use
3805 :hg:`revert`.
3813 :hg:`revert`.
3806
3814
3807 See :hg:`help dates` for a list of formats valid for -d/--date.
3815 See :hg:`help dates` for a list of formats valid for -d/--date.
3808
3816
3809 Returns 0 on success, 1 if there are unresolved files.
3817 Returns 0 on success, 1 if there are unresolved files.
3810 """
3818 """
3811 if rev and node:
3819 if rev and node:
3812 raise util.Abort(_("please specify just one revision"))
3820 raise util.Abort(_("please specify just one revision"))
3813
3821
3814 if not rev:
3822 if not rev:
3815 rev = node
3823 rev = node
3816
3824
3817 rev = cmdutil.revsingle(repo, rev, rev).rev()
3825 rev = cmdutil.revsingle(repo, rev, rev).rev()
3818
3826
3819 if check and clean:
3827 if check and clean:
3820 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3828 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
3821
3829
3822 if check:
3830 if check:
3823 # we could use dirty() but we can ignore merge and branch trivia
3831 # we could use dirty() but we can ignore merge and branch trivia
3824 c = repo[None]
3832 c = repo[None]
3825 if c.modified() or c.added() or c.removed():
3833 if c.modified() or c.added() or c.removed():
3826 raise util.Abort(_("uncommitted local changes"))
3834 raise util.Abort(_("uncommitted local changes"))
3827
3835
3828 if date:
3836 if date:
3829 if rev:
3837 if rev:
3830 raise util.Abort(_("you can't specify a revision and a date"))
3838 raise util.Abort(_("you can't specify a revision and a date"))
3831 rev = cmdutil.finddate(ui, repo, date)
3839 rev = cmdutil.finddate(ui, repo, date)
3832
3840
3833 if clean or check:
3841 if clean or check:
3834 return hg.clean(repo, rev)
3842 return hg.clean(repo, rev)
3835 else:
3843 else:
3836 return hg.update(repo, rev)
3844 return hg.update(repo, rev)
3837
3845
3838 def verify(ui, repo):
3846 def verify(ui, repo):
3839 """verify the integrity of the repository
3847 """verify the integrity of the repository
3840
3848
3841 Verify the integrity of the current repository.
3849 Verify the integrity of the current repository.
3842
3850
3843 This will perform an extensive check of the repository's
3851 This will perform an extensive check of the repository's
3844 integrity, validating the hashes and checksums of each entry in
3852 integrity, validating the hashes and checksums of each entry in
3845 the changelog, manifest, and tracked files, as well as the
3853 the changelog, manifest, and tracked files, as well as the
3846 integrity of their crosslinks and indices.
3854 integrity of their crosslinks and indices.
3847
3855
3848 Returns 0 on success, 1 if errors are encountered.
3856 Returns 0 on success, 1 if errors are encountered.
3849 """
3857 """
3850 return hg.verify(repo)
3858 return hg.verify(repo)
3851
3859
3852 def version_(ui):
3860 def version_(ui):
3853 """output version and copyright information"""
3861 """output version and copyright information"""
3854 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3862 ui.write(_("Mercurial Distributed SCM (version %s)\n")
3855 % util.version())
3863 % util.version())
3856 ui.status(_(
3864 ui.status(_(
3857 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3865 "\nCopyright (C) 2005-2010 Matt Mackall <mpm@selenic.com> and others\n"
3858 "This is free software; see the source for copying conditions. "
3866 "This is free software; see the source for copying conditions. "
3859 "There is NO\nwarranty; "
3867 "There is NO\nwarranty; "
3860 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3868 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
3861 ))
3869 ))
3862
3870
3863 # Command options and aliases are listed here, alphabetically
3871 # Command options and aliases are listed here, alphabetically
3864
3872
3865 globalopts = [
3873 globalopts = [
3866 ('R', 'repository', '',
3874 ('R', 'repository', '',
3867 _('repository root directory or name of overlay bundle file'),
3875 _('repository root directory or name of overlay bundle file'),
3868 _('REPO')),
3876 _('REPO')),
3869 ('', 'cwd', '',
3877 ('', 'cwd', '',
3870 _('change working directory'), _('DIR')),
3878 _('change working directory'), _('DIR')),
3871 ('y', 'noninteractive', None,
3879 ('y', 'noninteractive', None,
3872 _('do not prompt, assume \'yes\' for any required answers')),
3880 _('do not prompt, assume \'yes\' for any required answers')),
3873 ('q', 'quiet', None, _('suppress output')),
3881 ('q', 'quiet', None, _('suppress output')),
3874 ('v', 'verbose', None, _('enable additional output')),
3882 ('v', 'verbose', None, _('enable additional output')),
3875 ('', 'config', [],
3883 ('', 'config', [],
3876 _('set/override config option (use \'section.name=value\')'),
3884 _('set/override config option (use \'section.name=value\')'),
3877 _('CONFIG')),
3885 _('CONFIG')),
3878 ('', 'debug', None, _('enable debugging output')),
3886 ('', 'debug', None, _('enable debugging output')),
3879 ('', 'debugger', None, _('start debugger')),
3887 ('', 'debugger', None, _('start debugger')),
3880 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3888 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
3881 _('ENCODE')),
3889 _('ENCODE')),
3882 ('', 'encodingmode', encoding.encodingmode,
3890 ('', 'encodingmode', encoding.encodingmode,
3883 _('set the charset encoding mode'), _('MODE')),
3891 _('set the charset encoding mode'), _('MODE')),
3884 ('', 'traceback', None, _('always print a traceback on exception')),
3892 ('', 'traceback', None, _('always print a traceback on exception')),
3885 ('', 'time', None, _('time how long the command takes')),
3893 ('', 'time', None, _('time how long the command takes')),
3886 ('', 'profile', None, _('print command execution profile')),
3894 ('', 'profile', None, _('print command execution profile')),
3887 ('', 'version', None, _('output version information and exit')),
3895 ('', 'version', None, _('output version information and exit')),
3888 ('h', 'help', None, _('display help and exit')),
3896 ('h', 'help', None, _('display help and exit')),
3889 ]
3897 ]
3890
3898
3891 dryrunopts = [('n', 'dry-run', None,
3899 dryrunopts = [('n', 'dry-run', None,
3892 _('do not perform actions, just print output'))]
3900 _('do not perform actions, just print output'))]
3893
3901
3894 remoteopts = [
3902 remoteopts = [
3895 ('e', 'ssh', '',
3903 ('e', 'ssh', '',
3896 _('specify ssh command to use'), _('CMD')),
3904 _('specify ssh command to use'), _('CMD')),
3897 ('', 'remotecmd', '',
3905 ('', 'remotecmd', '',
3898 _('specify hg command to run on the remote side'), _('CMD')),
3906 _('specify hg command to run on the remote side'), _('CMD')),
3899 ]
3907 ]
3900
3908
3901 walkopts = [
3909 walkopts = [
3902 ('I', 'include', [],
3910 ('I', 'include', [],
3903 _('include names matching the given patterns'), _('PATTERN')),
3911 _('include names matching the given patterns'), _('PATTERN')),
3904 ('X', 'exclude', [],
3912 ('X', 'exclude', [],
3905 _('exclude names matching the given patterns'), _('PATTERN')),
3913 _('exclude names matching the given patterns'), _('PATTERN')),
3906 ]
3914 ]
3907
3915
3908 commitopts = [
3916 commitopts = [
3909 ('m', 'message', '',
3917 ('m', 'message', '',
3910 _('use text as commit message'), _('TEXT')),
3918 _('use text as commit message'), _('TEXT')),
3911 ('l', 'logfile', '',
3919 ('l', 'logfile', '',
3912 _('read commit message from file'), _('FILE')),
3920 _('read commit message from file'), _('FILE')),
3913 ]
3921 ]
3914
3922
3915 commitopts2 = [
3923 commitopts2 = [
3916 ('d', 'date', '',
3924 ('d', 'date', '',
3917 _('record datecode as commit date'), _('DATE')),
3925 _('record datecode as commit date'), _('DATE')),
3918 ('u', 'user', '',
3926 ('u', 'user', '',
3919 _('record the specified user as committer'), _('USER')),
3927 _('record the specified user as committer'), _('USER')),
3920 ]
3928 ]
3921
3929
3922 templateopts = [
3930 templateopts = [
3923 ('', 'style', '',
3931 ('', 'style', '',
3924 _('display using template map file'), _('STYLE')),
3932 _('display using template map file'), _('STYLE')),
3925 ('', 'template', '',
3933 ('', 'template', '',
3926 _('display with template'), _('TEMPLATE')),
3934 _('display with template'), _('TEMPLATE')),
3927 ]
3935 ]
3928
3936
3929 logopts = [
3937 logopts = [
3930 ('p', 'patch', None, _('show patch')),
3938 ('p', 'patch', None, _('show patch')),
3931 ('g', 'git', None, _('use git extended diff format')),
3939 ('g', 'git', None, _('use git extended diff format')),
3932 ('l', 'limit', '',
3940 ('l', 'limit', '',
3933 _('limit number of changes displayed'), _('NUM')),
3941 _('limit number of changes displayed'), _('NUM')),
3934 ('M', 'no-merges', None, _('do not show merges')),
3942 ('M', 'no-merges', None, _('do not show merges')),
3935 ('', 'stat', None, _('output diffstat-style summary of changes')),
3943 ('', 'stat', None, _('output diffstat-style summary of changes')),
3936 ] + templateopts
3944 ] + templateopts
3937
3945
3938 diffopts = [
3946 diffopts = [
3939 ('a', 'text', None, _('treat all files as text')),
3947 ('a', 'text', None, _('treat all files as text')),
3940 ('g', 'git', None, _('use git extended diff format')),
3948 ('g', 'git', None, _('use git extended diff format')),
3941 ('', 'nodates', None, _('omit dates from diff headers'))
3949 ('', 'nodates', None, _('omit dates from diff headers'))
3942 ]
3950 ]
3943
3951
3944 diffopts2 = [
3952 diffopts2 = [
3945 ('p', 'show-function', None, _('show which function each change is in')),
3953 ('p', 'show-function', None, _('show which function each change is in')),
3946 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3954 ('', 'reverse', None, _('produce a diff that undoes the changes')),
3947 ('w', 'ignore-all-space', None,
3955 ('w', 'ignore-all-space', None,
3948 _('ignore white space when comparing lines')),
3956 _('ignore white space when comparing lines')),
3949 ('b', 'ignore-space-change', None,
3957 ('b', 'ignore-space-change', None,
3950 _('ignore changes in the amount of white space')),
3958 _('ignore changes in the amount of white space')),
3951 ('B', 'ignore-blank-lines', None,
3959 ('B', 'ignore-blank-lines', None,
3952 _('ignore changes whose lines are all blank')),
3960 _('ignore changes whose lines are all blank')),
3953 ('U', 'unified', '',
3961 ('U', 'unified', '',
3954 _('number of lines of context to show'), _('NUM')),
3962 _('number of lines of context to show'), _('NUM')),
3955 ('', 'stat', None, _('output diffstat-style summary of changes')),
3963 ('', 'stat', None, _('output diffstat-style summary of changes')),
3956 ]
3964 ]
3957
3965
3958 similarityopts = [
3966 similarityopts = [
3959 ('s', 'similarity', '',
3967 ('s', 'similarity', '',
3960 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3968 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
3961 ]
3969 ]
3962
3970
3963 subrepoopts = [
3971 subrepoopts = [
3964 ('S', 'subrepos', None,
3972 ('S', 'subrepos', None,
3965 _('recurse into subrepositories'))
3973 _('recurse into subrepositories'))
3966 ]
3974 ]
3967
3975
3968 table = {
3976 table = {
3969 "^add": (add, walkopts + subrepoopts + dryrunopts,
3977 "^add": (add, walkopts + subrepoopts + dryrunopts,
3970 _('[OPTION]... [FILE]...')),
3978 _('[OPTION]... [FILE]...')),
3971 "addremove":
3979 "addremove":
3972 (addremove, similarityopts + walkopts + dryrunopts,
3980 (addremove, similarityopts + walkopts + dryrunopts,
3973 _('[OPTION]... [FILE]...')),
3981 _('[OPTION]... [FILE]...')),
3974 "^annotate|blame":
3982 "^annotate|blame":
3975 (annotate,
3983 (annotate,
3976 [('r', 'rev', '',
3984 [('r', 'rev', '',
3977 _('annotate the specified revision'), _('REV')),
3985 _('annotate the specified revision'), _('REV')),
3978 ('', 'follow', None,
3986 ('', 'follow', None,
3979 _('follow copies/renames and list the filename (DEPRECATED)')),
3987 _('follow copies/renames and list the filename (DEPRECATED)')),
3980 ('', 'no-follow', None, _("don't follow copies and renames")),
3988 ('', 'no-follow', None, _("don't follow copies and renames")),
3981 ('a', 'text', None, _('treat all files as text')),
3989 ('a', 'text', None, _('treat all files as text')),
3982 ('u', 'user', None, _('list the author (long with -v)')),
3990 ('u', 'user', None, _('list the author (long with -v)')),
3983 ('f', 'file', None, _('list the filename')),
3991 ('f', 'file', None, _('list the filename')),
3984 ('d', 'date', None, _('list the date (short with -q)')),
3992 ('d', 'date', None, _('list the date (short with -q)')),
3985 ('n', 'number', None, _('list the revision number (default)')),
3993 ('n', 'number', None, _('list the revision number (default)')),
3986 ('c', 'changeset', None, _('list the changeset')),
3994 ('c', 'changeset', None, _('list the changeset')),
3987 ('l', 'line-number', None,
3995 ('l', 'line-number', None,
3988 _('show line number at the first appearance'))
3996 _('show line number at the first appearance'))
3989 ] + walkopts,
3997 ] + walkopts,
3990 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3998 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3991 "archive":
3999 "archive":
3992 (archive,
4000 (archive,
3993 [('', 'no-decode', None, _('do not pass files through decoders')),
4001 [('', 'no-decode', None, _('do not pass files through decoders')),
3994 ('p', 'prefix', '',
4002 ('p', 'prefix', '',
3995 _('directory prefix for files in archive'), _('PREFIX')),
4003 _('directory prefix for files in archive'), _('PREFIX')),
3996 ('r', 'rev', '',
4004 ('r', 'rev', '',
3997 _('revision to distribute'), _('REV')),
4005 _('revision to distribute'), _('REV')),
3998 ('t', 'type', '',
4006 ('t', 'type', '',
3999 _('type of distribution to create'), _('TYPE')),
4007 _('type of distribution to create'), _('TYPE')),
4000 ] + subrepoopts + walkopts,
4008 ] + subrepoopts + walkopts,
4001 _('[OPTION]... DEST')),
4009 _('[OPTION]... DEST')),
4002 "backout":
4010 "backout":
4003 (backout,
4011 (backout,
4004 [('', 'merge', None,
4012 [('', 'merge', None,
4005 _('merge with old dirstate parent after backout')),
4013 _('merge with old dirstate parent after backout')),
4006 ('', 'parent', '',
4014 ('', 'parent', '',
4007 _('parent to choose when backing out merge'), _('REV')),
4015 _('parent to choose when backing out merge'), _('REV')),
4016 ('t', 'tool', '',
4017 _('specify merge tool')),
4008 ('r', 'rev', '',
4018 ('r', 'rev', '',
4009 _('revision to backout'), _('REV')),
4019 _('revision to backout'), _('REV')),
4010 ] + walkopts + commitopts + commitopts2,
4020 ] + walkopts + commitopts + commitopts2,
4011 _('[OPTION]... [-r] REV')),
4021 _('[OPTION]... [-r] REV')),
4012 "bisect":
4022 "bisect":
4013 (bisect,
4023 (bisect,
4014 [('r', 'reset', False, _('reset bisect state')),
4024 [('r', 'reset', False, _('reset bisect state')),
4015 ('g', 'good', False, _('mark changeset good')),
4025 ('g', 'good', False, _('mark changeset good')),
4016 ('b', 'bad', False, _('mark changeset bad')),
4026 ('b', 'bad', False, _('mark changeset bad')),
4017 ('s', 'skip', False, _('skip testing changeset')),
4027 ('s', 'skip', False, _('skip testing changeset')),
4018 ('c', 'command', '',
4028 ('c', 'command', '',
4019 _('use command to check changeset state'), _('CMD')),
4029 _('use command to check changeset state'), _('CMD')),
4020 ('U', 'noupdate', False, _('do not update to target'))],
4030 ('U', 'noupdate', False, _('do not update to target'))],
4021 _("[-gbsr] [-U] [-c CMD] [REV]")),
4031 _("[-gbsr] [-U] [-c CMD] [REV]")),
4022 "branch":
4032 "branch":
4023 (branch,
4033 (branch,
4024 [('f', 'force', None,
4034 [('f', 'force', None,
4025 _('set branch name even if it shadows an existing branch')),
4035 _('set branch name even if it shadows an existing branch')),
4026 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4036 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4027 _('[-fC] [NAME]')),
4037 _('[-fC] [NAME]')),
4028 "branches":
4038 "branches":
4029 (branches,
4039 (branches,
4030 [('a', 'active', False,
4040 [('a', 'active', False,
4031 _('show only branches that have unmerged heads')),
4041 _('show only branches that have unmerged heads')),
4032 ('c', 'closed', False,
4042 ('c', 'closed', False,
4033 _('show normal and closed branches'))],
4043 _('show normal and closed branches'))],
4034 _('[-ac]')),
4044 _('[-ac]')),
4035 "bundle":
4045 "bundle":
4036 (bundle,
4046 (bundle,
4037 [('f', 'force', None,
4047 [('f', 'force', None,
4038 _('run even when the destination is unrelated')),
4048 _('run even when the destination is unrelated')),
4039 ('r', 'rev', [],
4049 ('r', 'rev', [],
4040 _('a changeset intended to be added to the destination'),
4050 _('a changeset intended to be added to the destination'),
4041 _('REV')),
4051 _('REV')),
4042 ('b', 'branch', [],
4052 ('b', 'branch', [],
4043 _('a specific branch you would like to bundle'),
4053 _('a specific branch you would like to bundle'),
4044 _('BRANCH')),
4054 _('BRANCH')),
4045 ('', 'base', [],
4055 ('', 'base', [],
4046 _('a base changeset assumed to be available at the destination'),
4056 _('a base changeset assumed to be available at the destination'),
4047 _('REV')),
4057 _('REV')),
4048 ('a', 'all', None, _('bundle all changesets in the repository')),
4058 ('a', 'all', None, _('bundle all changesets in the repository')),
4049 ('t', 'type', 'bzip2',
4059 ('t', 'type', 'bzip2',
4050 _('bundle compression type to use'), _('TYPE')),
4060 _('bundle compression type to use'), _('TYPE')),
4051 ] + remoteopts,
4061 ] + remoteopts,
4052 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4062 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4053 "cat":
4063 "cat":
4054 (cat,
4064 (cat,
4055 [('o', 'output', '',
4065 [('o', 'output', '',
4056 _('print output to file with formatted name'), _('FORMAT')),
4066 _('print output to file with formatted name'), _('FORMAT')),
4057 ('r', 'rev', '',
4067 ('r', 'rev', '',
4058 _('print the given revision'), _('REV')),
4068 _('print the given revision'), _('REV')),
4059 ('', 'decode', None, _('apply any matching decode filter')),
4069 ('', 'decode', None, _('apply any matching decode filter')),
4060 ] + walkopts,
4070 ] + walkopts,
4061 _('[OPTION]... FILE...')),
4071 _('[OPTION]... FILE...')),
4062 "^clone":
4072 "^clone":
4063 (clone,
4073 (clone,
4064 [('U', 'noupdate', None,
4074 [('U', 'noupdate', None,
4065 _('the clone will include an empty working copy (only a repository)')),
4075 _('the clone will include an empty working copy (only a repository)')),
4066 ('u', 'updaterev', '',
4076 ('u', 'updaterev', '',
4067 _('revision, tag or branch to check out'), _('REV')),
4077 _('revision, tag or branch to check out'), _('REV')),
4068 ('r', 'rev', [],
4078 ('r', 'rev', [],
4069 _('include the specified changeset'), _('REV')),
4079 _('include the specified changeset'), _('REV')),
4070 ('b', 'branch', [],
4080 ('b', 'branch', [],
4071 _('clone only the specified branch'), _('BRANCH')),
4081 _('clone only the specified branch'), _('BRANCH')),
4072 ('', 'pull', None, _('use pull protocol to copy metadata')),
4082 ('', 'pull', None, _('use pull protocol to copy metadata')),
4073 ('', 'uncompressed', None,
4083 ('', 'uncompressed', None,
4074 _('use uncompressed transfer (fast over LAN)')),
4084 _('use uncompressed transfer (fast over LAN)')),
4075 ] + remoteopts,
4085 ] + remoteopts,
4076 _('[OPTION]... SOURCE [DEST]')),
4086 _('[OPTION]... SOURCE [DEST]')),
4077 "^commit|ci":
4087 "^commit|ci":
4078 (commit,
4088 (commit,
4079 [('A', 'addremove', None,
4089 [('A', 'addremove', None,
4080 _('mark new/missing files as added/removed before committing')),
4090 _('mark new/missing files as added/removed before committing')),
4081 ('', 'close-branch', None,
4091 ('', 'close-branch', None,
4082 _('mark a branch as closed, hiding it from the branch list')),
4092 _('mark a branch as closed, hiding it from the branch list')),
4083 ] + walkopts + commitopts + commitopts2,
4093 ] + walkopts + commitopts + commitopts2,
4084 _('[OPTION]... [FILE]...')),
4094 _('[OPTION]... [FILE]...')),
4085 "copy|cp":
4095 "copy|cp":
4086 (copy,
4096 (copy,
4087 [('A', 'after', None, _('record a copy that has already occurred')),
4097 [('A', 'after', None, _('record a copy that has already occurred')),
4088 ('f', 'force', None,
4098 ('f', 'force', None,
4089 _('forcibly copy over an existing managed file')),
4099 _('forcibly copy over an existing managed file')),
4090 ] + walkopts + dryrunopts,
4100 ] + walkopts + dryrunopts,
4091 _('[OPTION]... [SOURCE]... DEST')),
4101 _('[OPTION]... [SOURCE]... DEST')),
4092 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4102 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4093 "debugbuilddag":
4103 "debugbuilddag":
4094 (debugbuilddag,
4104 (debugbuilddag,
4095 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4105 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4096 ('a', 'appended-file', None, _('add single file all revs append to')),
4106 ('a', 'appended-file', None, _('add single file all revs append to')),
4097 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4107 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4098 ('n', 'new-file', None, _('add new file at each rev')),
4108 ('n', 'new-file', None, _('add new file at each rev')),
4099 ],
4109 ],
4100 _('[OPTION]... TEXT')),
4110 _('[OPTION]... TEXT')),
4101 "debugcheckstate": (debugcheckstate, [], ''),
4111 "debugcheckstate": (debugcheckstate, [], ''),
4102 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4112 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4103 "debugcomplete":
4113 "debugcomplete":
4104 (debugcomplete,
4114 (debugcomplete,
4105 [('o', 'options', None, _('show the command options'))],
4115 [('o', 'options', None, _('show the command options'))],
4106 _('[-o] CMD')),
4116 _('[-o] CMD')),
4107 "debugdag":
4117 "debugdag":
4108 (debugdag,
4118 (debugdag,
4109 [('t', 'tags', None, _('use tags as labels')),
4119 [('t', 'tags', None, _('use tags as labels')),
4110 ('b', 'branches', None, _('annotate with branch names')),
4120 ('b', 'branches', None, _('annotate with branch names')),
4111 ('', 'dots', None, _('use dots for runs')),
4121 ('', 'dots', None, _('use dots for runs')),
4112 ('s', 'spaces', None, _('separate elements by spaces')),
4122 ('s', 'spaces', None, _('separate elements by spaces')),
4113 ],
4123 ],
4114 _('[OPTION]... [FILE [REV]...]')),
4124 _('[OPTION]... [FILE [REV]...]')),
4115 "debugdate":
4125 "debugdate":
4116 (debugdate,
4126 (debugdate,
4117 [('e', 'extended', None, _('try extended date formats'))],
4127 [('e', 'extended', None, _('try extended date formats'))],
4118 _('[-e] DATE [RANGE]')),
4128 _('[-e] DATE [RANGE]')),
4119 "debugdata": (debugdata, [], _('FILE REV')),
4129 "debugdata": (debugdata, [], _('FILE REV')),
4120 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4130 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4121 "debugindex": (debugindex, [], _('FILE')),
4131 "debugindex": (debugindex, [], _('FILE')),
4122 "debugindexdot": (debugindexdot, [], _('FILE')),
4132 "debugindexdot": (debugindexdot, [], _('FILE')),
4123 "debuginstall": (debuginstall, [], ''),
4133 "debuginstall": (debuginstall, [], ''),
4124 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4134 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4125 "debugrebuildstate":
4135 "debugrebuildstate":
4126 (debugrebuildstate,
4136 (debugrebuildstate,
4127 [('r', 'rev', '',
4137 [('r', 'rev', '',
4128 _('revision to rebuild to'), _('REV'))],
4138 _('revision to rebuild to'), _('REV'))],
4129 _('[-r REV] [REV]')),
4139 _('[-r REV] [REV]')),
4130 "debugrename":
4140 "debugrename":
4131 (debugrename,
4141 (debugrename,
4132 [('r', 'rev', '',
4142 [('r', 'rev', '',
4133 _('revision to debug'), _('REV'))],
4143 _('revision to debug'), _('REV'))],
4134 _('[-r REV] FILE')),
4144 _('[-r REV] FILE')),
4135 "debugrevspec":
4145 "debugrevspec":
4136 (debugrevspec, [], ('REVSPEC')),
4146 (debugrevspec, [], ('REVSPEC')),
4137 "debugsetparents":
4147 "debugsetparents":
4138 (debugsetparents, [], _('REV1 [REV2]')),
4148 (debugsetparents, [], _('REV1 [REV2]')),
4139 "debugstate":
4149 "debugstate":
4140 (debugstate,
4150 (debugstate,
4141 [('', 'nodates', None, _('do not display the saved mtime'))],
4151 [('', 'nodates', None, _('do not display the saved mtime'))],
4142 _('[OPTION]...')),
4152 _('[OPTION]...')),
4143 "debugsub":
4153 "debugsub":
4144 (debugsub,
4154 (debugsub,
4145 [('r', 'rev', '',
4155 [('r', 'rev', '',
4146 _('revision to check'), _('REV'))],
4156 _('revision to check'), _('REV'))],
4147 _('[-r REV] [REV]')),
4157 _('[-r REV] [REV]')),
4148 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4158 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4149 "^diff":
4159 "^diff":
4150 (diff,
4160 (diff,
4151 [('r', 'rev', [],
4161 [('r', 'rev', [],
4152 _('revision'), _('REV')),
4162 _('revision'), _('REV')),
4153 ('c', 'change', '',
4163 ('c', 'change', '',
4154 _('change made by revision'), _('REV'))
4164 _('change made by revision'), _('REV'))
4155 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4165 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4156 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4166 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4157 "^export":
4167 "^export":
4158 (export,
4168 (export,
4159 [('o', 'output', '',
4169 [('o', 'output', '',
4160 _('print output to file with formatted name'), _('FORMAT')),
4170 _('print output to file with formatted name'), _('FORMAT')),
4161 ('', 'switch-parent', None, _('diff against the second parent')),
4171 ('', 'switch-parent', None, _('diff against the second parent')),
4162 ('r', 'rev', [],
4172 ('r', 'rev', [],
4163 _('revisions to export'), _('REV')),
4173 _('revisions to export'), _('REV')),
4164 ] + diffopts,
4174 ] + diffopts,
4165 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4175 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4166 "^forget":
4176 "^forget":
4167 (forget,
4177 (forget,
4168 [] + walkopts,
4178 [] + walkopts,
4169 _('[OPTION]... FILE...')),
4179 _('[OPTION]... FILE...')),
4170 "grep":
4180 "grep":
4171 (grep,
4181 (grep,
4172 [('0', 'print0', None, _('end fields with NUL')),
4182 [('0', 'print0', None, _('end fields with NUL')),
4173 ('', 'all', None, _('print all revisions that match')),
4183 ('', 'all', None, _('print all revisions that match')),
4174 ('f', 'follow', None,
4184 ('f', 'follow', None,
4175 _('follow changeset history,'
4185 _('follow changeset history,'
4176 ' or file history across copies and renames')),
4186 ' or file history across copies and renames')),
4177 ('i', 'ignore-case', None, _('ignore case when matching')),
4187 ('i', 'ignore-case', None, _('ignore case when matching')),
4178 ('l', 'files-with-matches', None,
4188 ('l', 'files-with-matches', None,
4179 _('print only filenames and revisions that match')),
4189 _('print only filenames and revisions that match')),
4180 ('n', 'line-number', None, _('print matching line numbers')),
4190 ('n', 'line-number', None, _('print matching line numbers')),
4181 ('r', 'rev', [],
4191 ('r', 'rev', [],
4182 _('only search files changed within revision range'), _('REV')),
4192 _('only search files changed within revision range'), _('REV')),
4183 ('u', 'user', None, _('list the author (long with -v)')),
4193 ('u', 'user', None, _('list the author (long with -v)')),
4184 ('d', 'date', None, _('list the date (short with -q)')),
4194 ('d', 'date', None, _('list the date (short with -q)')),
4185 ] + walkopts,
4195 ] + walkopts,
4186 _('[OPTION]... PATTERN [FILE]...')),
4196 _('[OPTION]... PATTERN [FILE]...')),
4187 "heads":
4197 "heads":
4188 (heads,
4198 (heads,
4189 [('r', 'rev', '',
4199 [('r', 'rev', '',
4190 _('show only heads which are descendants of STARTREV'),
4200 _('show only heads which are descendants of STARTREV'),
4191 _('STARTREV')),
4201 _('STARTREV')),
4192 ('t', 'topo', False, _('show topological heads only')),
4202 ('t', 'topo', False, _('show topological heads only')),
4193 ('a', 'active', False,
4203 ('a', 'active', False,
4194 _('show active branchheads only (DEPRECATED)')),
4204 _('show active branchheads only (DEPRECATED)')),
4195 ('c', 'closed', False,
4205 ('c', 'closed', False,
4196 _('show normal and closed branch heads')),
4206 _('show normal and closed branch heads')),
4197 ] + templateopts,
4207 ] + templateopts,
4198 _('[-ac] [-r STARTREV] [REV]...')),
4208 _('[-ac] [-r STARTREV] [REV]...')),
4199 "help": (help_, [], _('[TOPIC]')),
4209 "help": (help_, [], _('[TOPIC]')),
4200 "identify|id":
4210 "identify|id":
4201 (identify,
4211 (identify,
4202 [('r', 'rev', '',
4212 [('r', 'rev', '',
4203 _('identify the specified revision'), _('REV')),
4213 _('identify the specified revision'), _('REV')),
4204 ('n', 'num', None, _('show local revision number')),
4214 ('n', 'num', None, _('show local revision number')),
4205 ('i', 'id', None, _('show global revision id')),
4215 ('i', 'id', None, _('show global revision id')),
4206 ('b', 'branch', None, _('show branch')),
4216 ('b', 'branch', None, _('show branch')),
4207 ('t', 'tags', None, _('show tags'))],
4217 ('t', 'tags', None, _('show tags'))],
4208 _('[-nibt] [-r REV] [SOURCE]')),
4218 _('[-nibt] [-r REV] [SOURCE]')),
4209 "import|patch":
4219 "import|patch":
4210 (import_,
4220 (import_,
4211 [('p', 'strip', 1,
4221 [('p', 'strip', 1,
4212 _('directory strip option for patch. This has the same '
4222 _('directory strip option for patch. This has the same '
4213 'meaning as the corresponding patch option'),
4223 'meaning as the corresponding patch option'),
4214 _('NUM')),
4224 _('NUM')),
4215 ('b', 'base', '',
4225 ('b', 'base', '',
4216 _('base path'), _('PATH')),
4226 _('base path'), _('PATH')),
4217 ('f', 'force', None,
4227 ('f', 'force', None,
4218 _('skip check for outstanding uncommitted changes')),
4228 _('skip check for outstanding uncommitted changes')),
4219 ('', 'no-commit', None,
4229 ('', 'no-commit', None,
4220 _("don't commit, just update the working directory")),
4230 _("don't commit, just update the working directory")),
4221 ('', 'exact', None,
4231 ('', 'exact', None,
4222 _('apply patch to the nodes from which it was generated')),
4232 _('apply patch to the nodes from which it was generated')),
4223 ('', 'import-branch', None,
4233 ('', 'import-branch', None,
4224 _('use any branch information in patch (implied by --exact)'))] +
4234 _('use any branch information in patch (implied by --exact)'))] +
4225 commitopts + commitopts2 + similarityopts,
4235 commitopts + commitopts2 + similarityopts,
4226 _('[OPTION]... PATCH...')),
4236 _('[OPTION]... PATCH...')),
4227 "incoming|in":
4237 "incoming|in":
4228 (incoming,
4238 (incoming,
4229 [('f', 'force', None,
4239 [('f', 'force', None,
4230 _('run even if remote repository is unrelated')),
4240 _('run even if remote repository is unrelated')),
4231 ('n', 'newest-first', None, _('show newest record first')),
4241 ('n', 'newest-first', None, _('show newest record first')),
4232 ('', 'bundle', '',
4242 ('', 'bundle', '',
4233 _('file to store the bundles into'), _('FILE')),
4243 _('file to store the bundles into'), _('FILE')),
4234 ('r', 'rev', [],
4244 ('r', 'rev', [],
4235 _('a remote changeset intended to be added'), _('REV')),
4245 _('a remote changeset intended to be added'), _('REV')),
4236 ('b', 'branch', [],
4246 ('b', 'branch', [],
4237 _('a specific branch you would like to pull'), _('BRANCH')),
4247 _('a specific branch you would like to pull'), _('BRANCH')),
4238 ] + logopts + remoteopts + subrepoopts,
4248 ] + logopts + remoteopts + subrepoopts,
4239 _('[-p] [-n] [-M] [-f] [-r REV]...'
4249 _('[-p] [-n] [-M] [-f] [-r REV]...'
4240 ' [--bundle FILENAME] [SOURCE]')),
4250 ' [--bundle FILENAME] [SOURCE]')),
4241 "^init":
4251 "^init":
4242 (init,
4252 (init,
4243 remoteopts,
4253 remoteopts,
4244 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4254 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4245 "locate":
4255 "locate":
4246 (locate,
4256 (locate,
4247 [('r', 'rev', '',
4257 [('r', 'rev', '',
4248 _('search the repository as it is in REV'), _('REV')),
4258 _('search the repository as it is in REV'), _('REV')),
4249 ('0', 'print0', None,
4259 ('0', 'print0', None,
4250 _('end filenames with NUL, for use with xargs')),
4260 _('end filenames with NUL, for use with xargs')),
4251 ('f', 'fullpath', None,
4261 ('f', 'fullpath', None,
4252 _('print complete paths from the filesystem root')),
4262 _('print complete paths from the filesystem root')),
4253 ] + walkopts,
4263 ] + walkopts,
4254 _('[OPTION]... [PATTERN]...')),
4264 _('[OPTION]... [PATTERN]...')),
4255 "^log|history":
4265 "^log|history":
4256 (log,
4266 (log,
4257 [('f', 'follow', None,
4267 [('f', 'follow', None,
4258 _('follow changeset history,'
4268 _('follow changeset history,'
4259 ' or file history across copies and renames')),
4269 ' or file history across copies and renames')),
4260 ('', 'follow-first', None,
4270 ('', 'follow-first', None,
4261 _('only follow the first parent of merge changesets')),
4271 _('only follow the first parent of merge changesets')),
4262 ('d', 'date', '',
4272 ('d', 'date', '',
4263 _('show revisions matching date spec'), _('DATE')),
4273 _('show revisions matching date spec'), _('DATE')),
4264 ('C', 'copies', None, _('show copied files')),
4274 ('C', 'copies', None, _('show copied files')),
4265 ('k', 'keyword', [],
4275 ('k', 'keyword', [],
4266 _('do case-insensitive search for a given text'), _('TEXT')),
4276 _('do case-insensitive search for a given text'), _('TEXT')),
4267 ('r', 'rev', [],
4277 ('r', 'rev', [],
4268 _('show the specified revision or range'), _('REV')),
4278 _('show the specified revision or range'), _('REV')),
4269 ('', 'removed', None, _('include revisions where files were removed')),
4279 ('', 'removed', None, _('include revisions where files were removed')),
4270 ('m', 'only-merges', None, _('show only merges')),
4280 ('m', 'only-merges', None, _('show only merges')),
4271 ('u', 'user', [],
4281 ('u', 'user', [],
4272 _('revisions committed by user'), _('USER')),
4282 _('revisions committed by user'), _('USER')),
4273 ('', 'only-branch', [],
4283 ('', 'only-branch', [],
4274 _('show only changesets within the given named branch (DEPRECATED)'),
4284 _('show only changesets within the given named branch (DEPRECATED)'),
4275 _('BRANCH')),
4285 _('BRANCH')),
4276 ('b', 'branch', [],
4286 ('b', 'branch', [],
4277 _('show changesets within the given named branch'), _('BRANCH')),
4287 _('show changesets within the given named branch'), _('BRANCH')),
4278 ('P', 'prune', [],
4288 ('P', 'prune', [],
4279 _('do not display revision or any of its ancestors'), _('REV')),
4289 _('do not display revision or any of its ancestors'), _('REV')),
4280 ] + logopts + walkopts,
4290 ] + logopts + walkopts,
4281 _('[OPTION]... [FILE]')),
4291 _('[OPTION]... [FILE]')),
4282 "manifest":
4292 "manifest":
4283 (manifest,
4293 (manifest,
4284 [('r', 'rev', '',
4294 [('r', 'rev', '',
4285 _('revision to display'), _('REV'))],
4295 _('revision to display'), _('REV'))],
4286 _('[-r REV]')),
4296 _('[-r REV]')),
4287 "^merge":
4297 "^merge":
4288 (merge,
4298 (merge,
4289 [('f', 'force', None, _('force a merge with outstanding changes')),
4299 [('f', 'force', None, _('force a merge with outstanding changes')),
4290 ('t', 'tool', '', _('specify merge tool')),
4300 ('t', 'tool', '', _('specify merge tool')),
4291 ('r', 'rev', '',
4301 ('r', 'rev', '',
4292 _('revision to merge'), _('REV')),
4302 _('revision to merge'), _('REV')),
4293 ('P', 'preview', None,
4303 ('P', 'preview', None,
4294 _('review revisions to merge (no merge is performed)'))],
4304 _('review revisions to merge (no merge is performed)'))],
4295 _('[-P] [-f] [[-r] REV]')),
4305 _('[-P] [-f] [[-r] REV]')),
4296 "outgoing|out":
4306 "outgoing|out":
4297 (outgoing,
4307 (outgoing,
4298 [('f', 'force', None,
4308 [('f', 'force', None,
4299 _('run even when the destination is unrelated')),
4309 _('run even when the destination is unrelated')),
4300 ('r', 'rev', [],
4310 ('r', 'rev', [],
4301 _('a changeset intended to be included in the destination'),
4311 _('a changeset intended to be included in the destination'),
4302 _('REV')),
4312 _('REV')),
4303 ('n', 'newest-first', None, _('show newest record first')),
4313 ('n', 'newest-first', None, _('show newest record first')),
4304 ('b', 'branch', [],
4314 ('b', 'branch', [],
4305 _('a specific branch you would like to push'), _('BRANCH')),
4315 _('a specific branch you would like to push'), _('BRANCH')),
4306 ] + logopts + remoteopts + subrepoopts,
4316 ] + logopts + remoteopts + subrepoopts,
4307 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4317 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4308 "parents":
4318 "parents":
4309 (parents,
4319 (parents,
4310 [('r', 'rev', '',
4320 [('r', 'rev', '',
4311 _('show parents of the specified revision'), _('REV')),
4321 _('show parents of the specified revision'), _('REV')),
4312 ] + templateopts,
4322 ] + templateopts,
4313 _('[-r REV] [FILE]')),
4323 _('[-r REV] [FILE]')),
4314 "paths": (paths, [], _('[NAME]')),
4324 "paths": (paths, [], _('[NAME]')),
4315 "^pull":
4325 "^pull":
4316 (pull,
4326 (pull,
4317 [('u', 'update', None,
4327 [('u', 'update', None,
4318 _('update to new branch head if changesets were pulled')),
4328 _('update to new branch head if changesets were pulled')),
4319 ('f', 'force', None,
4329 ('f', 'force', None,
4320 _('run even when remote repository is unrelated')),
4330 _('run even when remote repository is unrelated')),
4321 ('r', 'rev', [],
4331 ('r', 'rev', [],
4322 _('a remote changeset intended to be added'), _('REV')),
4332 _('a remote changeset intended to be added'), _('REV')),
4323 ('b', 'branch', [],
4333 ('b', 'branch', [],
4324 _('a specific branch you would like to pull'), _('BRANCH')),
4334 _('a specific branch you would like to pull'), _('BRANCH')),
4325 ] + remoteopts,
4335 ] + remoteopts,
4326 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4336 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4327 "^push":
4337 "^push":
4328 (push,
4338 (push,
4329 [('f', 'force', None, _('force push')),
4339 [('f', 'force', None, _('force push')),
4330 ('r', 'rev', [],
4340 ('r', 'rev', [],
4331 _('a changeset intended to be included in the destination'),
4341 _('a changeset intended to be included in the destination'),
4332 _('REV')),
4342 _('REV')),
4333 ('b', 'branch', [],
4343 ('b', 'branch', [],
4334 _('a specific branch you would like to push'), _('BRANCH')),
4344 _('a specific branch you would like to push'), _('BRANCH')),
4335 ('', 'new-branch', False, _('allow pushing a new branch')),
4345 ('', 'new-branch', False, _('allow pushing a new branch')),
4336 ] + remoteopts,
4346 ] + remoteopts,
4337 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4347 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4338 "recover": (recover, []),
4348 "recover": (recover, []),
4339 "^remove|rm":
4349 "^remove|rm":
4340 (remove,
4350 (remove,
4341 [('A', 'after', None, _('record delete for missing files')),
4351 [('A', 'after', None, _('record delete for missing files')),
4342 ('f', 'force', None,
4352 ('f', 'force', None,
4343 _('remove (and delete) file even if added or modified')),
4353 _('remove (and delete) file even if added or modified')),
4344 ] + walkopts,
4354 ] + walkopts,
4345 _('[OPTION]... FILE...')),
4355 _('[OPTION]... FILE...')),
4346 "rename|move|mv":
4356 "rename|move|mv":
4347 (rename,
4357 (rename,
4348 [('A', 'after', None, _('record a rename that has already occurred')),
4358 [('A', 'after', None, _('record a rename that has already occurred')),
4349 ('f', 'force', None,
4359 ('f', 'force', None,
4350 _('forcibly copy over an existing managed file')),
4360 _('forcibly copy over an existing managed file')),
4351 ] + walkopts + dryrunopts,
4361 ] + walkopts + dryrunopts,
4352 _('[OPTION]... SOURCE... DEST')),
4362 _('[OPTION]... SOURCE... DEST')),
4353 "resolve":
4363 "resolve":
4354 (resolve,
4364 (resolve,
4355 [('a', 'all', None, _('select all unresolved files')),
4365 [('a', 'all', None, _('select all unresolved files')),
4356 ('l', 'list', None, _('list state of files needing merge')),
4366 ('l', 'list', None, _('list state of files needing merge')),
4357 ('m', 'mark', None, _('mark files as resolved')),
4367 ('m', 'mark', None, _('mark files as resolved')),
4358 ('u', 'unmark', None, _('mark files as unresolved')),
4368 ('u', 'unmark', None, _('mark files as unresolved')),
4359 ('t', 'tool', '', _('specify merge tool')),
4369 ('t', 'tool', '', _('specify merge tool')),
4360 ('n', 'no-status', None, _('hide status prefix'))]
4370 ('n', 'no-status', None, _('hide status prefix'))]
4361 + walkopts,
4371 + walkopts,
4362 _('[OPTION]... [FILE]...')),
4372 _('[OPTION]... [FILE]...')),
4363 "revert":
4373 "revert":
4364 (revert,
4374 (revert,
4365 [('a', 'all', None, _('revert all changes when no arguments given')),
4375 [('a', 'all', None, _('revert all changes when no arguments given')),
4366 ('d', 'date', '',
4376 ('d', 'date', '',
4367 _('tipmost revision matching date'), _('DATE')),
4377 _('tipmost revision matching date'), _('DATE')),
4368 ('r', 'rev', '',
4378 ('r', 'rev', '',
4369 _('revert to the specified revision'), _('REV')),
4379 _('revert to the specified revision'), _('REV')),
4370 ('', 'no-backup', None, _('do not save backup copies of files')),
4380 ('', 'no-backup', None, _('do not save backup copies of files')),
4371 ] + walkopts + dryrunopts,
4381 ] + walkopts + dryrunopts,
4372 _('[OPTION]... [-r REV] [NAME]...')),
4382 _('[OPTION]... [-r REV] [NAME]...')),
4373 "rollback": (rollback, dryrunopts),
4383 "rollback": (rollback, dryrunopts),
4374 "root": (root, []),
4384 "root": (root, []),
4375 "^serve":
4385 "^serve":
4376 (serve,
4386 (serve,
4377 [('A', 'accesslog', '',
4387 [('A', 'accesslog', '',
4378 _('name of access log file to write to'), _('FILE')),
4388 _('name of access log file to write to'), _('FILE')),
4379 ('d', 'daemon', None, _('run server in background')),
4389 ('d', 'daemon', None, _('run server in background')),
4380 ('', 'daemon-pipefds', '',
4390 ('', 'daemon-pipefds', '',
4381 _('used internally by daemon mode'), _('NUM')),
4391 _('used internally by daemon mode'), _('NUM')),
4382 ('E', 'errorlog', '',
4392 ('E', 'errorlog', '',
4383 _('name of error log file to write to'), _('FILE')),
4393 _('name of error log file to write to'), _('FILE')),
4384 # use string type, then we can check if something was passed
4394 # use string type, then we can check if something was passed
4385 ('p', 'port', '',
4395 ('p', 'port', '',
4386 _('port to listen on (default: 8000)'), _('PORT')),
4396 _('port to listen on (default: 8000)'), _('PORT')),
4387 ('a', 'address', '',
4397 ('a', 'address', '',
4388 _('address to listen on (default: all interfaces)'), _('ADDR')),
4398 _('address to listen on (default: all interfaces)'), _('ADDR')),
4389 ('', 'prefix', '',
4399 ('', 'prefix', '',
4390 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4400 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4391 ('n', 'name', '',
4401 ('n', 'name', '',
4392 _('name to show in web pages (default: working directory)'),
4402 _('name to show in web pages (default: working directory)'),
4393 _('NAME')),
4403 _('NAME')),
4394 ('', 'web-conf', '',
4404 ('', 'web-conf', '',
4395 _('name of the hgweb config file (see "hg help hgweb")'),
4405 _('name of the hgweb config file (see "hg help hgweb")'),
4396 _('FILE')),
4406 _('FILE')),
4397 ('', 'webdir-conf', '',
4407 ('', 'webdir-conf', '',
4398 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4408 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4399 ('', 'pid-file', '',
4409 ('', 'pid-file', '',
4400 _('name of file to write process ID to'), _('FILE')),
4410 _('name of file to write process ID to'), _('FILE')),
4401 ('', 'stdio', None, _('for remote clients')),
4411 ('', 'stdio', None, _('for remote clients')),
4402 ('t', 'templates', '',
4412 ('t', 'templates', '',
4403 _('web templates to use'), _('TEMPLATE')),
4413 _('web templates to use'), _('TEMPLATE')),
4404 ('', 'style', '',
4414 ('', 'style', '',
4405 _('template style to use'), _('STYLE')),
4415 _('template style to use'), _('STYLE')),
4406 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4416 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4407 ('', 'certificate', '',
4417 ('', 'certificate', '',
4408 _('SSL certificate file'), _('FILE'))],
4418 _('SSL certificate file'), _('FILE'))],
4409 _('[OPTION]...')),
4419 _('[OPTION]...')),
4410 "showconfig|debugconfig":
4420 "showconfig|debugconfig":
4411 (showconfig,
4421 (showconfig,
4412 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4422 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4413 _('[-u] [NAME]...')),
4423 _('[-u] [NAME]...')),
4414 "^summary|sum":
4424 "^summary|sum":
4415 (summary,
4425 (summary,
4416 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4426 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4417 "^status|st":
4427 "^status|st":
4418 (status,
4428 (status,
4419 [('A', 'all', None, _('show status of all files')),
4429 [('A', 'all', None, _('show status of all files')),
4420 ('m', 'modified', None, _('show only modified files')),
4430 ('m', 'modified', None, _('show only modified files')),
4421 ('a', 'added', None, _('show only added files')),
4431 ('a', 'added', None, _('show only added files')),
4422 ('r', 'removed', None, _('show only removed files')),
4432 ('r', 'removed', None, _('show only removed files')),
4423 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4433 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4424 ('c', 'clean', None, _('show only files without changes')),
4434 ('c', 'clean', None, _('show only files without changes')),
4425 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4435 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4426 ('i', 'ignored', None, _('show only ignored files')),
4436 ('i', 'ignored', None, _('show only ignored files')),
4427 ('n', 'no-status', None, _('hide status prefix')),
4437 ('n', 'no-status', None, _('hide status prefix')),
4428 ('C', 'copies', None, _('show source of copied files')),
4438 ('C', 'copies', None, _('show source of copied files')),
4429 ('0', 'print0', None,
4439 ('0', 'print0', None,
4430 _('end filenames with NUL, for use with xargs')),
4440 _('end filenames with NUL, for use with xargs')),
4431 ('', 'rev', [],
4441 ('', 'rev', [],
4432 _('show difference from revision'), _('REV')),
4442 _('show difference from revision'), _('REV')),
4433 ('', 'change', '',
4443 ('', 'change', '',
4434 _('list the changed files of a revision'), _('REV')),
4444 _('list the changed files of a revision'), _('REV')),
4435 ] + walkopts + subrepoopts,
4445 ] + walkopts + subrepoopts,
4436 _('[OPTION]... [FILE]...')),
4446 _('[OPTION]... [FILE]...')),
4437 "tag":
4447 "tag":
4438 (tag,
4448 (tag,
4439 [('f', 'force', None, _('replace existing tag')),
4449 [('f', 'force', None, _('replace existing tag')),
4440 ('l', 'local', None, _('make the tag local')),
4450 ('l', 'local', None, _('make the tag local')),
4441 ('r', 'rev', '',
4451 ('r', 'rev', '',
4442 _('revision to tag'), _('REV')),
4452 _('revision to tag'), _('REV')),
4443 ('', 'remove', None, _('remove a tag')),
4453 ('', 'remove', None, _('remove a tag')),
4444 # -l/--local is already there, commitopts cannot be used
4454 # -l/--local is already there, commitopts cannot be used
4445 ('e', 'edit', None, _('edit commit message')),
4455 ('e', 'edit', None, _('edit commit message')),
4446 ('m', 'message', '',
4456 ('m', 'message', '',
4447 _('use <text> as commit message'), _('TEXT')),
4457 _('use <text> as commit message'), _('TEXT')),
4448 ] + commitopts2,
4458 ] + commitopts2,
4449 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4459 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4450 "tags": (tags, [], ''),
4460 "tags": (tags, [], ''),
4451 "tip":
4461 "tip":
4452 (tip,
4462 (tip,
4453 [('p', 'patch', None, _('show patch')),
4463 [('p', 'patch', None, _('show patch')),
4454 ('g', 'git', None, _('use git extended diff format')),
4464 ('g', 'git', None, _('use git extended diff format')),
4455 ] + templateopts,
4465 ] + templateopts,
4456 _('[-p] [-g]')),
4466 _('[-p] [-g]')),
4457 "unbundle":
4467 "unbundle":
4458 (unbundle,
4468 (unbundle,
4459 [('u', 'update', None,
4469 [('u', 'update', None,
4460 _('update to new branch head if changesets were unbundled'))],
4470 _('update to new branch head if changesets were unbundled'))],
4461 _('[-u] FILE...')),
4471 _('[-u] FILE...')),
4462 "^update|up|checkout|co":
4472 "^update|up|checkout|co":
4463 (update,
4473 (update,
4464 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4474 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4465 ('c', 'check', None,
4475 ('c', 'check', None,
4466 _('update across branches if no uncommitted changes')),
4476 _('update across branches if no uncommitted changes')),
4467 ('d', 'date', '',
4477 ('d', 'date', '',
4468 _('tipmost revision matching date'), _('DATE')),
4478 _('tipmost revision matching date'), _('DATE')),
4469 ('r', 'rev', '',
4479 ('r', 'rev', '',
4470 _('revision'), _('REV'))],
4480 _('revision'), _('REV'))],
4471 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4481 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4472 "verify": (verify, []),
4482 "verify": (verify, []),
4473 "version": (version_, []),
4483 "version": (version_, []),
4474 }
4484 }
4475
4485
4476 norepo = ("clone init version help debugcommands debugcomplete"
4486 norepo = ("clone init version help debugcommands debugcomplete"
4477 " debugdate debuginstall debugfsinfo debugpushkey")
4487 " debugdate debuginstall debugfsinfo debugpushkey")
4478 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4488 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4479 " debugdata debugindex debugindexdot")
4489 " debugdata debugindex debugindexdot")
@@ -1,160 +1,160 b''
1 # demandimport.py - global demand-loading of modules for Mercurial
1 # demandimport.py - global demand-loading of modules for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 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 '''
8 '''
9 demandimport - automatic demandloading of modules
9 demandimport - automatic demandloading of modules
10
10
11 To enable this module, do:
11 To enable this module, do:
12
12
13 import demandimport; demandimport.enable()
13 import demandimport; demandimport.enable()
14
14
15 Imports of the following forms will be demand-loaded:
15 Imports of the following forms will be demand-loaded:
16
16
17 import a, b.c
17 import a, b.c
18 import a.b as c
18 import a.b as c
19 from a import b,c # a will be loaded immediately
19 from a import b,c # a will be loaded immediately
20
20
21 These imports will not be delayed:
21 These imports will not be delayed:
22
22
23 from a import *
23 from a import *
24 b = __import__(a)
24 b = __import__(a)
25 '''
25 '''
26
26
27 import __builtin__
27 import __builtin__
28 _origimport = __import__
28 _origimport = __import__
29
29
30 class _demandmod(object):
30 class _demandmod(object):
31 """module demand-loader and proxy"""
31 """module demand-loader and proxy"""
32 def __init__(self, name, globals, locals, level):
32 def __init__(self, name, globals, locals, level):
33 if '.' in name:
33 if '.' in name:
34 head, rest = name.split('.', 1)
34 head, rest = name.split('.', 1)
35 after = [rest]
35 after = [rest]
36 else:
36 else:
37 head = name
37 head = name
38 after = []
38 after = []
39 object.__setattr__(self, "_data", (head, globals, locals, after, level))
39 object.__setattr__(self, "_data", (head, globals, locals, after, level))
40 object.__setattr__(self, "_module", None)
40 object.__setattr__(self, "_module", None)
41 def _extend(self, name):
41 def _extend(self, name):
42 """add to the list of submodules to load"""
42 """add to the list of submodules to load"""
43 self._data[3].append(name)
43 self._data[3].append(name)
44 def _load(self):
44 def _load(self):
45 if not self._module:
45 if not self._module:
46 head, globals, locals, after, level = self._data
46 head, globals, locals, after, level = self._data
47 if level is not None:
47 if level is not None:
48 mod = _origimport(head, globals, locals, level=level)
48 mod = _origimport(head, globals, locals, level)
49 else:
49 else:
50 mod = _origimport(head, globals, locals)
50 mod = _origimport(head, globals, locals)
51 # load submodules
51 # load submodules
52 def subload(mod, p):
52 def subload(mod, p):
53 h, t = p, None
53 h, t = p, None
54 if '.' in p:
54 if '.' in p:
55 h, t = p.split('.', 1)
55 h, t = p.split('.', 1)
56 if not hasattr(mod, h):
56 if not hasattr(mod, h):
57 # TODO: should we adjust the level here?
57 # TODO: should we adjust the level here?
58 submod = _demandmod(p, mod.__dict__, mod.__dict__,
58 submod = _demandmod(p, mod.__dict__, mod.__dict__,
59 level=level)
59 level=level)
60 setattr(mod, h, submod)
60 setattr(mod, h, submod)
61 elif t:
61 elif t:
62 subload(getattr(mod, h), t)
62 subload(getattr(mod, h), t)
63
63
64 for x in after:
64 for x in after:
65 subload(mod, x)
65 subload(mod, x)
66
66
67 # are we in the locals dictionary still?
67 # are we in the locals dictionary still?
68 if locals and locals.get(head) == self:
68 if locals and locals.get(head) == self:
69 locals[head] = mod
69 locals[head] = mod
70 object.__setattr__(self, "_module", mod)
70 object.__setattr__(self, "_module", mod)
71
71
72 def __repr__(self):
72 def __repr__(self):
73 if self._module:
73 if self._module:
74 return "<proxied module '%s'>" % self._data[0]
74 return "<proxied module '%s'>" % self._data[0]
75 return "<unloaded module '%s'>" % self._data[0]
75 return "<unloaded module '%s'>" % self._data[0]
76 def __call__(self, *args, **kwargs):
76 def __call__(self, *args, **kwargs):
77 raise TypeError("%s object is not callable" % repr(self))
77 raise TypeError("%s object is not callable" % repr(self))
78 def __getattribute__(self, attr):
78 def __getattribute__(self, attr):
79 if attr in ('_data', '_extend', '_load', '_module'):
79 if attr in ('_data', '_extend', '_load', '_module'):
80 return object.__getattribute__(self, attr)
80 return object.__getattribute__(self, attr)
81 self._load()
81 self._load()
82 return getattr(self._module, attr)
82 return getattr(self._module, attr)
83 def __setattr__(self, attr, val):
83 def __setattr__(self, attr, val):
84 self._load()
84 self._load()
85 setattr(self._module, attr, val)
85 setattr(self._module, attr, val)
86
86
87 def _demandimport(name, globals=None, locals=None, fromlist=None, level=None):
87 def _demandimport(name, globals=None, locals=None, fromlist=None, level=None):
88 if not locals or name in ignore or fromlist == ('*',):
88 if not locals or name in ignore or fromlist == ('*',):
89 # these cases we can't really delay
89 # these cases we can't really delay
90 if level is None:
90 if level is None:
91 return _origimport(name, globals, locals, fromlist)
91 return _origimport(name, globals, locals, fromlist)
92 else:
92 else:
93 return _origimport(name, globals, locals, fromlist, level)
93 return _origimport(name, globals, locals, fromlist, level)
94 elif not fromlist:
94 elif not fromlist:
95 # import a [as b]
95 # import a [as b]
96 if '.' in name: # a.b
96 if '.' in name: # a.b
97 base, rest = name.split('.', 1)
97 base, rest = name.split('.', 1)
98 # email.__init__ loading email.mime
98 # email.__init__ loading email.mime
99 if globals and globals.get('__name__', None) == base:
99 if globals and globals.get('__name__', None) == base:
100 if level is not None:
100 if level is not None:
101 return _origimport(name, globals, locals, fromlist, level)
101 return _origimport(name, globals, locals, fromlist, level)
102 else:
102 else:
103 return _origimport(name, globals, locals, fromlist)
103 return _origimport(name, globals, locals, fromlist)
104 # if a is already demand-loaded, add b to its submodule list
104 # if a is already demand-loaded, add b to its submodule list
105 if base in locals:
105 if base in locals:
106 if isinstance(locals[base], _demandmod):
106 if isinstance(locals[base], _demandmod):
107 locals[base]._extend(rest)
107 locals[base]._extend(rest)
108 return locals[base]
108 return locals[base]
109 return _demandmod(name, globals, locals, level=level)
109 return _demandmod(name, globals, locals, level=level)
110 else:
110 else:
111 # from a import b,c,d
111 # from a import b,c,d
112 if level is not None:
112 if level is not None:
113 mod = _origimport(name, globals, locals, level=level)
113 mod = _origimport(name, globals, locals, level=level)
114 else:
114 else:
115 mod = _origimport(name, globals, locals)
115 mod = _origimport(name, globals, locals)
116 # recurse down the module chain
116 # recurse down the module chain
117 for comp in name.split('.')[1:]:
117 for comp in name.split('.')[1:]:
118 if not hasattr(mod, comp):
118 if not hasattr(mod, comp):
119 # TODO: should we adjust the level here?
119 # TODO: should we adjust the level here?
120 submod = _demandmod(comp, mod.__dict__, mod.__dict__,
120 submod = _demandmod(comp, mod.__dict__, mod.__dict__,
121 level=level)
121 level=level)
122 setattr(mod, comp, submod)
122 setattr(mod, comp, submod)
123 mod = getattr(mod, comp)
123 mod = getattr(mod, comp)
124 for x in fromlist:
124 for x in fromlist:
125 # set requested submodules for demand load
125 # set requested submodules for demand load
126 if not(hasattr(mod, x)):
126 if not(hasattr(mod, x)):
127 # TODO: should we adjust the level here?
127 # TODO: should we adjust the level here?
128 submod = _demandmod(x, mod.__dict__, locals, level=level)
128 submod = _demandmod(x, mod.__dict__, locals, level=level)
129 setattr(mod, x, submod)
129 setattr(mod, x, submod)
130 return mod
130 return mod
131
131
132 ignore = [
132 ignore = [
133 '_hashlib',
133 '_hashlib',
134 '_xmlplus',
134 '_xmlplus',
135 'fcntl',
135 'fcntl',
136 'win32com.gen_py',
136 'win32com.gen_py',
137 '_winreg', # 2.7 mimetypes needs immediate ImportError
137 '_winreg', # 2.7 mimetypes needs immediate ImportError
138 'pythoncom',
138 'pythoncom',
139 # imported by tarfile, not available under Windows
139 # imported by tarfile, not available under Windows
140 'pwd',
140 'pwd',
141 'grp',
141 'grp',
142 # imported by profile, itself imported by hotshot.stats,
142 # imported by profile, itself imported by hotshot.stats,
143 # not available under Windows
143 # not available under Windows
144 'resource',
144 'resource',
145 # this trips up many extension authors
145 # this trips up many extension authors
146 'gtk',
146 'gtk',
147 # setuptools' pkg_resources.py expects "from __main__ import x" to
147 # setuptools' pkg_resources.py expects "from __main__ import x" to
148 # raise ImportError if x not defined
148 # raise ImportError if x not defined
149 '__main__',
149 '__main__',
150 '_ssl', # conditional imports in the stdlib, issue1964
150 '_ssl', # conditional imports in the stdlib, issue1964
151 ]
151 ]
152
152
153 def enable():
153 def enable():
154 "enable global demand-loading of modules"
154 "enable global demand-loading of modules"
155 __builtin__.__import__ = _demandimport
155 __builtin__.__import__ = _demandimport
156
156
157 def disable():
157 def disable():
158 "disable global demand-loading of modules"
158 "disable global demand-loading of modules"
159 __builtin__.__import__ = _origimport
159 __builtin__.__import__ = _origimport
160
160
@@ -1,642 +1,642 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 def run():
14 def run():
15 "run the command in sys.argv"
15 "run the command in sys.argv"
16 sys.exit(dispatch(sys.argv[1:]))
16 sys.exit(dispatch(sys.argv[1:]))
17
17
18 def dispatch(args):
18 def dispatch(args):
19 "run the command specified in args"
19 "run the command specified in args"
20 try:
20 try:
21 u = uimod.ui()
21 u = uimod.ui()
22 if '--traceback' in args:
22 if '--traceback' in args:
23 u.setconfig('ui', 'traceback', 'on')
23 u.setconfig('ui', 'traceback', 'on')
24 except util.Abort, inst:
24 except util.Abort, inst:
25 sys.stderr.write(_("abort: %s\n") % inst)
25 sys.stderr.write(_("abort: %s\n") % inst)
26 if inst.hint:
26 if inst.hint:
27 sys.stderr.write("(%s)\n" % inst.hint)
27 sys.stderr.write(_("(%s)\n") % inst.hint)
28 return -1
28 return -1
29 except error.ParseError, inst:
29 except error.ParseError, inst:
30 if len(inst.args) > 1:
30 if len(inst.args) > 1:
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
32 (inst.args[1], inst.args[0]))
32 (inst.args[1], inst.args[0]))
33 else:
33 else:
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
35 return -1
35 return -1
36 return _runcatch(u, args)
36 return _runcatch(u, args)
37
37
38 def _runcatch(ui, args):
38 def _runcatch(ui, args):
39 def catchterm(*args):
39 def catchterm(*args):
40 raise error.SignalInterrupt
40 raise error.SignalInterrupt
41
41
42 try:
42 try:
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
44 num = getattr(signal, name, None)
44 num = getattr(signal, name, None)
45 if num:
45 if num:
46 signal.signal(num, catchterm)
46 signal.signal(num, catchterm)
47 except ValueError:
47 except ValueError:
48 pass # happens if called in a thread
48 pass # happens if called in a thread
49
49
50 try:
50 try:
51 try:
51 try:
52 # enter the debugger before command execution
52 # enter the debugger before command execution
53 if '--debugger' in args:
53 if '--debugger' in args:
54 ui.warn(_("entering debugger - "
54 ui.warn(_("entering debugger - "
55 "type c to continue starting hg or h for help\n"))
55 "type c to continue starting hg or h for help\n"))
56 pdb.set_trace()
56 pdb.set_trace()
57 try:
57 try:
58 return _dispatch(ui, args)
58 return _dispatch(ui, args)
59 finally:
59 finally:
60 ui.flush()
60 ui.flush()
61 except:
61 except:
62 # enter the debugger when we hit an exception
62 # enter the debugger when we hit an exception
63 if '--debugger' in args:
63 if '--debugger' in args:
64 traceback.print_exc()
64 traceback.print_exc()
65 pdb.post_mortem(sys.exc_info()[2])
65 pdb.post_mortem(sys.exc_info()[2])
66 ui.traceback()
66 ui.traceback()
67 raise
67 raise
68
68
69 # Global exception handling, alphabetically
69 # Global exception handling, alphabetically
70 # Mercurial-specific first, followed by built-in and library exceptions
70 # Mercurial-specific first, followed by built-in and library exceptions
71 except error.AmbiguousCommand, inst:
71 except error.AmbiguousCommand, inst:
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
73 (inst.args[0], " ".join(inst.args[1])))
73 (inst.args[0], " ".join(inst.args[1])))
74 except error.ParseError, inst:
74 except error.ParseError, inst:
75 if len(inst.args) > 1:
75 if len(inst.args) > 1:
76 ui.warn(_("hg: parse error at %s: %s\n") %
76 ui.warn(_("hg: parse error at %s: %s\n") %
77 (inst.args[1], inst.args[0]))
77 (inst.args[1], inst.args[0]))
78 else:
78 else:
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
80 return -1
80 return -1
81 except error.LockHeld, inst:
81 except error.LockHeld, inst:
82 if inst.errno == errno.ETIMEDOUT:
82 if inst.errno == errno.ETIMEDOUT:
83 reason = _('timed out waiting for lock held by %s') % inst.locker
83 reason = _('timed out waiting for lock held by %s') % inst.locker
84 else:
84 else:
85 reason = _('lock held by %s') % inst.locker
85 reason = _('lock held by %s') % inst.locker
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
87 except error.LockUnavailable, inst:
87 except error.LockUnavailable, inst:
88 ui.warn(_("abort: could not lock %s: %s\n") %
88 ui.warn(_("abort: could not lock %s: %s\n") %
89 (inst.desc or inst.filename, inst.strerror))
89 (inst.desc or inst.filename, inst.strerror))
90 except error.CommandError, inst:
90 except error.CommandError, inst:
91 if inst.args[0]:
91 if inst.args[0]:
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
93 commands.help_(ui, inst.args[0])
93 commands.help_(ui, inst.args[0])
94 else:
94 else:
95 ui.warn(_("hg: %s\n") % inst.args[1])
95 ui.warn(_("hg: %s\n") % inst.args[1])
96 commands.help_(ui, 'shortlist')
96 commands.help_(ui, 'shortlist')
97 except error.RepoError, inst:
97 except error.RepoError, inst:
98 ui.warn(_("abort: %s!\n") % inst)
98 ui.warn(_("abort: %s!\n") % inst)
99 except error.ResponseError, inst:
99 except error.ResponseError, inst:
100 ui.warn(_("abort: %s") % inst.args[0])
100 ui.warn(_("abort: %s") % inst.args[0])
101 if not isinstance(inst.args[1], basestring):
101 if not isinstance(inst.args[1], basestring):
102 ui.warn(" %r\n" % (inst.args[1],))
102 ui.warn(" %r\n" % (inst.args[1],))
103 elif not inst.args[1]:
103 elif not inst.args[1]:
104 ui.warn(_(" empty string\n"))
104 ui.warn(_(" empty string\n"))
105 else:
105 else:
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
107 except error.RevlogError, inst:
107 except error.RevlogError, inst:
108 ui.warn(_("abort: %s!\n") % inst)
108 ui.warn(_("abort: %s!\n") % inst)
109 except error.SignalInterrupt:
109 except error.SignalInterrupt:
110 ui.warn(_("killed!\n"))
110 ui.warn(_("killed!\n"))
111 except error.UnknownCommand, inst:
111 except error.UnknownCommand, inst:
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
113 try:
113 try:
114 # check if the command is in a disabled extension
114 # check if the command is in a disabled extension
115 # (but don't check for extensions themselves)
115 # (but don't check for extensions themselves)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
117 except error.UnknownCommand:
117 except error.UnknownCommand:
118 commands.help_(ui, 'shortlist')
118 commands.help_(ui, 'shortlist')
119 except util.Abort, inst:
119 except util.Abort, inst:
120 ui.warn(_("abort: %s\n") % inst)
120 ui.warn(_("abort: %s\n") % inst)
121 if inst.hint:
121 if inst.hint:
122 ui.warn(_("(%s)\n") % inst.hint)
122 ui.warn(_("(%s)\n") % inst.hint)
123 except ImportError, inst:
123 except ImportError, inst:
124 ui.warn(_("abort: %s!\n") % inst)
124 ui.warn(_("abort: %s!\n") % inst)
125 m = str(inst).split()[-1]
125 m = str(inst).split()[-1]
126 if m in "mpatch bdiff".split():
126 if m in "mpatch bdiff".split():
127 ui.warn(_("(did you forget to compile extensions?)\n"))
127 ui.warn(_("(did you forget to compile extensions?)\n"))
128 elif m in "zlib".split():
128 elif m in "zlib".split():
129 ui.warn(_("(is your Python install correct?)\n"))
129 ui.warn(_("(is your Python install correct?)\n"))
130 except IOError, inst:
130 except IOError, inst:
131 if hasattr(inst, "code"):
131 if hasattr(inst, "code"):
132 ui.warn(_("abort: %s\n") % inst)
132 ui.warn(_("abort: %s\n") % inst)
133 elif hasattr(inst, "reason"):
133 elif hasattr(inst, "reason"):
134 try: # usually it is in the form (errno, strerror)
134 try: # usually it is in the form (errno, strerror)
135 reason = inst.reason.args[1]
135 reason = inst.reason.args[1]
136 except: # it might be anything, for example a string
136 except: # it might be anything, for example a string
137 reason = inst.reason
137 reason = inst.reason
138 ui.warn(_("abort: error: %s\n") % reason)
138 ui.warn(_("abort: error: %s\n") % reason)
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
140 if ui.debugflag:
140 if ui.debugflag:
141 ui.warn(_("broken pipe\n"))
141 ui.warn(_("broken pipe\n"))
142 elif getattr(inst, "strerror", None):
142 elif getattr(inst, "strerror", None):
143 if getattr(inst, "filename", None):
143 if getattr(inst, "filename", None):
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
145 else:
145 else:
146 ui.warn(_("abort: %s\n") % inst.strerror)
146 ui.warn(_("abort: %s\n") % inst.strerror)
147 else:
147 else:
148 raise
148 raise
149 except OSError, inst:
149 except OSError, inst:
150 if getattr(inst, "filename", None):
150 if getattr(inst, "filename", None):
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
152 else:
152 else:
153 ui.warn(_("abort: %s\n") % inst.strerror)
153 ui.warn(_("abort: %s\n") % inst.strerror)
154 except KeyboardInterrupt:
154 except KeyboardInterrupt:
155 try:
155 try:
156 ui.warn(_("interrupted!\n"))
156 ui.warn(_("interrupted!\n"))
157 except IOError, inst:
157 except IOError, inst:
158 if inst.errno == errno.EPIPE:
158 if inst.errno == errno.EPIPE:
159 if ui.debugflag:
159 if ui.debugflag:
160 ui.warn(_("\nbroken pipe\n"))
160 ui.warn(_("\nbroken pipe\n"))
161 else:
161 else:
162 raise
162 raise
163 except MemoryError:
163 except MemoryError:
164 ui.warn(_("abort: out of memory\n"))
164 ui.warn(_("abort: out of memory\n"))
165 except SystemExit, inst:
165 except SystemExit, inst:
166 # Commands shouldn't sys.exit directly, but give a return code.
166 # Commands shouldn't sys.exit directly, but give a return code.
167 # Just in case catch this and and pass exit code to caller.
167 # Just in case catch this and and pass exit code to caller.
168 return inst.code
168 return inst.code
169 except socket.error, inst:
169 except socket.error, inst:
170 ui.warn(_("abort: %s\n") % inst.args[-1])
170 ui.warn(_("abort: %s\n") % inst.args[-1])
171 except:
171 except:
172 ui.warn(_("** unknown exception encountered, details follow\n"))
172 ui.warn(_("** unknown exception encountered, details follow\n"))
173 ui.warn(_("** report bug details to "
173 ui.warn(_("** report bug details to "
174 "http://mercurial.selenic.com/bts/\n"))
174 "http://mercurial.selenic.com/bts/\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
178 % util.version())
178 % util.version())
179 ui.warn(_("** Extensions loaded: %s\n")
179 ui.warn(_("** Extensions loaded: %s\n")
180 % ", ".join([x[0] for x in extensions.extensions()]))
180 % ", ".join([x[0] for x in extensions.extensions()]))
181 raise
181 raise
182
182
183 return -1
183 return -1
184
184
185 def aliasargs(fn):
185 def aliasargs(fn):
186 if hasattr(fn, 'args'):
186 if hasattr(fn, 'args'):
187 return fn.args
187 return fn.args
188 return []
188 return []
189
189
190 class cmdalias(object):
190 class cmdalias(object):
191 def __init__(self, name, definition, cmdtable):
191 def __init__(self, name, definition, cmdtable):
192 self.name = self.cmd = name
192 self.name = self.cmd = name
193 self.cmdname = ''
193 self.cmdname = ''
194 self.definition = definition
194 self.definition = definition
195 self.args = []
195 self.args = []
196 self.opts = []
196 self.opts = []
197 self.help = ''
197 self.help = ''
198 self.norepo = True
198 self.norepo = True
199 self.badalias = False
199 self.badalias = False
200
200
201 try:
201 try:
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
202 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
203 for alias, e in cmdtable.iteritems():
203 for alias, e in cmdtable.iteritems():
204 if e is entry:
204 if e is entry:
205 self.cmd = alias
205 self.cmd = alias
206 break
206 break
207 self.shadows = True
207 self.shadows = True
208 except error.UnknownCommand:
208 except error.UnknownCommand:
209 self.shadows = False
209 self.shadows = False
210
210
211 if not self.definition:
211 if not self.definition:
212 def fn(ui, *args):
212 def fn(ui, *args):
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
213 ui.warn(_("no definition for alias '%s'\n") % self.name)
214 return 1
214 return 1
215 self.fn = fn
215 self.fn = fn
216 self.badalias = True
216 self.badalias = True
217
217
218 return
218 return
219
219
220 if self.definition.startswith('!'):
220 if self.definition.startswith('!'):
221 self.shell = True
221 self.shell = True
222 def fn(ui, *args):
222 def fn(ui, *args):
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
223 env = {'HG_ARGS': ' '.join((self.name,) + args)}
224 def _checkvar(m):
224 def _checkvar(m):
225 if int(m.groups()[0]) <= len(args):
225 if int(m.groups()[0]) <= len(args):
226 return m.group()
226 return m.group()
227 else:
227 else:
228 return ''
228 return ''
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
229 cmd = re.sub(r'\$(\d+)', _checkvar, self.definition[1:])
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
230 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
231 replace['0'] = self.name
231 replace['0'] = self.name
232 replace['@'] = ' '.join(args)
232 replace['@'] = ' '.join(args)
233 cmd = util.interpolate(r'\$', replace, cmd)
233 cmd = util.interpolate(r'\$', replace, cmd)
234 return util.system(cmd, environ=env)
234 return util.system(cmd, environ=env)
235 self.fn = fn
235 self.fn = fn
236 return
236 return
237
237
238 args = shlex.split(self.definition)
238 args = shlex.split(self.definition)
239 self.cmdname = cmd = args.pop(0)
239 self.cmdname = cmd = args.pop(0)
240 args = map(util.expandpath, args)
240 args = map(util.expandpath, args)
241
241
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
242 for invalidarg in ("--cwd", "-R", "--repository", "--repo"):
243 if _earlygetopt([invalidarg], args):
243 if _earlygetopt([invalidarg], args):
244 def fn(ui, *args):
244 def fn(ui, *args):
245 ui.warn(_("error in definition for alias '%s': %s may only "
245 ui.warn(_("error in definition for alias '%s': %s may only "
246 "be given on the command line\n")
246 "be given on the command line\n")
247 % (self.name, invalidarg))
247 % (self.name, invalidarg))
248 return 1
248 return 1
249
249
250 self.fn = fn
250 self.fn = fn
251 self.badalias = True
251 self.badalias = True
252 return
252 return
253
253
254 try:
254 try:
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
255 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
256 if len(tableentry) > 2:
256 if len(tableentry) > 2:
257 self.fn, self.opts, self.help = tableentry
257 self.fn, self.opts, self.help = tableentry
258 else:
258 else:
259 self.fn, self.opts = tableentry
259 self.fn, self.opts = tableentry
260
260
261 self.args = aliasargs(self.fn) + args
261 self.args = aliasargs(self.fn) + args
262 if cmd not in commands.norepo.split(' '):
262 if cmd not in commands.norepo.split(' '):
263 self.norepo = False
263 self.norepo = False
264 if self.help.startswith("hg " + cmd):
264 if self.help.startswith("hg " + cmd):
265 # drop prefix in old-style help lines so hg shows the alias
265 # drop prefix in old-style help lines so hg shows the alias
266 self.help = self.help[4 + len(cmd):]
266 self.help = self.help[4 + len(cmd):]
267 self.__doc__ = self.fn.__doc__
267 self.__doc__ = self.fn.__doc__
268
268
269 except error.UnknownCommand:
269 except error.UnknownCommand:
270 def fn(ui, *args):
270 def fn(ui, *args):
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
271 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
272 % (self.name, cmd))
272 % (self.name, cmd))
273 try:
273 try:
274 # check if the command is in a disabled extension
274 # check if the command is in a disabled extension
275 commands.help_(ui, cmd, unknowncmd=True)
275 commands.help_(ui, cmd, unknowncmd=True)
276 except error.UnknownCommand:
276 except error.UnknownCommand:
277 pass
277 pass
278 return 1
278 return 1
279 self.fn = fn
279 self.fn = fn
280 self.badalias = True
280 self.badalias = True
281 except error.AmbiguousCommand:
281 except error.AmbiguousCommand:
282 def fn(ui, *args):
282 def fn(ui, *args):
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
283 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
284 % (self.name, cmd))
284 % (self.name, cmd))
285 return 1
285 return 1
286 self.fn = fn
286 self.fn = fn
287 self.badalias = True
287 self.badalias = True
288
288
289 def __call__(self, ui, *args, **opts):
289 def __call__(self, ui, *args, **opts):
290 if self.shadows:
290 if self.shadows:
291 ui.debug("alias '%s' shadows command '%s'\n" %
291 ui.debug("alias '%s' shadows command '%s'\n" %
292 (self.name, self.cmdname))
292 (self.name, self.cmdname))
293
293
294 if self.definition.startswith('!'):
294 if self.definition.startswith('!'):
295 return self.fn(ui, *args, **opts)
295 return self.fn(ui, *args, **opts)
296 else:
296 else:
297 try:
297 try:
298 util.checksignature(self.fn)(ui, *args, **opts)
298 util.checksignature(self.fn)(ui, *args, **opts)
299 except error.SignatureError:
299 except error.SignatureError:
300 args = ' '.join([self.cmdname] + self.args)
300 args = ' '.join([self.cmdname] + self.args)
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
301 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
302 raise
302 raise
303
303
304 def addaliases(ui, cmdtable):
304 def addaliases(ui, cmdtable):
305 # aliases are processed after extensions have been loaded, so they
305 # aliases are processed after extensions have been loaded, so they
306 # may use extension commands. Aliases can also use other alias definitions,
306 # may use extension commands. Aliases can also use other alias definitions,
307 # but only if they have been defined prior to the current definition.
307 # but only if they have been defined prior to the current definition.
308 for alias, definition in ui.configitems('alias'):
308 for alias, definition in ui.configitems('alias'):
309 aliasdef = cmdalias(alias, definition, cmdtable)
309 aliasdef = cmdalias(alias, definition, cmdtable)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
310 cmdtable[aliasdef.cmd] = (aliasdef, aliasdef.opts, aliasdef.help)
311 if aliasdef.norepo:
311 if aliasdef.norepo:
312 commands.norepo += ' %s' % alias
312 commands.norepo += ' %s' % alias
313
313
314 def _parse(ui, args):
314 def _parse(ui, args):
315 options = {}
315 options = {}
316 cmdoptions = {}
316 cmdoptions = {}
317
317
318 try:
318 try:
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
319 args = fancyopts.fancyopts(args, commands.globalopts, options)
320 except fancyopts.getopt.GetoptError, inst:
320 except fancyopts.getopt.GetoptError, inst:
321 raise error.CommandError(None, inst)
321 raise error.CommandError(None, inst)
322
322
323 if args:
323 if args:
324 cmd, args = args[0], args[1:]
324 cmd, args = args[0], args[1:]
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
325 aliases, entry = cmdutil.findcmd(cmd, commands.table,
326 ui.config("ui", "strict"))
326 ui.config("ui", "strict"))
327 cmd = aliases[0]
327 cmd = aliases[0]
328 args = aliasargs(entry[0]) + args
328 args = aliasargs(entry[0]) + args
329 defaults = ui.config("defaults", cmd)
329 defaults = ui.config("defaults", cmd)
330 if defaults:
330 if defaults:
331 args = map(util.expandpath, shlex.split(defaults)) + args
331 args = map(util.expandpath, shlex.split(defaults)) + args
332 c = list(entry[1])
332 c = list(entry[1])
333 else:
333 else:
334 cmd = None
334 cmd = None
335 c = []
335 c = []
336
336
337 # combine global options into local
337 # combine global options into local
338 for o in commands.globalopts:
338 for o in commands.globalopts:
339 c.append((o[0], o[1], options[o[1]], o[3]))
339 c.append((o[0], o[1], options[o[1]], o[3]))
340
340
341 try:
341 try:
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
342 args = fancyopts.fancyopts(args, c, cmdoptions, True)
343 except fancyopts.getopt.GetoptError, inst:
343 except fancyopts.getopt.GetoptError, inst:
344 raise error.CommandError(cmd, inst)
344 raise error.CommandError(cmd, inst)
345
345
346 # separate global options back out
346 # separate global options back out
347 for o in commands.globalopts:
347 for o in commands.globalopts:
348 n = o[1]
348 n = o[1]
349 options[n] = cmdoptions[n]
349 options[n] = cmdoptions[n]
350 del cmdoptions[n]
350 del cmdoptions[n]
351
351
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
352 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
353
353
354 def _parseconfig(ui, config):
354 def _parseconfig(ui, config):
355 """parse the --config options from the command line"""
355 """parse the --config options from the command line"""
356 for cfg in config:
356 for cfg in config:
357 try:
357 try:
358 name, value = cfg.split('=', 1)
358 name, value = cfg.split('=', 1)
359 section, name = name.split('.', 1)
359 section, name = name.split('.', 1)
360 if not section or not name:
360 if not section or not name:
361 raise IndexError
361 raise IndexError
362 ui.setconfig(section, name, value)
362 ui.setconfig(section, name, value)
363 except (IndexError, ValueError):
363 except (IndexError, ValueError):
364 raise util.Abort(_('malformed --config option: %r '
364 raise util.Abort(_('malformed --config option: %r '
365 '(use --config section.name=value)') % cfg)
365 '(use --config section.name=value)') % cfg)
366
366
367 def _earlygetopt(aliases, args):
367 def _earlygetopt(aliases, args):
368 """Return list of values for an option (or aliases).
368 """Return list of values for an option (or aliases).
369
369
370 The values are listed in the order they appear in args.
370 The values are listed in the order they appear in args.
371 The options and values are removed from args.
371 The options and values are removed from args.
372 """
372 """
373 try:
373 try:
374 argcount = args.index("--")
374 argcount = args.index("--")
375 except ValueError:
375 except ValueError:
376 argcount = len(args)
376 argcount = len(args)
377 shortopts = [opt for opt in aliases if len(opt) == 2]
377 shortopts = [opt for opt in aliases if len(opt) == 2]
378 values = []
378 values = []
379 pos = 0
379 pos = 0
380 while pos < argcount:
380 while pos < argcount:
381 if args[pos] in aliases:
381 if args[pos] in aliases:
382 if pos + 1 >= argcount:
382 if pos + 1 >= argcount:
383 # ignore and let getopt report an error if there is no value
383 # ignore and let getopt report an error if there is no value
384 break
384 break
385 del args[pos]
385 del args[pos]
386 values.append(args.pop(pos))
386 values.append(args.pop(pos))
387 argcount -= 2
387 argcount -= 2
388 elif args[pos][:2] in shortopts:
388 elif args[pos][:2] in shortopts:
389 # short option can have no following space, e.g. hg log -Rfoo
389 # short option can have no following space, e.g. hg log -Rfoo
390 values.append(args.pop(pos)[2:])
390 values.append(args.pop(pos)[2:])
391 argcount -= 1
391 argcount -= 1
392 else:
392 else:
393 pos += 1
393 pos += 1
394 return values
394 return values
395
395
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
396 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
397 # run pre-hook, and abort if it fails
397 # run pre-hook, and abort if it fails
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
398 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
399 pats=cmdpats, opts=cmdoptions)
399 pats=cmdpats, opts=cmdoptions)
400 if ret:
400 if ret:
401 return ret
401 return ret
402 ret = _runcommand(ui, options, cmd, d)
402 ret = _runcommand(ui, options, cmd, d)
403 # run post-hook, passing command result
403 # run post-hook, passing command result
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
404 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
405 result=ret, pats=cmdpats, opts=cmdoptions)
405 result=ret, pats=cmdpats, opts=cmdoptions)
406 return ret
406 return ret
407
407
408 def _getlocal(ui, rpath):
408 def _getlocal(ui, rpath):
409 """Return (path, local ui object) for the given target path.
409 """Return (path, local ui object) for the given target path.
410
410
411 Takes paths in [cwd]/.hg/hgrc into account."
411 Takes paths in [cwd]/.hg/hgrc into account."
412 """
412 """
413 try:
413 try:
414 wd = os.getcwd()
414 wd = os.getcwd()
415 except OSError, e:
415 except OSError, e:
416 raise util.Abort(_("error getting current working directory: %s") %
416 raise util.Abort(_("error getting current working directory: %s") %
417 e.strerror)
417 e.strerror)
418 path = cmdutil.findrepo(wd) or ""
418 path = cmdutil.findrepo(wd) or ""
419 if not path:
419 if not path:
420 lui = ui
420 lui = ui
421 else:
421 else:
422 lui = ui.copy()
422 lui = ui.copy()
423 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
423 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
424
424
425 if rpath:
425 if rpath:
426 path = lui.expandpath(rpath[-1])
426 path = lui.expandpath(rpath[-1])
427 lui = ui.copy()
427 lui = ui.copy()
428 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
428 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
429
429
430 return path, lui
430 return path, lui
431
431
432 def _checkshellalias(ui, args):
432 def _checkshellalias(ui, args):
433 cwd = os.getcwd()
433 cwd = os.getcwd()
434 norepo = commands.norepo
434 norepo = commands.norepo
435 options = {}
435 options = {}
436
436
437 try:
437 try:
438 args = fancyopts.fancyopts(args, commands.globalopts, options)
438 args = fancyopts.fancyopts(args, commands.globalopts, options)
439 except fancyopts.getopt.GetoptError:
439 except fancyopts.getopt.GetoptError:
440 return
440 return
441
441
442 if not args:
442 if not args:
443 return
443 return
444
444
445 _parseconfig(ui, options['config'])
445 _parseconfig(ui, options['config'])
446 if options['cwd']:
446 if options['cwd']:
447 os.chdir(options['cwd'])
447 os.chdir(options['cwd'])
448
448
449 path, lui = _getlocal(ui, [options['repository']])
449 path, lui = _getlocal(ui, [options['repository']])
450
450
451 cmdtable = commands.table.copy()
451 cmdtable = commands.table.copy()
452 addaliases(lui, cmdtable)
452 addaliases(lui, cmdtable)
453
453
454 cmd = args[0]
454 cmd = args[0]
455 try:
455 try:
456 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
456 aliases, entry = cmdutil.findcmd(cmd, cmdtable, lui.config("ui", "strict"))
457 except error.UnknownCommand:
457 except error.UnknownCommand:
458 commands.norepo = norepo
458 commands.norepo = norepo
459 os.chdir(cwd)
459 os.chdir(cwd)
460 return
460 return
461
461
462 cmd = aliases[0]
462 cmd = aliases[0]
463 fn = entry[0]
463 fn = entry[0]
464
464
465 if cmd and hasattr(fn, 'shell'):
465 if cmd and hasattr(fn, 'shell'):
466 d = lambda: fn(ui, *args[1:])
466 d = lambda: fn(ui, *args[1:])
467 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
467 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, [], {})
468
468
469 commands.norepo = norepo
469 commands.norepo = norepo
470 os.chdir(cwd)
470 os.chdir(cwd)
471
471
472 _loaded = set()
472 _loaded = set()
473 def _dispatch(ui, args):
473 def _dispatch(ui, args):
474 shellaliasfn = _checkshellalias(ui, args)
474 shellaliasfn = _checkshellalias(ui, args)
475 if shellaliasfn:
475 if shellaliasfn:
476 return shellaliasfn()
476 return shellaliasfn()
477
477
478 # read --config before doing anything else
478 # read --config before doing anything else
479 # (e.g. to change trust settings for reading .hg/hgrc)
479 # (e.g. to change trust settings for reading .hg/hgrc)
480 _parseconfig(ui, _earlygetopt(['--config'], args))
480 _parseconfig(ui, _earlygetopt(['--config'], args))
481
481
482 # check for cwd
482 # check for cwd
483 cwd = _earlygetopt(['--cwd'], args)
483 cwd = _earlygetopt(['--cwd'], args)
484 if cwd:
484 if cwd:
485 os.chdir(cwd[-1])
485 os.chdir(cwd[-1])
486
486
487 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
487 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
488 path, lui = _getlocal(ui, rpath)
488 path, lui = _getlocal(ui, rpath)
489
489
490 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
490 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
491 # reposetup. Programs like TortoiseHg will call _dispatch several
491 # reposetup. Programs like TortoiseHg will call _dispatch several
492 # times so we keep track of configured extensions in _loaded.
492 # times so we keep track of configured extensions in _loaded.
493 extensions.loadall(lui)
493 extensions.loadall(lui)
494 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
494 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
495 # Propagate any changes to lui.__class__ by extensions
495 # Propagate any changes to lui.__class__ by extensions
496 ui.__class__ = lui.__class__
496 ui.__class__ = lui.__class__
497
497
498 # (uisetup and extsetup are handled in extensions.loadall)
498 # (uisetup and extsetup are handled in extensions.loadall)
499
499
500 for name, module in exts:
500 for name, module in exts:
501 cmdtable = getattr(module, 'cmdtable', {})
501 cmdtable = getattr(module, 'cmdtable', {})
502 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
502 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
503 if overrides:
503 if overrides:
504 ui.warn(_("extension '%s' overrides commands: %s\n")
504 ui.warn(_("extension '%s' overrides commands: %s\n")
505 % (name, " ".join(overrides)))
505 % (name, " ".join(overrides)))
506 commands.table.update(cmdtable)
506 commands.table.update(cmdtable)
507 _loaded.add(name)
507 _loaded.add(name)
508
508
509 # (reposetup is handled in hg.repository)
509 # (reposetup is handled in hg.repository)
510
510
511 addaliases(lui, commands.table)
511 addaliases(lui, commands.table)
512
512
513 # check for fallback encoding
513 # check for fallback encoding
514 fallback = lui.config('ui', 'fallbackencoding')
514 fallback = lui.config('ui', 'fallbackencoding')
515 if fallback:
515 if fallback:
516 encoding.fallbackencoding = fallback
516 encoding.fallbackencoding = fallback
517
517
518 fullargs = args
518 fullargs = args
519 cmd, func, args, options, cmdoptions = _parse(lui, args)
519 cmd, func, args, options, cmdoptions = _parse(lui, args)
520
520
521 if options["config"]:
521 if options["config"]:
522 raise util.Abort(_("option --config may not be abbreviated!"))
522 raise util.Abort(_("option --config may not be abbreviated!"))
523 if options["cwd"]:
523 if options["cwd"]:
524 raise util.Abort(_("option --cwd may not be abbreviated!"))
524 raise util.Abort(_("option --cwd may not be abbreviated!"))
525 if options["repository"]:
525 if options["repository"]:
526 raise util.Abort(_(
526 raise util.Abort(_(
527 "Option -R has to be separated from other options (e.g. not -qR) "
527 "Option -R has to be separated from other options (e.g. not -qR) "
528 "and --repository may only be abbreviated as --repo!"))
528 "and --repository may only be abbreviated as --repo!"))
529
529
530 if options["encoding"]:
530 if options["encoding"]:
531 encoding.encoding = options["encoding"]
531 encoding.encoding = options["encoding"]
532 if options["encodingmode"]:
532 if options["encodingmode"]:
533 encoding.encodingmode = options["encodingmode"]
533 encoding.encodingmode = options["encodingmode"]
534 if options["time"]:
534 if options["time"]:
535 def get_times():
535 def get_times():
536 t = os.times()
536 t = os.times()
537 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
537 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
538 t = (t[0], t[1], t[2], t[3], time.clock())
538 t = (t[0], t[1], t[2], t[3], time.clock())
539 return t
539 return t
540 s = get_times()
540 s = get_times()
541 def print_time():
541 def print_time():
542 t = get_times()
542 t = get_times()
543 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
543 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
544 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
544 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
545 atexit.register(print_time)
545 atexit.register(print_time)
546
546
547 if options['verbose'] or options['debug'] or options['quiet']:
547 if options['verbose'] or options['debug'] or options['quiet']:
548 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
548 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
549 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
549 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
550 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
550 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
551 if options['traceback']:
551 if options['traceback']:
552 ui.setconfig('ui', 'traceback', 'on')
552 ui.setconfig('ui', 'traceback', 'on')
553 if options['noninteractive']:
553 if options['noninteractive']:
554 ui.setconfig('ui', 'interactive', 'off')
554 ui.setconfig('ui', 'interactive', 'off')
555
555
556 if options['help']:
556 if options['help']:
557 return commands.help_(ui, cmd, options['version'])
557 return commands.help_(ui, cmd, options['version'])
558 elif options['version']:
558 elif options['version']:
559 return commands.version_(ui)
559 return commands.version_(ui)
560 elif not cmd:
560 elif not cmd:
561 return commands.help_(ui, 'shortlist')
561 return commands.help_(ui, 'shortlist')
562
562
563 repo = None
563 repo = None
564 cmdpats = args[:]
564 cmdpats = args[:]
565 if cmd not in commands.norepo.split():
565 if cmd not in commands.norepo.split():
566 try:
566 try:
567 repo = hg.repository(ui, path=path)
567 repo = hg.repository(ui, path=path)
568 ui = repo.ui
568 ui = repo.ui
569 if not repo.local():
569 if not repo.local():
570 raise util.Abort(_("repository '%s' is not local") % path)
570 raise util.Abort(_("repository '%s' is not local") % path)
571 ui.setconfig("bundle", "mainreporoot", repo.root)
571 ui.setconfig("bundle", "mainreporoot", repo.root)
572 except error.RepoError:
572 except error.RepoError:
573 if cmd not in commands.optionalrepo.split():
573 if cmd not in commands.optionalrepo.split():
574 if args and not path: # try to infer -R from command args
574 if args and not path: # try to infer -R from command args
575 repos = map(cmdutil.findrepo, args)
575 repos = map(cmdutil.findrepo, args)
576 guess = repos[0]
576 guess = repos[0]
577 if guess and repos.count(guess) == len(repos):
577 if guess and repos.count(guess) == len(repos):
578 return _dispatch(ui, ['--repository', guess] + fullargs)
578 return _dispatch(ui, ['--repository', guess] + fullargs)
579 if not path:
579 if not path:
580 raise error.RepoError(_("There is no Mercurial repository"
580 raise error.RepoError(_("There is no Mercurial repository"
581 " here (.hg not found)"))
581 " here (.hg not found)"))
582 raise
582 raise
583 args.insert(0, repo)
583 args.insert(0, repo)
584 elif rpath:
584 elif rpath:
585 ui.warn(_("warning: --repository ignored\n"))
585 ui.warn(_("warning: --repository ignored\n"))
586
586
587 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
587 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
588 ui.log("command", msg + "\n")
588 ui.log("command", msg + "\n")
589 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
589 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
590 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
590 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
591 cmdpats, cmdoptions)
591 cmdpats, cmdoptions)
592
592
593 def _runcommand(ui, options, cmd, cmdfunc):
593 def _runcommand(ui, options, cmd, cmdfunc):
594 def checkargs():
594 def checkargs():
595 try:
595 try:
596 return cmdfunc()
596 return cmdfunc()
597 except error.SignatureError:
597 except error.SignatureError:
598 raise error.CommandError(cmd, _("invalid arguments"))
598 raise error.CommandError(cmd, _("invalid arguments"))
599
599
600 if options['profile']:
600 if options['profile']:
601 format = ui.config('profiling', 'format', default='text')
601 format = ui.config('profiling', 'format', default='text')
602
602
603 if not format in ['text', 'kcachegrind']:
603 if not format in ['text', 'kcachegrind']:
604 ui.warn(_("unrecognized profiling format '%s'"
604 ui.warn(_("unrecognized profiling format '%s'"
605 " - Ignored\n") % format)
605 " - Ignored\n") % format)
606 format = 'text'
606 format = 'text'
607
607
608 output = ui.config('profiling', 'output')
608 output = ui.config('profiling', 'output')
609
609
610 if output:
610 if output:
611 path = ui.expandpath(output)
611 path = ui.expandpath(output)
612 ostream = open(path, 'wb')
612 ostream = open(path, 'wb')
613 else:
613 else:
614 ostream = sys.stderr
614 ostream = sys.stderr
615
615
616 try:
616 try:
617 from mercurial import lsprof
617 from mercurial import lsprof
618 except ImportError:
618 except ImportError:
619 raise util.Abort(_(
619 raise util.Abort(_(
620 'lsprof not available - install from '
620 'lsprof not available - install from '
621 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
621 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
622 p = lsprof.Profiler()
622 p = lsprof.Profiler()
623 p.enable(subcalls=True)
623 p.enable(subcalls=True)
624 try:
624 try:
625 return checkargs()
625 return checkargs()
626 finally:
626 finally:
627 p.disable()
627 p.disable()
628
628
629 if format == 'kcachegrind':
629 if format == 'kcachegrind':
630 import lsprofcalltree
630 import lsprofcalltree
631 calltree = lsprofcalltree.KCacheGrind(p)
631 calltree = lsprofcalltree.KCacheGrind(p)
632 calltree.output(ostream)
632 calltree.output(ostream)
633 else:
633 else:
634 # format == 'text'
634 # format == 'text'
635 stats = lsprof.Stats(p.getstats())
635 stats = lsprof.Stats(p.getstats())
636 stats.sort()
636 stats.sort()
637 stats.pprint(top=10, file=ostream, climit=5)
637 stats.pprint(top=10, file=ostream, climit=5)
638
638
639 if output:
639 if output:
640 ostream.close()
640 ostream.close()
641 else:
641 else:
642 return checkargs()
642 return checkargs()
@@ -1,85 +1,109 b''
1 To merge files Mercurial uses merge tools.
1 To merge files Mercurial uses merge tools.
2
2
3 A merge tool combines two different versions of a file into a merged
3 A merge tool combines two different versions of a file into a merged
4 file. Merge tools are given the two files and the greatest common
4 file. Merge tools are given the two files and the greatest common
5 ancestor of the two file versions, so they can determine the changes
5 ancestor of the two file versions, so they can determine the changes
6 made on both branches.
6 made on both branches.
7
7
8 The merge tools are used both for :hg:`resolve` and :hg:`merge`.
8 Merge tools are used both for :hg:`resolve`, :hg:`merge`, :hg:`update`,
9 :hg:`backout` and in several extensions.
9
10
10 Usually, the merge tool tries to automatically, by combining all the
11 Usually, the merge tool tries to automatically reconcile the files by
11 non-overlapping changes that occurred separately in the two different
12 combining all non-overlapping changes that occurred separately in
12 evolutions of the same initial base file. Furthermore, some
13 the two different evolutions of the same initial base file. Furthermore, some
13 interactive merge programs make it easier to manually resolve
14 interactive merge programs make it easier to manually resolve
14 conflicting merges, either in a graphical way, or by inserting some
15 conflicting merges, either in a graphical way, or by inserting some
15 conflict markers. Mercurial does not include any interactive merge
16 conflict markers. Mercurial does not include any interactive merge
16 programs but relies on external tools for that. External merge tools
17 programs but relies on external tools for that.
17 and their properties and usage is configured in merge-tools section -
18
18 see hgrc(5).
19 Available merge tools
20 """""""""""""""""""""
21
22 External merge tools and their properties and usage is configured in the
23 merge-tools configuration section - see hgrc(5) - but they can often also just
24 be named by their executable.
25
26 A merge tool is generally usable if its executable can be found on the
27 system and if it can handle the merge. The executable can be found on the
28 system if it either is an absolute or relative executable path or the name of
29 an application in the executable search path. The tool is assumed to be able
30 to handle the merge if it can handle symlinks if the file is a symlink, if it
31 can handle binary files if the file is binary, and if a GUI is available if the
32 tool requires a GUI.
19
33
20 There are a some internal merge tools which can be used. The internal
34 There are a some internal merge tools which can be used. The internal
21 merge tools are:
35 merge tools are:
22
36
23 ``internal:merge``
37 ``internal:merge``
24 Uses the internal non-interactive merge tool for merging files.
38 Uses the internal non-interactive simple merge algorithm for merging files.
39 It will fail if there are any conflicts.
25
40
26 ``internal:fail``
41 ``internal:fail``
27 Rather than attempting to merge files that were modified on both
42 Rather than attempting to merge files that were modified on both
28 branches, it marks these files as unresolved. Then the resolve
43 branches, it marks these files as unresolved. Then the resolve
29 command must be used to mark files resolved.
44 command must be used to mark files resolved.
30
45
31 ``internal:local``
46 ``internal:local``
32 Uses the local version of files as the merged version.
47 Uses the local version of files as the merged version.
33
48
34 ``internal:other``
49 ``internal:other``
35 Uses the remote version of files as the merged version.
50 Uses the other version of files as the merged version.
36
51
37 ``internal:prompt``
52 ``internal:prompt``
38 Asks the user which of the local or the other version to keep as
53 Asks the user which of the local or the other version to keep as
39 the merged version.
54 the merged version.
40
55
41 ``internal:dump``
56 ``internal:dump``
42 Creates three versions of the files to merge, containing the
57 Creates three versions of the files to merge, containing the
43 contents of local, other and base. These files can then be used to
58 contents of local, other and base. These files can then be used to
44 perform a merge manually. If the file merged is name ``a.txt``,
59 perform a merge manually. If the file to be merged is named
45 these files will accordingly be named ``a.txt.local``,
60 ``a.txt``, these files will accordingly be named ``a.txt.local``,
46 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
61 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
47 same directory as the file to merge.
62 same directory as ``a.txt``.
63
64 Internal tools are always available and do not require a GUI but will by default
65 not handle symlinks or binary files.
48
66
49 How Mercurial decides which merge program to use
67 Choosing a merge tool
68 """""""""""""""""""""
69
70 Mercurial uses these rules when decing which merge tool to use:
50
71
51 1. If the ``HGMERGE`` environment variable is present, it is used. If
72 0. If a tool has been specified with the --tool option to merge or resolve, it
52 specified it must be either an executable path or the name of an
73 is used. If it is the name of a tool in the merge-tools configuration, its
53 application in your executable search path.
74 configuration is used. Otherwise the specified tool must be executable by
75 the shell.
54
76
55 2. If the filename of the file to be merged matches any of the
77 1. If the ``HGMERGE`` environment variable is present, its value is used and
56 patterns in the merge-patterns configuration section, then the
78 must be executable by the shell.
57 corresponding merge tool is used, unless the file to be merged is a
79
58 symlink. Here binary capabilities of the merge tool are not
80 2. If the filename of the file to be merged matches any of the patterns in the
59 considered.
81 merge-patterns configuration section, the first usable merge tool
82 corresponding to a matching pattern is used. Here, binary capabilities of the
83 merge tool are not considered.
60
84
61 3. If ui.merge is set, it is used.
85 3. If ui.merge is set it will be considered next. If the value is not the name
86 of a configured tool, the specified value is used and must be executable by
87 the shell. Otherwise the named tool is used if it is usable.
62
88
63 4. If any merge tools are present in the merge-tools configuration
89 4. If any usable merge tools are present in the merge-tools configuration
64 section, and any of the tools can be found on the system, the
90 section, the one with the higest priority is used.
65 priority settings are used to determine which one to use. Binary,
66 symlink and GUI capabilities do also have to match.
67
91
68 5. If a program named ``hgmerge`` exists on the system, it is used.
92 5. If a program named ``hgmerge`` can be found on the system, it is used - but
93 it will by default not be used for symlinks and binary files.
69
94
70 6. If the file to be merged is not binary and is not a symlink, then
95 6. If the file to be merged is not binary and is not a symlink, then
71 ``internal:merge`` is used.
96 ``internal:merge`` is used.
72
97
73 7. The merge fails.
98 7. The merge of the file fails and must be resolved before commit.
74
99
75 .. note::
100 .. note::
76 After selecting a merge program, Mercurial will by default attempt
101 After selecting a merge program, Mercurial will by default attempt
77 to merge the files using a simple merge algorithm first, to see if
102 to merge the files using a simple merge algorithm first. Only if it doesn't
78 they can be merged without conflicts. Only if there are conflicting
103 succeed because of conflicting changes Mercurial will actually execute the
79 changes Mercurial will actually execute the merge program. Whether
104 merge program. Whether to use the simple merge algorithm first can be
80 to use the simple merge algorithm first can be controlled be the
105 controlled by the premerge setting of the merge tool. Premerge is enabled by
81 premerge setting of the merge tool, which is enabled by default
106 default unless the file is binary or a symlink.
82 unless the file is binary or symlink.
83
107
84 See the merge-tools and ui sections of hgrc(5) for details on
108 See the merge-tools and ui sections of hgrc(5) for details on the
85 configuration of merge tools.
109 configuration of merge tools.
@@ -1,203 +1,203 b''
1 Mercurial supports a functional language for selecting a set of
1 Mercurial supports a functional language for selecting a set of
2 revisions.
2 revisions.
3
3
4 The language supports a number of predicates which are joined by infix
4 The language supports a number of predicates which are joined by infix
5 operators. Parenthesis can be used for grouping.
5 operators. Parenthesis can be used for grouping.
6
6
7 Identifiers such as branch names must be quoted with single or double
7 Identifiers such as branch names must be quoted with single or double
8 quotes if they contain characters outside of
8 quotes if they contain characters outside of
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
10 predicates.
10 predicates.
11
11
12 Special characters can be used in quoted identifiers by escaping them,
12 Special characters can be used in quoted identifiers by escaping them,
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
15
15
16 There is a single prefix operator:
16 There is a single prefix operator:
17
17
18 ``not x``
18 ``not x``
19 Changesets not in x. Short form is ``! x``.
19 Changesets not in x. Short form is ``! x``.
20
20
21 These are the supported infix operators:
21 These are the supported infix operators:
22
22
23 ``x::y``
23 ``x::y``
24 A DAG range, meaning all changesets that are descendants of x and
24 A DAG range, meaning all changesets that are descendants of x and
25 ancestors of y, including x and y themselves. If the first endpoint
25 ancestors of y, including x and y themselves. If the first endpoint
26 is left out, this is equivalent to ``ancestors(y)``, if the second
26 is left out, this is equivalent to ``ancestors(y)``, if the second
27 is left out it is equivalent to ``descendants(x)``.
27 is left out it is equivalent to ``descendants(x)``.
28
28
29 An alternative syntax is ``x..y``.
29 An alternative syntax is ``x..y``.
30
30
31 ``x:y``
31 ``x:y``
32 All changesets with revision numbers between x and y, both
32 All changesets with revision numbers between x and y, both
33 inclusive. Either endpoint can be left out, they default to 0 and
33 inclusive. Either endpoint can be left out, they default to 0 and
34 tip.
34 tip.
35
35
36 ``x and y``
36 ``x and y``
37 The intersection of changesets in x and y. Short form is ``x & y``.
37 The intersection of changesets in x and y. Short form is ``x & y``.
38
38
39 ``x or y``
39 ``x or y``
40 The union of changesets in x and y. There are two alternative short
40 The union of changesets in x and y. There are two alternative short
41 forms: ``x | y`` and ``x + y``.
41 forms: ``x | y`` and ``x + y``.
42
42
43 ``x - y``
43 ``x - y``
44 Changesets in x but not in y.
44 Changesets in x but not in y.
45
45
46 The following predicates are supported:
46 The following predicates are supported:
47
47
48 ``adds(pattern)``
48 ``adds(pattern)``
49 Changesets that add a file matching pattern.
49 Changesets that add a file matching pattern.
50
50
51 ``all()``
51 ``all()``
52 All changesets, the same as ``0:tip``.
52 All changesets, the same as ``0:tip``.
53
53
54 ``ancestor(single, single)``
54 ``ancestor(single, single)``
55 Greatest common ancestor of the two changesets.
55 Greatest common ancestor of the two changesets.
56
56
57 ``ancestors(set)``
57 ``ancestors(set)``
58 Changesets that are ancestors of a changeset in set.
58 Changesets that are ancestors of a changeset in set.
59
59
60 ``author(string)``
60 ``author(string)``
61 Alias for ``user(string)``.
61 Alias for ``user(string)``.
62
62
63 ``branch(set)``
63 ``branch(set)``
64 All changesets belonging to the branches of changesets in set.
64 All changesets belonging to the branches of changesets in set.
65
65
66 ``children(set)``
66 ``children(set)``
67 Child changesets of changesets in set.
67 Child changesets of changesets in set.
68
68
69 ``closed()``
69 ``closed()``
70 Changeset is closed.
70 Changeset is closed.
71
71
72 ``contains(pattern)``
72 ``contains(pattern)``
73 Revision contains pattern.
73 Revision contains pattern.
74
74
75 ``date(interval)``
75 ``date(interval)``
76 Changesets within the interval, see :hg:`help dates`.
76 Changesets within the interval, see :hg:`help dates`.
77
77
78 ``descendants(set)``
78 ``descendants(set)``
79 Changesets which are descendants of changesets in set.
79 Changesets which are descendants of changesets in set.
80
80
81 ``file(pattern)``
81 ``file(pattern)``
82 Changesets affecting files matched by pattern.
82 Changesets affecting files matched by pattern.
83
83
84 ``follow()``
84 ``follow()``
85 An alias for ``::.`` (ancestors of the working copy's first parent).
85 An alias for ``::.`` (ancestors of the working copy's first parent).
86
86
87 ``grep(regex)``
87 ``grep(regex)``
88 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
88 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
89 to ensure special escape characters are handled correctly.
89 to ensure special escape characters are handled correctly.
90
90
91 ``head()``
91 ``head()``
92 Changeset is a named branch head.
92 Changeset is a named branch head.
93
93
94 ``heads(set)``
94 ``heads(set)``
95 Members of set with no children in set.
95 Members of set with no children in set.
96
96
97 ``id(string)``
97 ``id(string)``
98 Revision non-ambiguously specified by the given hex string prefix
98 Revision non-ambiguously specified by the given hex string prefix
99
99
100 ``keyword(string)``
100 ``keyword(string)``
101 Search commit message, user name, and names of changed files for
101 Search commit message, user name, and names of changed files for
102 string.
102 string.
103
103
104 ``limit(set, n)``
104 ``limit(set, n)``
105 First n members of set.
105 First n members of set.
106
106
107 ``max(set)``
107 ``max(set)``
108 Changeset with highest revision number in set.
108 Changeset with highest revision number in set.
109
109
110 ``min(set)``
110 ``min(set)``
111 Changeset with lowest revision number in set.
111 Changeset with lowest revision number in set.
112
112
113 ``merge()``
113 ``merge()``
114 Changeset is a merge changeset.
114 Changeset is a merge changeset.
115
115
116 ``modifies(pattern)``
116 ``modifies(pattern)``
117 Changesets modifying files matched by pattern.
117 Changesets modifying files matched by pattern.
118
118
119 ``outgoing([path])``
119 ``outgoing([path])``
120 Changesets not found in the specified destination repository, or the
120 Changesets not found in the specified destination repository, or the
121 default push location.
121 default push location.
122
122
123 ``p1(set)``
123 ``p1(set)``
124 First parent of changesets in set.
124 First parent of changesets in set.
125
125
126 ``p2(set)``
126 ``p2(set)``
127 Second parent of changesets in set.
127 Second parent of changesets in set.
128
128
129 ``parents(set)``
129 ``parents(set)``
130 The set of all parents for all changesets in set.
130 The set of all parents for all changesets in set.
131
131
132 ``present(set)``
132 ``present(set)``
133 An empty set, if any revision in set isn't found; otherwise,
133 An empty set, if any revision in set isn't found; otherwise,
134 all revisions in set.
134 all revisions in set.
135
135
136 ``removes(pattern)``
136 ``removes(pattern)``
137 Changesets which remove files matching pattern.
137 Changesets which remove files matching pattern.
138
138
139 ``rev(number)``
139 ``rev(number)``
140 Revision with the given numeric identifier.
140 Revision with the given numeric identifier.
141
141
142 ``reverse(set)``
142 ``reverse(set)``
143 Reverse order of set.
143 Reverse order of set.
144
144
145 ``roots(set)``
145 ``roots(set)``
146 Changesets with no parent changeset in set.
146 Changesets with no parent changeset in set.
147
147
148 ``sort(set[, [-]key...])``
148 ``sort(set[, [-]key...])``
149 Sort set by keys. The default sort order is ascending, specify a key
149 Sort set by keys. The default sort order is ascending, specify a key
150 as ``-key`` to sort in descending order.
150 as ``-key`` to sort in descending order.
151
151
152 The keys can be:
152 The keys can be:
153
153
154 - ``rev`` for the revision number,
154 - ``rev`` for the revision number,
155 - ``branch`` for the branch name,
155 - ``branch`` for the branch name,
156 - ``desc`` for the commit message (description),
156 - ``desc`` for the commit message (description),
157 - ``user`` for user name (``author`` can be used as an alias),
157 - ``user`` for user name (``author`` can be used as an alias),
158 - ``date`` for the commit date
158 - ``date`` for the commit date
159
159
160 ``tag(name)``
160 ``tag(name)``
161 The specified tag by name, or all tagged revisions if no name is given.
161 The specified tag by name, or all tagged revisions if no name is given.
162
162
163 ``user(string)``
163 ``user(string)``
164 User name is string.
164 User name is string.
165
165
166 Command line equivalents for :hg:`log`::
166 Command line equivalents for :hg:`log`::
167
167
168 -f -> ::.
168 -f -> ::.
169 -d x -> date(x)
169 -d x -> date(x)
170 -k x -> keyword(x)
170 -k x -> keyword(x)
171 -m -> merge()
171 -m -> merge()
172 -u x -> user(x)
172 -u x -> user(x)
173 -b x -> branch(x)
173 -b x -> branch(x)
174 -P x -> !::x
174 -P x -> !::x
175 -l x -> limit(expr, x)
175 -l x -> limit(expr, x)
176
176
177 Some sample queries:
177 Some sample queries:
178
178
179 - Changesets on the default branch::
179 - Changesets on the default branch::
180
180
181 hg log -r 'branch(default)'
181 hg log -r "branch(default)"
182
182
183 - Changesets on the default branch since tag 1.5 (excluding merges)::
183 - Changesets on the default branch since tag 1.5 (excluding merges)::
184
184
185 hg log -r 'branch(default) and 1.5:: and not merge()'
185 hg log -r "branch(default) and 1.5:: and not merge()"
186
186
187 - Open branch heads::
187 - Open branch heads::
188
188
189 hg log -r 'head() and not closed()'
189 hg log -r "head() and not closed()"
190
190
191 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
191 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
192 ``hgext/*``::
192 ``hgext/*``::
193
193
194 hg log -r '1.3::1.5 and keyword(bug) and file("hgext/*")'
194 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
195
195
196 - Changesets in committed May 2008, sorted by user::
196 - Changesets in committed May 2008, sorted by user::
197
197
198 hg log -r 'sort(date("May 2008"), user)'
198 hg log -r "sort(date('May 2008'), user)"
199
199
200 - Changesets mentioning "bug" or "issue" that are not in a tagged
200 - Changesets mentioning "bug" or "issue" that are not in a tagged
201 release::
201 release::
202
202
203 hg log -r '(keyword(bug) or keyword(issue)) and not ancestors(tagged())'
203 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tagged())"
@@ -1,580 +1,580 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 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 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
8 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
9 from i18n import _
9 from i18n import _
10 import config, util, node, error, cmdutil
10 import config, util, node, error, cmdutil
11 hg = None
11 hg = None
12
12
13 nullstate = ('', '', 'empty')
13 nullstate = ('', '', 'empty')
14
14
15 def state(ctx, ui):
15 def state(ctx, ui):
16 """return a state dict, mapping subrepo paths configured in .hgsub
16 """return a state dict, mapping subrepo paths configured in .hgsub
17 to tuple: (source from .hgsub, revision from .hgsubstate, kind
17 to tuple: (source from .hgsub, revision from .hgsubstate, kind
18 (key in types dict))
18 (key in types dict))
19 """
19 """
20 p = config.config()
20 p = config.config()
21 def read(f, sections=None, remap=None):
21 def read(f, sections=None, remap=None):
22 if f in ctx:
22 if f in ctx:
23 p.parse(f, ctx[f].data(), sections, remap, read)
23 p.parse(f, ctx[f].data(), sections, remap, read)
24 else:
24 else:
25 raise util.Abort(_("subrepo spec file %s not found") % f)
25 raise util.Abort(_("subrepo spec file %s not found") % f)
26
26
27 if '.hgsub' in ctx:
27 if '.hgsub' in ctx:
28 read('.hgsub')
28 read('.hgsub')
29
29
30 for path, src in ui.configitems('subpaths'):
30 for path, src in ui.configitems('subpaths'):
31 p.set('subpaths', path, src, ui.configsource('subpaths', path))
31 p.set('subpaths', path, src, ui.configsource('subpaths', path))
32
32
33 rev = {}
33 rev = {}
34 if '.hgsubstate' in ctx:
34 if '.hgsubstate' in ctx:
35 try:
35 try:
36 for l in ctx['.hgsubstate'].data().splitlines():
36 for l in ctx['.hgsubstate'].data().splitlines():
37 revision, path = l.split(" ", 1)
37 revision, path = l.split(" ", 1)
38 rev[path] = revision
38 rev[path] = revision
39 except IOError, err:
39 except IOError, err:
40 if err.errno != errno.ENOENT:
40 if err.errno != errno.ENOENT:
41 raise
41 raise
42
42
43 state = {}
43 state = {}
44 for path, src in p[''].items():
44 for path, src in p[''].items():
45 kind = 'hg'
45 kind = 'hg'
46 if src.startswith('['):
46 if src.startswith('['):
47 if ']' not in src:
47 if ']' not in src:
48 raise util.Abort(_('missing ] in subrepo source'))
48 raise util.Abort(_('missing ] in subrepo source'))
49 kind, src = src.split(']', 1)
49 kind, src = src.split(']', 1)
50 kind = kind[1:]
50 kind = kind[1:]
51
51
52 for pattern, repl in p.items('subpaths'):
52 for pattern, repl in p.items('subpaths'):
53 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
53 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
54 # does a string decode.
54 # does a string decode.
55 repl = repl.encode('string-escape')
55 repl = repl.encode('string-escape')
56 # However, we still want to allow back references to go
56 # However, we still want to allow back references to go
57 # through unharmed, so we turn r'\\1' into r'\1'. Again,
57 # through unharmed, so we turn r'\\1' into r'\1'. Again,
58 # extra escapes are needed because re.sub string decodes.
58 # extra escapes are needed because re.sub string decodes.
59 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
59 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
60 try:
60 try:
61 src = re.sub(pattern, repl, src, 1)
61 src = re.sub(pattern, repl, src, 1)
62 except re.error, e:
62 except re.error, e:
63 raise util.Abort(_("bad subrepository pattern in %s: %s")
63 raise util.Abort(_("bad subrepository pattern in %s: %s")
64 % (p.source('subpaths', pattern), e))
64 % (p.source('subpaths', pattern), e))
65
65
66 state[path] = (src.strip(), rev.get(path, ''), kind)
66 state[path] = (src.strip(), rev.get(path, ''), kind)
67
67
68 return state
68 return state
69
69
70 def writestate(repo, state):
70 def writestate(repo, state):
71 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
71 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
72 repo.wwrite('.hgsubstate',
72 repo.wwrite('.hgsubstate',
73 ''.join(['%s %s\n' % (state[s][1], s)
73 ''.join(['%s %s\n' % (state[s][1], s)
74 for s in sorted(state)]), '')
74 for s in sorted(state)]), '')
75
75
76 def submerge(repo, wctx, mctx, actx):
76 def submerge(repo, wctx, mctx, actx):
77 """delegated from merge.applyupdates: merging of .hgsubstate file
77 """delegated from merge.applyupdates: merging of .hgsubstate file
78 in working context, merging context and ancestor context"""
78 in working context, merging context and ancestor context"""
79 if mctx == actx: # backwards?
79 if mctx == actx: # backwards?
80 actx = wctx.p1()
80 actx = wctx.p1()
81 s1 = wctx.substate
81 s1 = wctx.substate
82 s2 = mctx.substate
82 s2 = mctx.substate
83 sa = actx.substate
83 sa = actx.substate
84 sm = {}
84 sm = {}
85
85
86 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
86 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
87
87
88 def debug(s, msg, r=""):
88 def debug(s, msg, r=""):
89 if r:
89 if r:
90 r = "%s:%s:%s" % r
90 r = "%s:%s:%s" % r
91 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
91 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
92
92
93 for s, l in s1.items():
93 for s, l in s1.items():
94 a = sa.get(s, nullstate)
94 a = sa.get(s, nullstate)
95 ld = l # local state with possible dirty flag for compares
95 ld = l # local state with possible dirty flag for compares
96 if wctx.sub(s).dirty():
96 if wctx.sub(s).dirty():
97 ld = (l[0], l[1] + "+")
97 ld = (l[0], l[1] + "+")
98 if wctx == actx: # overwrite
98 if wctx == actx: # overwrite
99 a = ld
99 a = ld
100
100
101 if s in s2:
101 if s in s2:
102 r = s2[s]
102 r = s2[s]
103 if ld == r or r == a: # no change or local is newer
103 if ld == r or r == a: # no change or local is newer
104 sm[s] = l
104 sm[s] = l
105 continue
105 continue
106 elif ld == a: # other side changed
106 elif ld == a: # other side changed
107 debug(s, "other changed, get", r)
107 debug(s, "other changed, get", r)
108 wctx.sub(s).get(r)
108 wctx.sub(s).get(r)
109 sm[s] = r
109 sm[s] = r
110 elif ld[0] != r[0]: # sources differ
110 elif ld[0] != r[0]: # sources differ
111 if repo.ui.promptchoice(
111 if repo.ui.promptchoice(
112 _(' subrepository sources for %s differ\n'
112 _(' subrepository sources for %s differ\n'
113 'use (l)ocal source (%s) or (r)emote source (%s)?')
113 'use (l)ocal source (%s) or (r)emote source (%s)?')
114 % (s, l[0], r[0]),
114 % (s, l[0], r[0]),
115 (_('&Local'), _('&Remote')), 0):
115 (_('&Local'), _('&Remote')), 0):
116 debug(s, "prompt changed, get", r)
116 debug(s, "prompt changed, get", r)
117 wctx.sub(s).get(r)
117 wctx.sub(s).get(r)
118 sm[s] = r
118 sm[s] = r
119 elif ld[1] == a[1]: # local side is unchanged
119 elif ld[1] == a[1]: # local side is unchanged
120 debug(s, "other side changed, get", r)
120 debug(s, "other side changed, get", r)
121 wctx.sub(s).get(r)
121 wctx.sub(s).get(r)
122 sm[s] = r
122 sm[s] = r
123 else:
123 else:
124 debug(s, "both sides changed, merge with", r)
124 debug(s, "both sides changed, merge with", r)
125 wctx.sub(s).merge(r)
125 wctx.sub(s).merge(r)
126 sm[s] = l
126 sm[s] = l
127 elif ld == a: # remote removed, local unchanged
127 elif ld == a: # remote removed, local unchanged
128 debug(s, "remote removed, remove")
128 debug(s, "remote removed, remove")
129 wctx.sub(s).remove()
129 wctx.sub(s).remove()
130 else:
130 else:
131 if repo.ui.promptchoice(
131 if repo.ui.promptchoice(
132 _(' local changed subrepository %s which remote removed\n'
132 _(' local changed subrepository %s which remote removed\n'
133 'use (c)hanged version or (d)elete?') % s,
133 'use (c)hanged version or (d)elete?') % s,
134 (_('&Changed'), _('&Delete')), 0):
134 (_('&Changed'), _('&Delete')), 0):
135 debug(s, "prompt remove")
135 debug(s, "prompt remove")
136 wctx.sub(s).remove()
136 wctx.sub(s).remove()
137
137
138 for s, r in s2.items():
138 for s, r in s2.items():
139 if s in s1:
139 if s in s1:
140 continue
140 continue
141 elif s not in sa:
141 elif s not in sa:
142 debug(s, "remote added, get", r)
142 debug(s, "remote added, get", r)
143 mctx.sub(s).get(r)
143 mctx.sub(s).get(r)
144 sm[s] = r
144 sm[s] = r
145 elif r != sa[s]:
145 elif r != sa[s]:
146 if repo.ui.promptchoice(
146 if repo.ui.promptchoice(
147 _(' remote changed subrepository %s which local removed\n'
147 _(' remote changed subrepository %s which local removed\n'
148 'use (c)hanged version or (d)elete?') % s,
148 'use (c)hanged version or (d)elete?') % s,
149 (_('&Changed'), _('&Delete')), 0) == 0:
149 (_('&Changed'), _('&Delete')), 0) == 0:
150 debug(s, "prompt recreate", r)
150 debug(s, "prompt recreate", r)
151 wctx.sub(s).get(r)
151 wctx.sub(s).get(r)
152 sm[s] = r
152 sm[s] = r
153
153
154 # record merged .hgsubstate
154 # record merged .hgsubstate
155 writestate(repo, sm)
155 writestate(repo, sm)
156
156
157 def reporelpath(repo):
157 def reporelpath(repo):
158 """return path to this (sub)repo as seen from outermost repo"""
158 """return path to this (sub)repo as seen from outermost repo"""
159 parent = repo
159 parent = repo
160 while hasattr(parent, '_subparent'):
160 while hasattr(parent, '_subparent'):
161 parent = parent._subparent
161 parent = parent._subparent
162 return repo.root[len(parent.root)+1:]
162 return repo.root[len(parent.root)+1:]
163
163
164 def subrelpath(sub):
164 def subrelpath(sub):
165 """return path to this subrepo as seen from outermost repo"""
165 """return path to this subrepo as seen from outermost repo"""
166 if not hasattr(sub, '_repo'):
166 if not hasattr(sub, '_repo'):
167 return sub._path
167 return sub._path
168 return reporelpath(sub._repo)
168 return reporelpath(sub._repo)
169
169
170 def _abssource(repo, push=False, abort=True):
170 def _abssource(repo, push=False, abort=True):
171 """return pull/push path of repo - either based on parent repo .hgsub info
171 """return pull/push path of repo - either based on parent repo .hgsub info
172 or on the top repo config. Abort or return None if no source found."""
172 or on the top repo config. Abort or return None if no source found."""
173 if hasattr(repo, '_subparent'):
173 if hasattr(repo, '_subparent'):
174 source = repo._subsource
174 source = repo._subsource
175 if source.startswith('/') or '://' in source:
175 if source.startswith('/') or '://' in source:
176 return source
176 return source
177 parent = _abssource(repo._subparent, push, abort=False)
177 parent = _abssource(repo._subparent, push, abort=False)
178 if parent:
178 if parent:
179 if '://' in parent:
179 if '://' in parent:
180 if parent[-1] == '/':
180 if parent[-1] == '/':
181 parent = parent[:-1]
181 parent = parent[:-1]
182 r = urlparse.urlparse(parent + '/' + source)
182 r = urlparse.urlparse(parent + '/' + source)
183 r = urlparse.urlunparse((r[0], r[1],
183 r = urlparse.urlunparse((r[0], r[1],
184 posixpath.normpath(r[2]),
184 posixpath.normpath(r[2]),
185 r[3], r[4], r[5]))
185 r[3], r[4], r[5]))
186 return r
186 return r
187 else: # plain file system path
187 else: # plain file system path
188 return posixpath.normpath(os.path.join(parent, repo._subsource))
188 return posixpath.normpath(os.path.join(parent, repo._subsource))
189 else: # recursion reached top repo
189 else: # recursion reached top repo
190 if push and repo.ui.config('paths', 'default-push'):
190 if push and repo.ui.config('paths', 'default-push'):
191 return repo.ui.config('paths', 'default-push')
191 return repo.ui.config('paths', 'default-push')
192 if repo.ui.config('paths', 'default'):
192 if repo.ui.config('paths', 'default'):
193 return repo.ui.config('paths', 'default')
193 return repo.ui.config('paths', 'default')
194 if abort:
194 if abort:
195 raise util.Abort(_("default path for subrepository %s not found") %
195 raise util.Abort(_("default path for subrepository %s not found") %
196 reporelpath(repo))
196 reporelpath(repo))
197
197
198 def itersubrepos(ctx1, ctx2):
198 def itersubrepos(ctx1, ctx2):
199 """find subrepos in ctx1 or ctx2"""
199 """find subrepos in ctx1 or ctx2"""
200 # Create a (subpath, ctx) mapping where we prefer subpaths from
200 # Create a (subpath, ctx) mapping where we prefer subpaths from
201 # ctx1. The subpaths from ctx2 are important when the .hgsub file
201 # ctx1. The subpaths from ctx2 are important when the .hgsub file
202 # has been modified (in ctx2) but not yet committed (in ctx1).
202 # has been modified (in ctx2) but not yet committed (in ctx1).
203 subpaths = dict.fromkeys(ctx2.substate, ctx2)
203 subpaths = dict.fromkeys(ctx2.substate, ctx2)
204 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
204 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
205 for subpath, ctx in sorted(subpaths.iteritems()):
205 for subpath, ctx in sorted(subpaths.iteritems()):
206 yield subpath, ctx.sub(subpath)
206 yield subpath, ctx.sub(subpath)
207
207
208 def subrepo(ctx, path):
208 def subrepo(ctx, path):
209 """return instance of the right subrepo class for subrepo in path"""
209 """return instance of the right subrepo class for subrepo in path"""
210 # subrepo inherently violates our import layering rules
210 # subrepo inherently violates our import layering rules
211 # because it wants to make repo objects from deep inside the stack
211 # because it wants to make repo objects from deep inside the stack
212 # so we manually delay the circular imports to not break
212 # so we manually delay the circular imports to not break
213 # scripts that don't use our demand-loading
213 # scripts that don't use our demand-loading
214 global hg
214 global hg
215 import hg as h
215 import hg as h
216 hg = h
216 hg = h
217
217
218 util.path_auditor(ctx._repo.root)(path)
218 util.path_auditor(ctx._repo.root)(path)
219 state = ctx.substate.get(path, nullstate)
219 state = ctx.substate.get(path, nullstate)
220 if state[2] not in types:
220 if state[2] not in types:
221 raise util.Abort(_('unknown subrepo type %s') % state[2])
221 raise util.Abort(_('unknown subrepo type %s') % state[2])
222 return types[state[2]](ctx, path, state[:2])
222 return types[state[2]](ctx, path, state[:2])
223
223
224 # subrepo classes need to implement the following abstract class:
224 # subrepo classes need to implement the following abstract class:
225
225
226 class abstractsubrepo(object):
226 class abstractsubrepo(object):
227
227
228 def dirty(self):
228 def dirty(self):
229 """returns true if the dirstate of the subrepo does not match
229 """returns true if the dirstate of the subrepo does not match
230 current stored state
230 current stored state
231 """
231 """
232 raise NotImplementedError
232 raise NotImplementedError
233
233
234 def checknested(self, path):
234 def checknested(self, path):
235 """check if path is a subrepository within this repository"""
235 """check if path is a subrepository within this repository"""
236 return False
236 return False
237
237
238 def commit(self, text, user, date):
238 def commit(self, text, user, date):
239 """commit the current changes to the subrepo with the given
239 """commit the current changes to the subrepo with the given
240 log message. Use given user and date if possible. Return the
240 log message. Use given user and date if possible. Return the
241 new state of the subrepo.
241 new state of the subrepo.
242 """
242 """
243 raise NotImplementedError
243 raise NotImplementedError
244
244
245 def remove(self):
245 def remove(self):
246 """remove the subrepo
246 """remove the subrepo
247
247
248 (should verify the dirstate is not dirty first)
248 (should verify the dirstate is not dirty first)
249 """
249 """
250 raise NotImplementedError
250 raise NotImplementedError
251
251
252 def get(self, state):
252 def get(self, state):
253 """run whatever commands are needed to put the subrepo into
253 """run whatever commands are needed to put the subrepo into
254 this state
254 this state
255 """
255 """
256 raise NotImplementedError
256 raise NotImplementedError
257
257
258 def merge(self, state):
258 def merge(self, state):
259 """merge currently-saved state with the new state."""
259 """merge currently-saved state with the new state."""
260 raise NotImplementedError
260 raise NotImplementedError
261
261
262 def push(self, force):
262 def push(self, force):
263 """perform whatever action is analogous to 'hg push'
263 """perform whatever action is analogous to 'hg push'
264
264
265 This may be a no-op on some systems.
265 This may be a no-op on some systems.
266 """
266 """
267 raise NotImplementedError
267 raise NotImplementedError
268
268
269 def add(self, ui, match, dryrun, prefix):
269 def add(self, ui, match, dryrun, prefix):
270 return []
270 return []
271
271
272 def status(self, rev2, **opts):
272 def status(self, rev2, **opts):
273 return [], [], [], [], [], [], []
273 return [], [], [], [], [], [], []
274
274
275 def diff(self, diffopts, node2, match, prefix, **opts):
275 def diff(self, diffopts, node2, match, prefix, **opts):
276 pass
276 pass
277
277
278 def outgoing(self, ui, dest, opts):
278 def outgoing(self, ui, dest, opts):
279 return 1
279 return 1
280
280
281 def incoming(self, ui, source, opts):
281 def incoming(self, ui, source, opts):
282 return 1
282 return 1
283
283
284 def files(self):
284 def files(self):
285 """return filename iterator"""
285 """return filename iterator"""
286 raise NotImplementedError
286 raise NotImplementedError
287
287
288 def filedata(self, name):
288 def filedata(self, name):
289 """return file data"""
289 """return file data"""
290 raise NotImplementedError
290 raise NotImplementedError
291
291
292 def fileflags(self, name):
292 def fileflags(self, name):
293 """return file flags"""
293 """return file flags"""
294 return ''
294 return ''
295
295
296 def archive(self, archiver, prefix):
296 def archive(self, archiver, prefix):
297 for name in self.files():
297 for name in self.files():
298 flags = self.fileflags(name)
298 flags = self.fileflags(name)
299 mode = 'x' in flags and 0755 or 0644
299 mode = 'x' in flags and 0755 or 0644
300 symlink = 'l' in flags
300 symlink = 'l' in flags
301 archiver.addfile(os.path.join(prefix, self._path, name),
301 archiver.addfile(os.path.join(prefix, self._path, name),
302 mode, symlink, self.filedata(name))
302 mode, symlink, self.filedata(name))
303
303
304
304
305 class hgsubrepo(abstractsubrepo):
305 class hgsubrepo(abstractsubrepo):
306 def __init__(self, ctx, path, state):
306 def __init__(self, ctx, path, state):
307 self._path = path
307 self._path = path
308 self._state = state
308 self._state = state
309 r = ctx._repo
309 r = ctx._repo
310 root = r.wjoin(path)
310 root = r.wjoin(path)
311 create = False
311 create = False
312 if not os.path.exists(os.path.join(root, '.hg')):
312 if not os.path.exists(os.path.join(root, '.hg')):
313 create = True
313 create = True
314 util.makedirs(root)
314 util.makedirs(root)
315 self._repo = hg.repository(r.ui, root, create=create)
315 self._repo = hg.repository(r.ui, root, create=create)
316 self._repo._subparent = r
316 self._repo._subparent = r
317 self._repo._subsource = state[0]
317 self._repo._subsource = state[0]
318
318
319 if create:
319 if create:
320 fp = self._repo.opener("hgrc", "w", text=True)
320 fp = self._repo.opener("hgrc", "w", text=True)
321 fp.write('[paths]\n')
321 fp.write('[paths]\n')
322
322
323 def addpathconfig(key, value):
323 def addpathconfig(key, value):
324 if value:
324 if value:
325 fp.write('%s = %s\n' % (key, value))
325 fp.write('%s = %s\n' % (key, value))
326 self._repo.ui.setconfig('paths', key, value)
326 self._repo.ui.setconfig('paths', key, value)
327
327
328 defpath = _abssource(self._repo, abort=False)
328 defpath = _abssource(self._repo, abort=False)
329 defpushpath = _abssource(self._repo, True, abort=False)
329 defpushpath = _abssource(self._repo, True, abort=False)
330 addpathconfig('default', defpath)
330 addpathconfig('default', defpath)
331 if defpath != defpushpath:
331 if defpath != defpushpath:
332 addpathconfig('default-push', defpushpath)
332 addpathconfig('default-push', defpushpath)
333 fp.close()
333 fp.close()
334
334
335 def add(self, ui, match, dryrun, prefix):
335 def add(self, ui, match, dryrun, prefix):
336 return cmdutil.add(ui, self._repo, match, dryrun, True,
336 return cmdutil.add(ui, self._repo, match, dryrun, True,
337 os.path.join(prefix, self._path))
337 os.path.join(prefix, self._path))
338
338
339 def status(self, rev2, **opts):
339 def status(self, rev2, **opts):
340 try:
340 try:
341 rev1 = self._state[1]
341 rev1 = self._state[1]
342 ctx1 = self._repo[rev1]
342 ctx1 = self._repo[rev1]
343 ctx2 = self._repo[rev2]
343 ctx2 = self._repo[rev2]
344 return self._repo.status(ctx1, ctx2, **opts)
344 return self._repo.status(ctx1, ctx2, **opts)
345 except error.RepoLookupError, inst:
345 except error.RepoLookupError, inst:
346 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
346 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
347 % (inst, subrelpath(self)))
347 % (inst, subrelpath(self)))
348 return [], [], [], [], [], [], []
348 return [], [], [], [], [], [], []
349
349
350 def diff(self, diffopts, node2, match, prefix, **opts):
350 def diff(self, diffopts, node2, match, prefix, **opts):
351 try:
351 try:
352 node1 = node.bin(self._state[1])
352 node1 = node.bin(self._state[1])
353 # We currently expect node2 to come from substate and be
353 # We currently expect node2 to come from substate and be
354 # in hex format
354 # in hex format
355 if node2 is not None:
355 if node2 is not None:
356 node2 = node.bin(node2)
356 node2 = node.bin(node2)
357 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
357 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
358 node1, node2, match,
358 node1, node2, match,
359 prefix=os.path.join(prefix, self._path),
359 prefix=os.path.join(prefix, self._path),
360 listsubrepos=True, **opts)
360 listsubrepos=True, **opts)
361 except error.RepoLookupError, inst:
361 except error.RepoLookupError, inst:
362 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
362 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
363 % (inst, subrelpath(self)))
363 % (inst, subrelpath(self)))
364
364
365 def archive(self, archiver, prefix):
365 def archive(self, archiver, prefix):
366 abstractsubrepo.archive(self, archiver, prefix)
366 abstractsubrepo.archive(self, archiver, prefix)
367
367
368 rev = self._state[1]
368 rev = self._state[1]
369 ctx = self._repo[rev]
369 ctx = self._repo[rev]
370 for subpath in ctx.substate:
370 for subpath in ctx.substate:
371 s = subrepo(ctx, subpath)
371 s = subrepo(ctx, subpath)
372 s.archive(archiver, os.path.join(prefix, self._path))
372 s.archive(archiver, os.path.join(prefix, self._path))
373
373
374 def dirty(self):
374 def dirty(self):
375 r = self._state[1]
375 r = self._state[1]
376 if r == '':
376 if r == '':
377 return True
377 return True
378 w = self._repo[None]
378 w = self._repo[None]
379 if w.p1() != self._repo[r]: # version checked out change
379 if w.p1() != self._repo[r]: # version checked out change
380 return True
380 return True
381 return w.dirty() # working directory changed
381 return w.dirty() # working directory changed
382
382
383 def checknested(self, path):
383 def checknested(self, path):
384 return self._repo._checknested(self._repo.wjoin(path))
384 return self._repo._checknested(self._repo.wjoin(path))
385
385
386 def commit(self, text, user, date):
386 def commit(self, text, user, date):
387 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
387 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
388 n = self._repo.commit(text, user, date)
388 n = self._repo.commit(text, user, date)
389 if not n:
389 if not n:
390 return self._repo['.'].hex() # different version checked out
390 return self._repo['.'].hex() # different version checked out
391 return node.hex(n)
391 return node.hex(n)
392
392
393 def remove(self):
393 def remove(self):
394 # we can't fully delete the repository as it may contain
394 # we can't fully delete the repository as it may contain
395 # local-only history
395 # local-only history
396 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
396 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
397 hg.clean(self._repo, node.nullid, False)
397 hg.clean(self._repo, node.nullid, False)
398
398
399 def _get(self, state):
399 def _get(self, state):
400 source, revision, kind = state
400 source, revision, kind = state
401 try:
401 try:
402 self._repo.lookup(revision)
402 self._repo.lookup(revision)
403 except error.RepoError:
403 except error.RepoError:
404 self._repo._subsource = source
404 self._repo._subsource = source
405 srcurl = _abssource(self._repo)
405 srcurl = _abssource(self._repo)
406 self._repo.ui.status(_('pulling subrepo %s from %s\n')
406 self._repo.ui.status(_('pulling subrepo %s from %s\n')
407 % (subrelpath(self), srcurl))
407 % (subrelpath(self), srcurl))
408 other = hg.repository(self._repo.ui, srcurl)
408 other = hg.repository(self._repo.ui, srcurl)
409 self._repo.pull(other)
409 self._repo.pull(other)
410
410
411 def get(self, state):
411 def get(self, state):
412 self._get(state)
412 self._get(state)
413 source, revision, kind = state
413 source, revision, kind = state
414 self._repo.ui.debug("getting subrepo %s\n" % self._path)
414 self._repo.ui.debug("getting subrepo %s\n" % self._path)
415 hg.clean(self._repo, revision, False)
415 hg.clean(self._repo, revision, False)
416
416
417 def merge(self, state):
417 def merge(self, state):
418 self._get(state)
418 self._get(state)
419 cur = self._repo['.']
419 cur = self._repo['.']
420 dst = self._repo[state[1]]
420 dst = self._repo[state[1]]
421 anc = dst.ancestor(cur)
421 anc = dst.ancestor(cur)
422 if anc == cur:
422 if anc == cur:
423 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
423 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
424 hg.update(self._repo, state[1])
424 hg.update(self._repo, state[1])
425 elif anc == dst:
425 elif anc == dst:
426 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
426 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
427 else:
427 else:
428 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
428 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
429 hg.merge(self._repo, state[1], remind=False)
429 hg.merge(self._repo, state[1], remind=False)
430
430
431 def push(self, force):
431 def push(self, force):
432 # push subrepos depth-first for coherent ordering
432 # push subrepos depth-first for coherent ordering
433 c = self._repo['']
433 c = self._repo['']
434 subs = c.substate # only repos that are committed
434 subs = c.substate # only repos that are committed
435 for s in sorted(subs):
435 for s in sorted(subs):
436 if not c.sub(s).push(force):
436 if not c.sub(s).push(force):
437 return False
437 return False
438
438
439 dsturl = _abssource(self._repo, True)
439 dsturl = _abssource(self._repo, True)
440 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
440 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
441 (subrelpath(self), dsturl))
441 (subrelpath(self), dsturl))
442 other = hg.repository(self._repo.ui, dsturl)
442 other = hg.repository(self._repo.ui, dsturl)
443 return self._repo.push(other, force)
443 return self._repo.push(other, force)
444
444
445 def outgoing(self, ui, dest, opts):
445 def outgoing(self, ui, dest, opts):
446 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
446 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
447
447
448 def incoming(self, ui, source, opts):
448 def incoming(self, ui, source, opts):
449 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
449 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
450
450
451 def files(self):
451 def files(self):
452 rev = self._state[1]
452 rev = self._state[1]
453 ctx = self._repo[rev]
453 ctx = self._repo[rev]
454 return ctx.manifest()
454 return ctx.manifest()
455
455
456 def filedata(self, name):
456 def filedata(self, name):
457 rev = self._state[1]
457 rev = self._state[1]
458 return self._repo[rev][name].data()
458 return self._repo[rev][name].data()
459
459
460 def fileflags(self, name):
460 def fileflags(self, name):
461 rev = self._state[1]
461 rev = self._state[1]
462 ctx = self._repo[rev]
462 ctx = self._repo[rev]
463 return ctx.flags(name)
463 return ctx.flags(name)
464
464
465
465
466 class svnsubrepo(abstractsubrepo):
466 class svnsubrepo(abstractsubrepo):
467 def __init__(self, ctx, path, state):
467 def __init__(self, ctx, path, state):
468 self._path = path
468 self._path = path
469 self._state = state
469 self._state = state
470 self._ctx = ctx
470 self._ctx = ctx
471 self._ui = ctx._repo.ui
471 self._ui = ctx._repo.ui
472
472
473 def _svncommand(self, commands, filename=''):
473 def _svncommand(self, commands, filename=''):
474 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
474 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
475 cmd = ['svn'] + commands + [path]
475 cmd = ['svn'] + commands + [path]
476 cmd = [util.shellquote(arg) for arg in cmd]
476 cmd = [util.shellquote(arg) for arg in cmd]
477 cmd = util.quotecommand(' '.join(cmd))
477 cmd = util.quotecommand(' '.join(cmd))
478 env = dict(os.environ)
478 env = dict(os.environ)
479 # Avoid localized output, preserve current locale for everything else.
479 # Avoid localized output, preserve current locale for everything else.
480 env['LC_MESSAGES'] = 'C'
480 env['LC_MESSAGES'] = 'C'
481 write, read, err = util.popen3(cmd, env=env, newlines=True)
481 write, read, err = util.popen3(cmd, env=env, newlines=True)
482 retdata = read.read()
482 retdata = read.read()
483 err = err.read().strip()
483 err = err.read().strip()
484 if err:
484 if err:
485 raise util.Abort(err)
485 raise util.Abort(err)
486 return retdata
486 return retdata
487
487
488 def _wcrev(self):
488 def _wcrev(self):
489 output = self._svncommand(['info', '--xml'])
489 output = self._svncommand(['info', '--xml'])
490 doc = xml.dom.minidom.parseString(output)
490 doc = xml.dom.minidom.parseString(output)
491 entries = doc.getElementsByTagName('entry')
491 entries = doc.getElementsByTagName('entry')
492 if not entries:
492 if not entries:
493 return 0
493 return '0'
494 return str(entries[0].getAttribute('revision')) or '0'
494 return str(entries[0].getAttribute('revision')) or '0'
495
495
496 def _wcchanged(self):
496 def _wcchanged(self):
497 """Return (changes, extchanges) where changes is True
497 """Return (changes, extchanges) where changes is True
498 if the working directory was changed, and extchanges is
498 if the working directory was changed, and extchanges is
499 True if any of these changes concern an external entry.
499 True if any of these changes concern an external entry.
500 """
500 """
501 output = self._svncommand(['status', '--xml'])
501 output = self._svncommand(['status', '--xml'])
502 externals, changes = [], []
502 externals, changes = [], []
503 doc = xml.dom.minidom.parseString(output)
503 doc = xml.dom.minidom.parseString(output)
504 for e in doc.getElementsByTagName('entry'):
504 for e in doc.getElementsByTagName('entry'):
505 s = e.getElementsByTagName('wc-status')
505 s = e.getElementsByTagName('wc-status')
506 if not s:
506 if not s:
507 continue
507 continue
508 item = s[0].getAttribute('item')
508 item = s[0].getAttribute('item')
509 props = s[0].getAttribute('props')
509 props = s[0].getAttribute('props')
510 path = e.getAttribute('path')
510 path = e.getAttribute('path')
511 if item == 'external':
511 if item == 'external':
512 externals.append(path)
512 externals.append(path)
513 if (item not in ('', 'normal', 'unversioned', 'external')
513 if (item not in ('', 'normal', 'unversioned', 'external')
514 or props not in ('', 'none')):
514 or props not in ('', 'none')):
515 changes.append(path)
515 changes.append(path)
516 for path in changes:
516 for path in changes:
517 for ext in externals:
517 for ext in externals:
518 if path == ext or path.startswith(ext + os.sep):
518 if path == ext or path.startswith(ext + os.sep):
519 return True, True
519 return True, True
520 return bool(changes), False
520 return bool(changes), False
521
521
522 def dirty(self):
522 def dirty(self):
523 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
523 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
524 return False
524 return False
525 return True
525 return True
526
526
527 def commit(self, text, user, date):
527 def commit(self, text, user, date):
528 # user and date are out of our hands since svn is centralized
528 # user and date are out of our hands since svn is centralized
529 changed, extchanged = self._wcchanged()
529 changed, extchanged = self._wcchanged()
530 if not changed:
530 if not changed:
531 return self._wcrev()
531 return self._wcrev()
532 if extchanged:
532 if extchanged:
533 # Do not try to commit externals
533 # Do not try to commit externals
534 raise util.Abort(_('cannot commit svn externals'))
534 raise util.Abort(_('cannot commit svn externals'))
535 commitinfo = self._svncommand(['commit', '-m', text])
535 commitinfo = self._svncommand(['commit', '-m', text])
536 self._ui.status(commitinfo)
536 self._ui.status(commitinfo)
537 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
537 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
538 if not newrev:
538 if not newrev:
539 raise util.Abort(commitinfo.splitlines()[-1])
539 raise util.Abort(commitinfo.splitlines()[-1])
540 newrev = newrev.groups()[0]
540 newrev = newrev.groups()[0]
541 self._ui.status(self._svncommand(['update', '-r', newrev]))
541 self._ui.status(self._svncommand(['update', '-r', newrev]))
542 return newrev
542 return newrev
543
543
544 def remove(self):
544 def remove(self):
545 if self.dirty():
545 if self.dirty():
546 self._ui.warn(_('not removing repo %s because '
546 self._ui.warn(_('not removing repo %s because '
547 'it has changes.\n' % self._path))
547 'it has changes.\n' % self._path))
548 return
548 return
549 self._ui.note(_('removing subrepo %s\n') % self._path)
549 self._ui.note(_('removing subrepo %s\n') % self._path)
550 shutil.rmtree(self._ctx.repo.join(self._path))
550 shutil.rmtree(self._ctx.repo.join(self._path))
551
551
552 def get(self, state):
552 def get(self, state):
553 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
553 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
554 if not re.search('Checked out revision [0-9]+.', status):
554 if not re.search('Checked out revision [0-9]+.', status):
555 raise util.Abort(status.splitlines()[-1])
555 raise util.Abort(status.splitlines()[-1])
556 self._ui.status(status)
556 self._ui.status(status)
557
557
558 def merge(self, state):
558 def merge(self, state):
559 old = int(self._state[1])
559 old = int(self._state[1])
560 new = int(state[1])
560 new = int(state[1])
561 if new > old:
561 if new > old:
562 self.get(state)
562 self.get(state)
563
563
564 def push(self, force):
564 def push(self, force):
565 # push is a no-op for SVN
565 # push is a no-op for SVN
566 return True
566 return True
567
567
568 def files(self):
568 def files(self):
569 output = self._svncommand(['list'])
569 output = self._svncommand(['list'])
570 # This works because svn forbids \n in filenames.
570 # This works because svn forbids \n in filenames.
571 return output.splitlines()
571 return output.splitlines()
572
572
573 def filedata(self, name):
573 def filedata(self, name):
574 return self._svncommand(['cat'], name)
574 return self._svncommand(['cat'], name)
575
575
576
576
577 types = {
577 types = {
578 'hg': hgsubrepo,
578 'hg': hgsubrepo,
579 'svn': svnsubrepo,
579 'svn': svnsubrepo,
580 }
580 }
@@ -1,289 +1,287 b''
1 $ HGMERGE=true; export HGMERGE
2
3 $ hg init basic
1 $ hg init basic
4 $ cd basic
2 $ cd basic
5
3
6 should complain
4 should complain
7
5
8 $ hg backout
6 $ hg backout
9 abort: please specify a revision to backout
7 abort: please specify a revision to backout
10 [255]
8 [255]
11 $ hg backout -r 0 0
9 $ hg backout -r 0 0
12 abort: please specify just one revision
10 abort: please specify just one revision
13 [255]
11 [255]
14
12
15 basic operation
13 basic operation
16
14
17 $ echo a > a
15 $ echo a > a
18 $ hg commit -d '0 0' -A -m a
16 $ hg commit -d '0 0' -A -m a
19 adding a
17 adding a
20 $ echo b >> a
18 $ echo b >> a
21 $ hg commit -d '1 0' -m b
19 $ hg commit -d '1 0' -m b
22
20
23 $ hg backout -d '2 0' tip
21 $ hg backout -d '2 0' tip --tool=true
24 reverting a
22 reverting a
25 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
23 changeset 2:2929462c3dff backs out changeset 1:a820f4f40a57
26 $ cat a
24 $ cat a
27 a
25 a
28
26
29 file that was removed is recreated
27 file that was removed is recreated
30
28
31 $ cd ..
29 $ cd ..
32 $ hg init remove
30 $ hg init remove
33 $ cd remove
31 $ cd remove
34
32
35 $ echo content > a
33 $ echo content > a
36 $ hg commit -d '0 0' -A -m a
34 $ hg commit -d '0 0' -A -m a
37 adding a
35 adding a
38
36
39 $ hg rm a
37 $ hg rm a
40 $ hg commit -d '1 0' -m b
38 $ hg commit -d '1 0' -m b
41
39
42 $ hg backout -d '2 0' tip
40 $ hg backout -d '2 0' tip --tool=true
43 adding a
41 adding a
44 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
42 changeset 2:de31bdc76c0d backs out changeset 1:76862dcce372
45 $ cat a
43 $ cat a
46 content
44 content
47
45
48 backout of backout is as if nothing happened
46 backout of backout is as if nothing happened
49
47
50 $ hg backout -d '3 0' --merge tip
48 $ hg backout -d '3 0' --merge tip --tool=true
51 removing a
49 removing a
52 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
50 changeset 3:7f6d0f120113 backs out changeset 2:de31bdc76c0d
53 $ cat a 2>/dev/null || echo cat: a: No such file or directory
51 $ cat a 2>/dev/null || echo cat: a: No such file or directory
54 cat: a: No such file or directory
52 cat: a: No such file or directory
55
53
56 across branch
54 across branch
57
55
58 $ cd ..
56 $ cd ..
59 $ hg init branch
57 $ hg init branch
60 $ cd branch
58 $ cd branch
61 $ echo a > a
59 $ echo a > a
62 $ hg ci -Am0
60 $ hg ci -Am0
63 adding a
61 adding a
64 $ echo b > b
62 $ echo b > b
65 $ hg ci -Am1
63 $ hg ci -Am1
66 adding b
64 adding b
67 $ hg co -C 0
65 $ hg co -C 0
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
66 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
69
67
70 should fail
68 should fail
71
69
72 $ hg backout 1
70 $ hg backout 1
73 abort: cannot backout change on a different branch
71 abort: cannot backout change on a different branch
74 [255]
72 [255]
75 $ echo c > c
73 $ echo c > c
76 $ hg ci -Am2
74 $ hg ci -Am2
77 adding c
75 adding c
78 created new head
76 created new head
79
77
80 should fail
78 should fail
81
79
82 $ hg backout 1
80 $ hg backout 1
83 abort: cannot backout change on a different branch
81 abort: cannot backout change on a different branch
84 [255]
82 [255]
85
83
86 backout with merge
84 backout with merge
87
85
88 $ cd ..
86 $ cd ..
89 $ hg init merge
87 $ hg init merge
90 $ cd merge
88 $ cd merge
91
89
92 $ echo line 1 > a
90 $ echo line 1 > a
93 $ echo line 2 >> a
91 $ echo line 2 >> a
94 $ hg commit -d '0 0' -A -m a
92 $ hg commit -d '0 0' -A -m a
95 adding a
93 adding a
96
94
97 remove line 1
95 remove line 1
98
96
99 $ echo line 2 > a
97 $ echo line 2 > a
100 $ hg commit -d '1 0' -m b
98 $ hg commit -d '1 0' -m b
101
99
102 $ echo line 3 >> a
100 $ echo line 3 >> a
103 $ hg commit -d '2 0' -m c
101 $ hg commit -d '2 0' -m c
104
102
105 $ hg backout --merge -d '3 0' 1
103 $ hg backout --merge -d '3 0' 1 --tool=true
106 reverting a
104 reverting a
107 created new head
105 created new head
108 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
106 changeset 3:26b8ccb9ad91 backs out changeset 1:5a50a024c182
109 merging with changeset 3:26b8ccb9ad91
107 merging with changeset 3:26b8ccb9ad91
110 merging a
108 merging a
111 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
109 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
112 (branch merge, don't forget to commit)
110 (branch merge, don't forget to commit)
113 $ hg commit -d '4 0' -m d
111 $ hg commit -d '4 0' -m d
114
112
115 check line 1 is back
113 check line 1 is back
116
114
117 $ cat a
115 $ cat a
118 line 1
116 line 1
119 line 2
117 line 2
120 line 3
118 line 3
121
119
122 backout should not back out subsequent changesets
120 backout should not back out subsequent changesets
123
121
124 $ hg init onecs
122 $ hg init onecs
125 $ cd onecs
123 $ cd onecs
126 $ echo 1 > a
124 $ echo 1 > a
127 $ hg commit -d '0 0' -A -m a
125 $ hg commit -d '0 0' -A -m a
128 adding a
126 adding a
129 $ echo 2 >> a
127 $ echo 2 >> a
130 $ hg commit -d '1 0' -m b
128 $ hg commit -d '1 0' -m b
131 $ echo 1 > b
129 $ echo 1 > b
132 $ hg commit -d '2 0' -A -m c
130 $ hg commit -d '2 0' -A -m c
133 adding b
131 adding b
134
132
135 without --merge
133 without --merge
136 $ hg backout -d '3 0' 1
134 $ hg backout -d '3 0' 1 --tool=true
137 reverting a
135 reverting a
138 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 $ hg locate b
137 $ hg locate b
140 b
138 b
141 $ hg update -C tip
139 $ hg update -C tip
142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 $ hg locate b
141 $ hg locate b
144 b
142 b
145
143
146 with --merge
144 with --merge
147 $ hg backout --merge -d '3 0' 1
145 $ hg backout --merge -d '3 0' 1 --tool=true
148 reverting a
146 reverting a
149 created new head
147 created new head
150 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
148 changeset 3:3202beb76721 backs out changeset 1:22bca4c721e5
151 merging with changeset 3:3202beb76721
149 merging with changeset 3:3202beb76721
152 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
150 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 (branch merge, don't forget to commit)
151 (branch merge, don't forget to commit)
154 $ hg locate b
152 $ hg locate b
155 b
153 b
156 $ hg update -C tip
154 $ hg update -C tip
157 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
155 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
158 $ hg locate b
156 $ hg locate b
159 [1]
157 [1]
160
158
161 $ cd ..
159 $ cd ..
162 $ hg init m
160 $ hg init m
163 $ cd m
161 $ cd m
164 $ echo a > a
162 $ echo a > a
165 $ hg commit -d '0 0' -A -m a
163 $ hg commit -d '0 0' -A -m a
166 adding a
164 adding a
167 $ echo b > b
165 $ echo b > b
168 $ hg commit -d '1 0' -A -m b
166 $ hg commit -d '1 0' -A -m b
169 adding b
167 adding b
170 $ echo c > c
168 $ echo c > c
171 $ hg commit -d '2 0' -A -m b
169 $ hg commit -d '2 0' -A -m b
172 adding c
170 adding c
173 $ hg update 1
171 $ hg update 1
174 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
172 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
175 $ echo d > d
173 $ echo d > d
176 $ hg commit -d '3 0' -A -m c
174 $ hg commit -d '3 0' -A -m c
177 adding d
175 adding d
178 created new head
176 created new head
179 $ hg merge 2
177 $ hg merge 2
180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
181 (branch merge, don't forget to commit)
179 (branch merge, don't forget to commit)
182 $ hg commit -d '4 0' -A -m d
180 $ hg commit -d '4 0' -A -m d
183
181
184 backout of merge should fail
182 backout of merge should fail
185
183
186 $ hg backout 4
184 $ hg backout 4
187 abort: cannot backout a merge changeset without --parent
185 abort: cannot backout a merge changeset without --parent
188 [255]
186 [255]
189
187
190 backout of merge with bad parent should fail
188 backout of merge with bad parent should fail
191
189
192 $ hg backout --parent 0 4
190 $ hg backout --parent 0 4
193 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
191 abort: cb9a9f314b8b is not a parent of b2f3bb92043e
194 [255]
192 [255]
195
193
196 backout of non-merge with parent should fail
194 backout of non-merge with parent should fail
197
195
198 $ hg backout --parent 0 3
196 $ hg backout --parent 0 3
199 abort: cannot use --parent on non-merge changeset
197 abort: cannot use --parent on non-merge changeset
200 [255]
198 [255]
201
199
202 backout with valid parent should be ok
200 backout with valid parent should be ok
203
201
204 $ hg backout -d '5 0' --parent 2 4
202 $ hg backout -d '5 0' --parent 2 4 --tool=true
205 removing d
203 removing d
206 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
204 changeset 5:10e5328c8435 backs out changeset 4:b2f3bb92043e
207
205
208 $ hg rollback
206 $ hg rollback
209 rolling back to revision 4 (undo commit)
207 rolling back to revision 4 (undo commit)
210 $ hg update -C
208 $ hg update -C
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212
210
213 $ hg backout -d '6 0' --parent 3 4
211 $ hg backout -d '6 0' --parent 3 4 --tool=true
214 removing c
212 removing c
215 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
213 changeset 5:033590168430 backs out changeset 4:b2f3bb92043e
216
214
217 $ cd ..
215 $ cd ..
218
216
219 named branches
217 named branches
220
218
221 $ hg init named_branches
219 $ hg init named_branches
222 $ cd named_branches
220 $ cd named_branches
223
221
224 $ echo default > default
222 $ echo default > default
225 $ hg ci -d '0 0' -Am default
223 $ hg ci -d '0 0' -Am default
226 adding default
224 adding default
227 $ hg branch branch1
225 $ hg branch branch1
228 marked working directory as branch branch1
226 marked working directory as branch branch1
229 $ echo branch1 > file1
227 $ echo branch1 > file1
230 $ hg ci -d '1 0' -Am file1
228 $ hg ci -d '1 0' -Am file1
231 adding file1
229 adding file1
232 $ hg branch branch2
230 $ hg branch branch2
233 marked working directory as branch branch2
231 marked working directory as branch branch2
234 $ echo branch2 > file2
232 $ echo branch2 > file2
235 $ hg ci -d '2 0' -Am file2
233 $ hg ci -d '2 0' -Am file2
236 adding file2
234 adding file2
237
235
238 without --merge
236 without --merge
239 $ hg backout -r 1
237 $ hg backout -r 1 --tool=true
240 removing file1
238 removing file1
241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 $ hg branch
240 $ hg branch
243 branch2
241 branch2
244 $ hg status -A
242 $ hg status -A
245 R file1
243 R file1
246 C default
244 C default
247 C file2
245 C file2
248
246
249 with --merge
247 with --merge
250 $ hg update -qC
248 $ hg update -qC
251 $ hg backout --merge -d '3 0' -r 1 -m 'backout on branch1'
249 $ hg backout --merge -d '3 0' -r 1 -m 'backout on branch1' --tool=true
252 removing file1
250 removing file1
253 created new head
251 created new head
254 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
252 changeset 3:d4e8f6db59fb backs out changeset 1:bf1602f437f3
255 merging with changeset 3:d4e8f6db59fb
253 merging with changeset 3:d4e8f6db59fb
256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
254 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
257 (branch merge, don't forget to commit)
255 (branch merge, don't forget to commit)
258 $ hg update -q -C 2
256 $ hg update -q -C 2
259
257
260 on branch2 with branch1 not merged, so file1 should still exist:
258 on branch2 with branch1 not merged, so file1 should still exist:
261
259
262 $ hg id
260 $ hg id
263 45bbcd363bf0 (branch2)
261 45bbcd363bf0 (branch2)
264 $ hg st -A
262 $ hg st -A
265 C default
263 C default
266 C file1
264 C file1
267 C file2
265 C file2
268
266
269 on branch2 with branch1 merged, so file1 should be gone:
267 on branch2 with branch1 merged, so file1 should be gone:
270
268
271 $ hg merge
269 $ hg merge
272 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
270 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
273 (branch merge, don't forget to commit)
271 (branch merge, don't forget to commit)
274 $ hg ci -d '4 0' -m 'merge backout of branch1'
272 $ hg ci -d '4 0' -m 'merge backout of branch1'
275 $ hg id
273 $ hg id
276 22149cdde76d (branch2) tip
274 22149cdde76d (branch2) tip
277 $ hg st -A
275 $ hg st -A
278 C default
276 C default
279 C file2
277 C file2
280
278
281 on branch1, so no file1 and file2:
279 on branch1, so no file1 and file2:
282
280
283 $ hg co -C branch1
281 $ hg co -C branch1
284 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
282 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
285 $ hg id
283 $ hg id
286 bf1602f437f3 (branch1)
284 bf1602f437f3 (branch1)
287 $ hg st -A
285 $ hg st -A
288 C default
286 C default
289 C file1
287 C file1
@@ -1,249 +1,249 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 branch
9 branch
10 branches
10 branches
11 bundle
11 bundle
12 cat
12 cat
13 clone
13 clone
14 commit
14 commit
15 copy
15 copy
16 diff
16 diff
17 export
17 export
18 forget
18 forget
19 grep
19 grep
20 heads
20 heads
21 help
21 help
22 identify
22 identify
23 import
23 import
24 incoming
24 incoming
25 init
25 init
26 locate
26 locate
27 log
27 log
28 manifest
28 manifest
29 merge
29 merge
30 outgoing
30 outgoing
31 parents
31 parents
32 paths
32 paths
33 pull
33 pull
34 push
34 push
35 recover
35 recover
36 remove
36 remove
37 rename
37 rename
38 resolve
38 resolve
39 revert
39 revert
40 rollback
40 rollback
41 root
41 root
42 serve
42 serve
43 showconfig
43 showconfig
44 status
44 status
45 summary
45 summary
46 tag
46 tag
47 tags
47 tags
48 tip
48 tip
49 unbundle
49 unbundle
50 update
50 update
51 verify
51 verify
52 version
52 version
53
53
54 Show all commands that start with "a"
54 Show all commands that start with "a"
55 $ hg debugcomplete a
55 $ hg debugcomplete a
56 add
56 add
57 addremove
57 addremove
58 annotate
58 annotate
59 archive
59 archive
60
60
61 Do not show debug commands if there are other candidates
61 Do not show debug commands if there are other candidates
62 $ hg debugcomplete d
62 $ hg debugcomplete d
63 diff
63 diff
64
64
65 Show debug commands if there are no other candidates
65 Show debug commands if there are no other candidates
66 $ hg debugcomplete debug
66 $ hg debugcomplete debug
67 debugancestor
67 debugancestor
68 debugbuilddag
68 debugbuilddag
69 debugcheckstate
69 debugcheckstate
70 debugcommands
70 debugcommands
71 debugcomplete
71 debugcomplete
72 debugconfig
72 debugconfig
73 debugdag
73 debugdag
74 debugdata
74 debugdata
75 debugdate
75 debugdate
76 debugfsinfo
76 debugfsinfo
77 debugindex
77 debugindex
78 debugindexdot
78 debugindexdot
79 debuginstall
79 debuginstall
80 debugpushkey
80 debugpushkey
81 debugrebuildstate
81 debugrebuildstate
82 debugrename
82 debugrename
83 debugrevspec
83 debugrevspec
84 debugsetparents
84 debugsetparents
85 debugstate
85 debugstate
86 debugsub
86 debugsub
87 debugwalk
87 debugwalk
88
88
89 Do not show the alias of a debug command if there are other candidates
89 Do not show the alias of a debug command if there are other candidates
90 (this should hide rawcommit)
90 (this should hide rawcommit)
91 $ hg debugcomplete r
91 $ hg debugcomplete r
92 recover
92 recover
93 remove
93 remove
94 rename
94 rename
95 resolve
95 resolve
96 revert
96 revert
97 rollback
97 rollback
98 root
98 root
99 Show the alias of a debug command if there are no other candidates
99 Show the alias of a debug command if there are no other candidates
100 $ hg debugcomplete rawc
100 $ hg debugcomplete rawc
101
101
102
102
103 Show the global options
103 Show the global options
104 $ hg debugcomplete --options | sort
104 $ hg debugcomplete --options | sort
105 --config
105 --config
106 --cwd
106 --cwd
107 --debug
107 --debug
108 --debugger
108 --debugger
109 --encoding
109 --encoding
110 --encodingmode
110 --encodingmode
111 --help
111 --help
112 --noninteractive
112 --noninteractive
113 --profile
113 --profile
114 --quiet
114 --quiet
115 --repository
115 --repository
116 --time
116 --time
117 --traceback
117 --traceback
118 --verbose
118 --verbose
119 --version
119 --version
120 -R
120 -R
121 -h
121 -h
122 -q
122 -q
123 -v
123 -v
124 -y
124 -y
125
125
126 Show the options for the "serve" command
126 Show the options for the "serve" command
127 $ hg debugcomplete --options serve | sort
127 $ hg debugcomplete --options serve | sort
128 --accesslog
128 --accesslog
129 --address
129 --address
130 --certificate
130 --certificate
131 --config
131 --config
132 --cwd
132 --cwd
133 --daemon
133 --daemon
134 --daemon-pipefds
134 --daemon-pipefds
135 --debug
135 --debug
136 --debugger
136 --debugger
137 --encoding
137 --encoding
138 --encodingmode
138 --encodingmode
139 --errorlog
139 --errorlog
140 --help
140 --help
141 --ipv6
141 --ipv6
142 --name
142 --name
143 --noninteractive
143 --noninteractive
144 --pid-file
144 --pid-file
145 --port
145 --port
146 --prefix
146 --prefix
147 --profile
147 --profile
148 --quiet
148 --quiet
149 --repository
149 --repository
150 --stdio
150 --stdio
151 --style
151 --style
152 --templates
152 --templates
153 --time
153 --time
154 --traceback
154 --traceback
155 --verbose
155 --verbose
156 --version
156 --version
157 --web-conf
157 --web-conf
158 -6
158 -6
159 -A
159 -A
160 -E
160 -E
161 -R
161 -R
162 -a
162 -a
163 -d
163 -d
164 -h
164 -h
165 -n
165 -n
166 -p
166 -p
167 -q
167 -q
168 -t
168 -t
169 -v
169 -v
170 -y
170 -y
171
171
172 Show an error if we use --options with an ambiguous abbreviation
172 Show an error if we use --options with an ambiguous abbreviation
173 $ hg debugcomplete --options s
173 $ hg debugcomplete --options s
174 hg: command 's' is ambiguous:
174 hg: command 's' is ambiguous:
175 serve showconfig status summary
175 serve showconfig status summary
176 [255]
176 [255]
177
177
178 Show all commands + options
178 Show all commands + options
179 $ hg debugcommands
179 $ hg debugcommands
180 add: include, exclude, subrepos, dry-run
180 add: include, exclude, subrepos, dry-run
181 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
181 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, include, exclude
182 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd
182 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd
183 commit: addremove, close-branch, include, exclude, message, logfile, date, user
183 commit: addremove, close-branch, include, exclude, message, logfile, date, user
184 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
184 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
185 export: output, switch-parent, rev, text, git, nodates
185 export: output, switch-parent, rev, text, git, nodates
186 forget: include, exclude
186 forget: include, exclude
187 init: ssh, remotecmd
187 init: ssh, remotecmd
188 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
188 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, style, template, include, exclude
189 merge: force, tool, rev, preview
189 merge: force, tool, rev, preview
190 pull: update, force, rev, branch, ssh, remotecmd
190 pull: update, force, rev, branch, ssh, remotecmd
191 push: force, rev, branch, new-branch, ssh, remotecmd
191 push: force, rev, branch, new-branch, ssh, remotecmd
192 remove: after, force, include, exclude
192 remove: after, force, include, exclude
193 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
193 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
194 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
194 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
195 summary: remote
195 summary: remote
196 update: clean, check, date, rev
196 update: clean, check, date, rev
197 addremove: similarity, include, exclude, dry-run
197 addremove: similarity, include, exclude, dry-run
198 archive: no-decode, prefix, rev, type, subrepos, include, exclude
198 archive: no-decode, prefix, rev, type, subrepos, include, exclude
199 backout: merge, parent, rev, include, exclude, message, logfile, date, user
199 backout: merge, parent, tool, rev, include, exclude, message, logfile, date, user
200 bisect: reset, good, bad, skip, command, noupdate
200 bisect: reset, good, bad, skip, command, noupdate
201 branch: force, clean
201 branch: force, clean
202 branches: active, closed
202 branches: active, closed
203 bundle: force, rev, branch, base, all, type, ssh, remotecmd
203 bundle: force, rev, branch, base, all, type, ssh, remotecmd
204 cat: output, rev, decode, include, exclude
204 cat: output, rev, decode, include, exclude
205 copy: after, force, include, exclude, dry-run
205 copy: after, force, include, exclude, dry-run
206 debugancestor:
206 debugancestor:
207 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
207 debugbuilddag: mergeable-file, appended-file, overwritten-file, new-file
208 debugcheckstate:
208 debugcheckstate:
209 debugcommands:
209 debugcommands:
210 debugcomplete: options
210 debugcomplete: options
211 debugdag: tags, branches, dots, spaces
211 debugdag: tags, branches, dots, spaces
212 debugdata:
212 debugdata:
213 debugdate: extended
213 debugdate: extended
214 debugfsinfo:
214 debugfsinfo:
215 debugindex:
215 debugindex:
216 debugindexdot:
216 debugindexdot:
217 debuginstall:
217 debuginstall:
218 debugpushkey:
218 debugpushkey:
219 debugrebuildstate: rev
219 debugrebuildstate: rev
220 debugrename: rev
220 debugrename: rev
221 debugrevspec:
221 debugrevspec:
222 debugsetparents:
222 debugsetparents:
223 debugstate: nodates
223 debugstate: nodates
224 debugsub: rev
224 debugsub: rev
225 debugwalk: include, exclude
225 debugwalk: include, exclude
226 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
226 grep: print0, all, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
227 heads: rev, topo, active, closed, style, template
227 heads: rev, topo, active, closed, style, template
228 help:
228 help:
229 identify: rev, num, id, branch, tags
229 identify: rev, num, id, branch, tags
230 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
230 import: strip, base, force, no-commit, exact, import-branch, message, logfile, date, user, similarity
231 incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, subrepos
231 incoming: force, newest-first, bundle, rev, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, subrepos
232 locate: rev, print0, fullpath, include, exclude
232 locate: rev, print0, fullpath, include, exclude
233 manifest: rev
233 manifest: rev
234 outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, subrepos
234 outgoing: force, rev, newest-first, branch, patch, git, limit, no-merges, stat, style, template, ssh, remotecmd, subrepos
235 parents: rev, style, template
235 parents: rev, style, template
236 paths:
236 paths:
237 recover:
237 recover:
238 rename: after, force, include, exclude, dry-run
238 rename: after, force, include, exclude, dry-run
239 resolve: all, list, mark, unmark, tool, no-status, include, exclude
239 resolve: all, list, mark, unmark, tool, no-status, include, exclude
240 revert: all, date, rev, no-backup, include, exclude, dry-run
240 revert: all, date, rev, no-backup, include, exclude, dry-run
241 rollback: dry-run
241 rollback: dry-run
242 root:
242 root:
243 showconfig: untrusted
243 showconfig: untrusted
244 tag: force, local, rev, remove, edit, message, date, user
244 tag: force, local, rev, remove, edit, message, date, user
245 tags:
245 tags:
246 tip: patch, git, style, template
246 tip: patch, git, style, template
247 unbundle: update
247 unbundle: update
248 verify:
248 verify:
249 version:
249 version:
@@ -1,356 +1,365 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > transplant=
3 > transplant=
4 > EOF
4 > EOF
5
5
6 $ hg init t
6 $ hg init t
7 $ cd t
7 $ cd t
8 $ echo r1 > r1
8 $ echo r1 > r1
9 $ hg ci -Amr1 -d'0 0'
9 $ hg ci -Amr1 -d'0 0'
10 adding r1
10 adding r1
11 $ echo r2 > r2
11 $ echo r2 > r2
12 $ hg ci -Amr2 -d'1 0'
12 $ hg ci -Amr2 -d'1 0'
13 adding r2
13 adding r2
14 $ hg up 0
14 $ hg up 0
15 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
15 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
16
16
17 $ echo b1 > b1
17 $ echo b1 > b1
18 $ hg ci -Amb1 -d '0 0'
18 $ hg ci -Amb1 -d '0 0'
19 adding b1
19 adding b1
20 created new head
20 created new head
21 $ echo b2 > b2
21 $ echo b2 > b2
22 $ hg ci -Amb2 -d '1 0'
22 $ hg ci -Amb2 -d '1 0'
23 adding b2
23 adding b2
24 $ echo b3 > b3
24 $ echo b3 > b3
25 $ hg ci -Amb3 -d '2 0'
25 $ hg ci -Amb3 -d '2 0'
26 adding b3
26 adding b3
27
27
28 $ hg log --template '{rev} {parents} {desc}\n'
28 $ hg log --template '{rev} {parents} {desc}\n'
29 4 b3
29 4 b3
30 3 b2
30 3 b2
31 2 0:17ab29e464c6 b1
31 2 0:17ab29e464c6 b1
32 1 r2
32 1 r2
33 0 r1
33 0 r1
34
34
35 $ hg clone . ../rebase
35 $ hg clone . ../rebase
36 updating to branch default
36 updating to branch default
37 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 $ cd ../rebase
38 $ cd ../rebase
39
39
40 $ hg up -C 1
40 $ hg up -C 1
41 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
41 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
42
42
43 rebase b onto r1
43 rebase b onto r1
44
44
45 $ hg transplant -a -b tip
45 $ hg transplant -a -b tip
46 applying 37a1297eb21b
46 applying 37a1297eb21b
47 37a1297eb21b transplanted to e234d668f844
47 37a1297eb21b transplanted to e234d668f844
48 applying 722f4667af76
48 applying 722f4667af76
49 722f4667af76 transplanted to 539f377d78df
49 722f4667af76 transplanted to 539f377d78df
50 applying a53251cdf717
50 applying a53251cdf717
51 a53251cdf717 transplanted to ffd6818a3975
51 a53251cdf717 transplanted to ffd6818a3975
52 $ hg log --template '{rev} {parents} {desc}\n'
52 $ hg log --template '{rev} {parents} {desc}\n'
53 7 b3
53 7 b3
54 6 b2
54 6 b2
55 5 1:d11e3596cc1a b1
55 5 1:d11e3596cc1a b1
56 4 b3
56 4 b3
57 3 b2
57 3 b2
58 2 0:17ab29e464c6 b1
58 2 0:17ab29e464c6 b1
59 1 r2
59 1 r2
60 0 r1
60 0 r1
61
61
62 test transplanted revset
63
64 $ hg log -r 'transplanted()' --template '{rev} {parents} {desc}\n'
65 5 1:d11e3596cc1a b1
66 6 b2
67 7 b3
68 $ hg help revsets | grep transplanted
69 "transplanted(set)"
70
62 $ hg clone ../t ../prune
71 $ hg clone ../t ../prune
63 updating to branch default
72 updating to branch default
64 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 $ cd ../prune
74 $ cd ../prune
66
75
67 $ hg up -C 1
76 $ hg up -C 1
68 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
77 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
69
78
70 rebase b onto r1, skipping b2
79 rebase b onto r1, skipping b2
71
80
72 $ hg transplant -a -b tip -p 3
81 $ hg transplant -a -b tip -p 3
73 applying 37a1297eb21b
82 applying 37a1297eb21b
74 37a1297eb21b transplanted to e234d668f844
83 37a1297eb21b transplanted to e234d668f844
75 applying a53251cdf717
84 applying a53251cdf717
76 a53251cdf717 transplanted to 7275fda4d04f
85 a53251cdf717 transplanted to 7275fda4d04f
77 $ hg log --template '{rev} {parents} {desc}\n'
86 $ hg log --template '{rev} {parents} {desc}\n'
78 6 b3
87 6 b3
79 5 1:d11e3596cc1a b1
88 5 1:d11e3596cc1a b1
80 4 b3
89 4 b3
81 3 b2
90 3 b2
82 2 0:17ab29e464c6 b1
91 2 0:17ab29e464c6 b1
83 1 r2
92 1 r2
84 0 r1
93 0 r1
85
94
86
95
87 remote transplant
96 remote transplant
88
97
89 $ hg clone -r 1 ../t ../remote
98 $ hg clone -r 1 ../t ../remote
90 requesting all changes
99 requesting all changes
91 adding changesets
100 adding changesets
92 adding manifests
101 adding manifests
93 adding file changes
102 adding file changes
94 added 2 changesets with 2 changes to 2 files
103 added 2 changesets with 2 changes to 2 files
95 updating to branch default
104 updating to branch default
96 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 $ cd ../remote
106 $ cd ../remote
98 $ hg transplant --log -s ../t 2 4
107 $ hg transplant --log -s ../t 2 4
99 searching for changes
108 searching for changes
100 applying 37a1297eb21b
109 applying 37a1297eb21b
101 37a1297eb21b transplanted to c19cf0ccb069
110 37a1297eb21b transplanted to c19cf0ccb069
102 applying a53251cdf717
111 applying a53251cdf717
103 a53251cdf717 transplanted to f7fe5bf98525
112 a53251cdf717 transplanted to f7fe5bf98525
104 $ hg log --template '{rev} {parents} {desc}\n'
113 $ hg log --template '{rev} {parents} {desc}\n'
105 3 b3
114 3 b3
106 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
115 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
107 2 b1
116 2 b1
108 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
117 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
109 1 r2
118 1 r2
110 0 r1
119 0 r1
111
120
112 skip previous transplants
121 skip previous transplants
113
122
114 $ hg transplant -s ../t -a -b 4
123 $ hg transplant -s ../t -a -b 4
115 searching for changes
124 searching for changes
116 applying 722f4667af76
125 applying 722f4667af76
117 722f4667af76 transplanted to 47156cd86c0b
126 722f4667af76 transplanted to 47156cd86c0b
118 $ hg log --template '{rev} {parents} {desc}\n'
127 $ hg log --template '{rev} {parents} {desc}\n'
119 4 b2
128 4 b2
120 3 b3
129 3 b3
121 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
130 (transplanted from a53251cdf717679d1907b289f991534be05c997a)
122 2 b1
131 2 b1
123 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
132 (transplanted from 37a1297eb21b3ef5c5d2ffac22121a0988ed9f21)
124 1 r2
133 1 r2
125 0 r1
134 0 r1
126
135
127 skip local changes transplanted to the source
136 skip local changes transplanted to the source
128
137
129 $ echo b4 > b4
138 $ echo b4 > b4
130 $ hg ci -Amb4 -d '3 0'
139 $ hg ci -Amb4 -d '3 0'
131 adding b4
140 adding b4
132 $ hg clone ../t ../pullback
141 $ hg clone ../t ../pullback
133 updating to branch default
142 updating to branch default
134 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
135 $ cd ../pullback
144 $ cd ../pullback
136 $ hg transplant -s ../remote -a -b tip
145 $ hg transplant -s ../remote -a -b tip
137 searching for changes
146 searching for changes
138 applying 4333daefcb15
147 applying 4333daefcb15
139 4333daefcb15 transplanted to 5f42c04e07cc
148 4333daefcb15 transplanted to 5f42c04e07cc
140
149
141
150
142 remote transplant with pull
151 remote transplant with pull
143
152
144 $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
153 $ hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
145 $ cat ../t.pid >> $DAEMON_PIDS
154 $ cat ../t.pid >> $DAEMON_PIDS
146
155
147 $ hg clone -r 0 ../t ../rp
156 $ hg clone -r 0 ../t ../rp
148 requesting all changes
157 requesting all changes
149 adding changesets
158 adding changesets
150 adding manifests
159 adding manifests
151 adding file changes
160 adding file changes
152 added 1 changesets with 1 changes to 1 files
161 added 1 changesets with 1 changes to 1 files
153 updating to branch default
162 updating to branch default
154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 $ cd ../rp
164 $ cd ../rp
156 $ hg transplant -s http://localhost:$HGPORT/ 2 4
165 $ hg transplant -s http://localhost:$HGPORT/ 2 4
157 searching for changes
166 searching for changes
158 searching for changes
167 searching for changes
159 adding changesets
168 adding changesets
160 adding manifests
169 adding manifests
161 adding file changes
170 adding file changes
162 added 1 changesets with 1 changes to 1 files
171 added 1 changesets with 1 changes to 1 files
163 applying a53251cdf717
172 applying a53251cdf717
164 a53251cdf717 transplanted to 8d9279348abb
173 a53251cdf717 transplanted to 8d9279348abb
165 $ hg log --template '{rev} {parents} {desc}\n'
174 $ hg log --template '{rev} {parents} {desc}\n'
166 2 b3
175 2 b3
167 1 b1
176 1 b1
168 0 r1
177 0 r1
169
178
170 transplant --continue
179 transplant --continue
171
180
172 $ hg init ../tc
181 $ hg init ../tc
173 $ cd ../tc
182 $ cd ../tc
174 $ cat <<EOF > foo
183 $ cat <<EOF > foo
175 > foo
184 > foo
176 > bar
185 > bar
177 > baz
186 > baz
178 > EOF
187 > EOF
179 $ echo toremove > toremove
188 $ echo toremove > toremove
180 $ hg ci -Amfoo
189 $ hg ci -Amfoo
181 adding foo
190 adding foo
182 adding toremove
191 adding toremove
183 $ cat <<EOF > foo
192 $ cat <<EOF > foo
184 > foo2
193 > foo2
185 > bar2
194 > bar2
186 > baz2
195 > baz2
187 > EOF
196 > EOF
188 $ rm toremove
197 $ rm toremove
189 $ echo added > added
198 $ echo added > added
190 $ hg ci -Amfoo2
199 $ hg ci -Amfoo2
191 adding added
200 adding added
192 removing toremove
201 removing toremove
193 $ echo bar > bar
202 $ echo bar > bar
194 $ hg ci -Ambar
203 $ hg ci -Ambar
195 adding bar
204 adding bar
196 $ echo bar2 >> bar
205 $ echo bar2 >> bar
197 $ hg ci -mbar2
206 $ hg ci -mbar2
198 $ hg up 0
207 $ hg up 0
199 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
208 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
200 $ echo foobar > foo
209 $ echo foobar > foo
201 $ hg ci -mfoobar
210 $ hg ci -mfoobar
202 created new head
211 created new head
203 $ hg transplant 1:3
212 $ hg transplant 1:3
204 applying a1e30dd1b8e7
213 applying a1e30dd1b8e7
205 patching file foo
214 patching file foo
206 Hunk #1 FAILED at 0
215 Hunk #1 FAILED at 0
207 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
216 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
208 patch failed to apply
217 patch failed to apply
209 abort: fix up the merge and run hg transplant --continue
218 abort: fix up the merge and run hg transplant --continue
210 [255]
219 [255]
211
220
212 transplant -c shouldn't use an old changeset
221 transplant -c shouldn't use an old changeset
213
222
214 $ hg up -C
223 $ hg up -C
215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
216 $ rm added
225 $ rm added
217 $ hg transplant 1
226 $ hg transplant 1
218 applying a1e30dd1b8e7
227 applying a1e30dd1b8e7
219 patching file foo
228 patching file foo
220 Hunk #1 FAILED at 0
229 Hunk #1 FAILED at 0
221 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
230 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
222 patch failed to apply
231 patch failed to apply
223 abort: fix up the merge and run hg transplant --continue
232 abort: fix up the merge and run hg transplant --continue
224 [255]
233 [255]
225 $ hg transplant --continue
234 $ hg transplant --continue
226 a1e30dd1b8e7 transplanted as f1563cf27039
235 a1e30dd1b8e7 transplanted as f1563cf27039
227 $ hg transplant 1:3
236 $ hg transplant 1:3
228 skipping already applied revision 1:a1e30dd1b8e7
237 skipping already applied revision 1:a1e30dd1b8e7
229 applying 1739ac5f6139
238 applying 1739ac5f6139
230 1739ac5f6139 transplanted to d649c221319f
239 1739ac5f6139 transplanted to d649c221319f
231 applying 0282d5fbbe02
240 applying 0282d5fbbe02
232 0282d5fbbe02 transplanted to 77418277ccb3
241 0282d5fbbe02 transplanted to 77418277ccb3
233 $ hg locate
242 $ hg locate
234 added
243 added
235 bar
244 bar
236 foo
245 foo
237 $ cd ..
246 $ cd ..
238
247
239 Issue1111: Test transplant --merge
248 Issue1111: Test transplant --merge
240
249
241 $ hg init t1111
250 $ hg init t1111
242 $ cd t1111
251 $ cd t1111
243 $ echo a > a
252 $ echo a > a
244 $ hg ci -Am adda
253 $ hg ci -Am adda
245 adding a
254 adding a
246 $ echo b >> a
255 $ echo b >> a
247 $ hg ci -m appendb
256 $ hg ci -m appendb
248 $ echo c >> a
257 $ echo c >> a
249 $ hg ci -m appendc
258 $ hg ci -m appendc
250 $ hg up -C 0
259 $ hg up -C 0
251 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 $ echo d >> a
261 $ echo d >> a
253 $ hg ci -m appendd
262 $ hg ci -m appendd
254 created new head
263 created new head
255
264
256 tranplant
265 tranplant
257
266
258 $ hg transplant -m 1
267 $ hg transplant -m 1
259 applying 42dc4432fd35
268 applying 42dc4432fd35
260 1:42dc4432fd35 merged at a9f4acbac129
269 1:42dc4432fd35 merged at a9f4acbac129
261 $ cd ..
270 $ cd ..
262
271
263 test transplant into empty repository
272 test transplant into empty repository
264
273
265 $ hg init empty
274 $ hg init empty
266 $ cd empty
275 $ cd empty
267 $ hg transplant -s ../t -b tip -a
276 $ hg transplant -s ../t -b tip -a
268 requesting all changes
277 requesting all changes
269 adding changesets
278 adding changesets
270 adding manifests
279 adding manifests
271 adding file changes
280 adding file changes
272 added 4 changesets with 4 changes to 4 files
281 added 4 changesets with 4 changes to 4 files
273 $ cd ..
282 $ cd ..
274
283
275
284
276 test filter
285 test filter
277
286
278 $ hg init filter
287 $ hg init filter
279 $ cd filter
288 $ cd filter
280 $ cat <<'EOF' >test-filter
289 $ cat <<'EOF' >test-filter
281 > #!/bin/sh
290 > #!/bin/sh
282 > sed 's/r1/r2/' $1 > $1.new
291 > sed 's/r1/r2/' $1 > $1.new
283 > mv $1.new $1
292 > mv $1.new $1
284 > EOF
293 > EOF
285 $ chmod +x test-filter
294 $ chmod +x test-filter
286 $ hg transplant -s ../t -b tip -a --filter ./test-filter
295 $ hg transplant -s ../t -b tip -a --filter ./test-filter
287 filtering * (glob)
296 filtering * (glob)
288 applying 17ab29e464c6
297 applying 17ab29e464c6
289 17ab29e464c6 transplanted to e9ffc54ea104
298 17ab29e464c6 transplanted to e9ffc54ea104
290 filtering * (glob)
299 filtering * (glob)
291 applying 37a1297eb21b
300 applying 37a1297eb21b
292 37a1297eb21b transplanted to 348b36d0b6a5
301 37a1297eb21b transplanted to 348b36d0b6a5
293 filtering * (glob)
302 filtering * (glob)
294 applying 722f4667af76
303 applying 722f4667af76
295 722f4667af76 transplanted to 0aa6979afb95
304 722f4667af76 transplanted to 0aa6979afb95
296 filtering * (glob)
305 filtering * (glob)
297 applying a53251cdf717
306 applying a53251cdf717
298 a53251cdf717 transplanted to 14f8512272b5
307 a53251cdf717 transplanted to 14f8512272b5
299 $ hg log --template '{rev} {parents} {desc}\n'
308 $ hg log --template '{rev} {parents} {desc}\n'
300 3 b3
309 3 b3
301 2 b2
310 2 b2
302 1 b1
311 1 b1
303 0 r2
312 0 r2
304 $ cd ..
313 $ cd ..
305
314
306
315
307 test filter with failed patch
316 test filter with failed patch
308
317
309 $ cd filter
318 $ cd filter
310 $ hg up 0
319 $ hg up 0
311 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
320 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
312 $ echo foo > b1
321 $ echo foo > b1
313 $ hg ci -Am foo
322 $ hg ci -Am foo
314 adding b1
323 adding b1
315 adding test-filter
324 adding test-filter
316 created new head
325 created new head
317 $ hg transplant 1 --filter ./test-filter
326 $ hg transplant 1 --filter ./test-filter
318 filtering * (glob)
327 filtering * (glob)
319 applying 348b36d0b6a5
328 applying 348b36d0b6a5
320 file b1 already exists
329 file b1 already exists
321 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
330 1 out of 1 hunks FAILED -- saving rejects to file b1.rej
322 patch failed to apply
331 patch failed to apply
323 abort: fix up the merge and run hg transplant --continue
332 abort: fix up the merge and run hg transplant --continue
324 [255]
333 [255]
325 $ cd ..
334 $ cd ..
326
335
327
336
328 test with a win32ext like setup (differing EOLs)
337 test with a win32ext like setup (differing EOLs)
329
338
330 $ hg init twin1
339 $ hg init twin1
331 $ cd twin1
340 $ cd twin1
332 $ echo a > a
341 $ echo a > a
333 $ echo b > b
342 $ echo b > b
334 $ echo b >> b
343 $ echo b >> b
335 $ hg ci -Am t
344 $ hg ci -Am t
336 adding a
345 adding a
337 adding b
346 adding b
338 $ echo a > b
347 $ echo a > b
339 $ echo b >> b
348 $ echo b >> b
340 $ hg ci -m changeb
349 $ hg ci -m changeb
341 $ cd ..
350 $ cd ..
342
351
343 $ hg init twin2
352 $ hg init twin2
344 $ cd twin2
353 $ cd twin2
345 $ echo '[patch]' >> .hg/hgrc
354 $ echo '[patch]' >> .hg/hgrc
346 $ echo 'eol = crlf' >> .hg/hgrc
355 $ echo 'eol = crlf' >> .hg/hgrc
347 $ python -c "file('b', 'wb').write('b\r\nb\r\n')"
356 $ python -c "file('b', 'wb').write('b\r\nb\r\n')"
348 $ hg ci -m addb
357 $ hg ci -m addb
349 nothing changed
358 nothing changed
350 [1]
359 [1]
351 $ hg transplant -s ../twin1 tip
360 $ hg transplant -s ../twin1 tip
352 applying 2e849d776c17
361 applying 2e849d776c17
353 2e849d776c17 transplanted to 589cea8ba85b
362 2e849d776c17 transplanted to 589cea8ba85b
354 $ python -c "print repr(file('b', 'rb').read())"
363 $ python -c "print repr(file('b', 'rb').read())"
355 'a\r\nb\r\n'
364 'a\r\nb\r\n'
356 $ cd ..
365 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now