##// END OF EJS Templates
Remove trailing spaces.
Thomas Arendsen Hein -
r7236:db6fbb78 default
parent child Browse files
Show More
@@ -1,203 +1,203 b''
1 # convert.py Foreign SCM converter
1 # convert.py Foreign SCM converter
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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7 '''converting foreign VCS repositories to Mercurial'''
7 '''converting foreign VCS repositories to Mercurial'''
8
8
9 import convcmd
9 import convcmd
10 from mercurial import commands
10 from mercurial import commands
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12
12
13 # Commands definition was moved elsewhere to ease demandload job.
13 # Commands definition was moved elsewhere to ease demandload job.
14
14
15 def convert(ui, src, dest=None, revmapfile=None, **opts):
15 def convert(ui, src, dest=None, revmapfile=None, **opts):
16 """Convert a foreign SCM repository to a Mercurial one.
16 """Convert a foreign SCM repository to a Mercurial one.
17
17
18 Accepted source formats [identifiers]:
18 Accepted source formats [identifiers]:
19 - Mercurial [hg]
19 - Mercurial [hg]
20 - CVS [cvs]
20 - CVS [cvs]
21 - Darcs [darcs]
21 - Darcs [darcs]
22 - git [git]
22 - git [git]
23 - Subversion [svn]
23 - Subversion [svn]
24 - Monotone [mtn]
24 - Monotone [mtn]
25 - GNU Arch [gnuarch]
25 - GNU Arch [gnuarch]
26 - Bazaar [bzr]
26 - Bazaar [bzr]
27
27
28 Accepted destination formats [identifiers]:
28 Accepted destination formats [identifiers]:
29 - Mercurial [hg]
29 - Mercurial [hg]
30 - Subversion [svn] (history on branches is not preserved)
30 - Subversion [svn] (history on branches is not preserved)
31
31
32 If no revision is given, all revisions will be converted. Otherwise,
32 If no revision is given, all revisions will be converted. Otherwise,
33 convert will only import up to the named revision (given in a format
33 convert will only import up to the named revision (given in a format
34 understood by the source).
34 understood by the source).
35
35
36 If no destination directory name is specified, it defaults to the
36 If no destination directory name is specified, it defaults to the
37 basename of the source with '-hg' appended. If the destination
37 basename of the source with '-hg' appended. If the destination
38 repository doesn't exist, it will be created.
38 repository doesn't exist, it will be created.
39
39
40 If <REVMAP> isn't given, it will be put in a default location
40 If <REVMAP> isn't given, it will be put in a default location
41 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
41 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
42 file that maps each source commit ID to the destination ID for
42 file that maps each source commit ID to the destination ID for
43 that revision, like so:
43 that revision, like so:
44 <source ID> <destination ID>
44 <source ID> <destination ID>
45
45
46 If the file doesn't exist, it's automatically created. It's updated
46 If the file doesn't exist, it's automatically created. It's updated
47 on each commit copied, so convert-repo can be interrupted and can
47 on each commit copied, so convert-repo can be interrupted and can
48 be run repeatedly to copy new commits.
48 be run repeatedly to copy new commits.
49
49
50 The [username mapping] file is a simple text file that maps each source
50 The [username mapping] file is a simple text file that maps each source
51 commit author to a destination commit author. It is handy for source SCMs
51 commit author to a destination commit author. It is handy for source SCMs
52 that use unix logins to identify authors (eg: CVS). One line per author
52 that use unix logins to identify authors (eg: CVS). One line per author
53 mapping and the line format is:
53 mapping and the line format is:
54 srcauthor=whatever string you want
54 srcauthor=whatever string you want
55
55
56 The filemap is a file that allows filtering and remapping of files
56 The filemap is a file that allows filtering and remapping of files
57 and directories. Comment lines start with '#'. Each line can
57 and directories. Comment lines start with '#'. Each line can
58 contain one of the following directives:
58 contain one of the following directives:
59
59
60 include path/to/file
60 include path/to/file
61
61
62 exclude path/to/file
62 exclude path/to/file
63
63
64 rename from/file to/file
64 rename from/file to/file
65
65
66 The 'include' directive causes a file, or all files under a
66 The 'include' directive causes a file, or all files under a
67 directory, to be included in the destination repository, and the
67 directory, to be included in the destination repository, and the
68 exclusion of all other files and dirs not explicitely included.
68 exclusion of all other files and dirs not explicitely included.
69 The 'exclude' directive causes files or directories to be omitted.
69 The 'exclude' directive causes files or directories to be omitted.
70 The 'rename' directive renames a file or directory. To rename from a
70 The 'rename' directive renames a file or directory. To rename from a
71 subdirectory into the root of the repository, use '.' as the path to
71 subdirectory into the root of the repository, use '.' as the path to
72 rename to.
72 rename to.
73
73
74 The splicemap is a file that allows insertion of synthetic
74 The splicemap is a file that allows insertion of synthetic
75 history, letting you specify the parents of a revision. This is
75 history, letting you specify the parents of a revision. This is
76 useful if you want to e.g. give a Subversion merge two parents, or
76 useful if you want to e.g. give a Subversion merge two parents, or
77 graft two disconnected series of history together. Each entry
77 graft two disconnected series of history together. Each entry
78 contains a key, followed by a space, followed by one or two
78 contains a key, followed by a space, followed by one or two
79 values, separated by spaces. The key is the revision ID in the
79 values, separated by spaces. The key is the revision ID in the
80 source revision control system whose parents should be modified
80 source revision control system whose parents should be modified
81 (same format as a key in .hg/shamap). The values are the revision
81 (same format as a key in .hg/shamap). The values are the revision
82 IDs (in either the source or destination revision control system)
82 IDs (in either the source or destination revision control system)
83 that should be used as the new parents for that node.
83 that should be used as the new parents for that node.
84
84
85 Mercurial Source
85 Mercurial Source
86 -----------------
86 -----------------
87
87
88 --config convert.hg.ignoreerrors=False (boolean)
88 --config convert.hg.ignoreerrors=False (boolean)
89 ignore integrity errors when reading. Use it to fix Mercurial
89 ignore integrity errors when reading. Use it to fix Mercurial
90 repositories with missing revlogs, by converting from and to
90 repositories with missing revlogs, by converting from and to
91 Mercurial.
91 Mercurial.
92 --config convert.hg.saverev=True (boolean)
92 --config convert.hg.saverev=True (boolean)
93 allow target to preserve source revision ID
93 allow target to preserve source revision ID
94 --config convert.hg.startrev=0 (hg revision identifier)
94 --config convert.hg.startrev=0 (hg revision identifier)
95 convert start revision and its descendants
95 convert start revision and its descendants
96
96
97 CVS Source
97 CVS Source
98 ----------
98 ----------
99
99
100 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
100 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
101 to indicate the starting point of what will be converted. Direct
101 to indicate the starting point of what will be converted. Direct
102 access to the repository files is not needed, unless of course
102 access to the repository files is not needed, unless of course
103 the repository is :local:. The conversion uses the top level
103 the repository is :local:. The conversion uses the top level
104 directory in the sandbox to find the CVS repository, and then uses
104 directory in the sandbox to find the CVS repository, and then uses
105 CVS rlog commands to find files to convert. This means that unless
105 CVS rlog commands to find files to convert. This means that unless
106 a filemap is given, all files under the starting directory will be
106 a filemap is given, all files under the starting directory will be
107 converted, and that any directory reorganisation in the CVS
107 converted, and that any directory reorganisation in the CVS
108 sandbox is ignored.
108 sandbox is ignored.
109
109
110 Because CVS does not have changesets, it is necessary to collect
110 Because CVS does not have changesets, it is necessary to collect
111 individual commits to CVS and merge them into changesets. CVS
111 individual commits to CVS and merge them into changesets. CVS
112 source uses its internal changeset merging code by default but can
112 source uses its internal changeset merging code by default but can
113 be configured to call the external 'cvsps' program by setting:
113 be configured to call the external 'cvsps' program by setting:
114 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
114 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
115 This is a legacy option and may be removed in future.
115 This is a legacy option and may be removed in future.
116
116
117 The options shown are the defaults.
117 The options shown are the defaults.
118
118
119 Internal cvsps is selected by setting
119 Internal cvsps is selected by setting
120 --config convert.cvsps=builtin
120 --config convert.cvsps=builtin
121 and has a few more configurable options:
121 and has a few more configurable options:
122 --config convert.cvsps.fuzz=60 (integer)
122 --config convert.cvsps.fuzz=60 (integer)
123 Specify the maximum time (in seconds) that is allowed between
123 Specify the maximum time (in seconds) that is allowed between
124 commits with identical user and log message in a single
124 commits with identical user and log message in a single
125 changeset. When very large files were checked in as part
125 changeset. When very large files were checked in as part
126 of a changeset then the default may not be long enough.
126 of a changeset then the default may not be long enough.
127 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
127 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
128 Specify a regular expression to which commit log messages are
128 Specify a regular expression to which commit log messages are
129 matched. If a match occurs, then the conversion process will
129 matched. If a match occurs, then the conversion process will
130 insert a dummy revision merging the branch on which this log
130 insert a dummy revision merging the branch on which this log
131 message occurs to the branch indicated in the regex.
131 message occurs to the branch indicated in the regex.
132 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
132 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
133 Specify a regular expression to which commit log messages are
133 Specify a regular expression to which commit log messages are
134 matched. If a match occurs, then the conversion process will
134 matched. If a match occurs, then the conversion process will
135 add the most recent revision on the branch indicated in the
135 add the most recent revision on the branch indicated in the
136 regex as the second parent of the changeset.
136 regex as the second parent of the changeset.
137
137
138 The hgext/convert/cvsps wrapper script allows the builtin changeset
138 The hgext/convert/cvsps wrapper script allows the builtin changeset
139 merging code to be run without doing a conversion. Its parameters and
139 merging code to be run without doing a conversion. Its parameters and
140 output are similar to that of cvsps 2.1.
140 output are similar to that of cvsps 2.1.
141
141
142 Subversion Source
142 Subversion Source
143 -----------------
143 -----------------
144
144
145 Subversion source detects classical trunk/branches/tags layouts.
145 Subversion source detects classical trunk/branches/tags layouts.
146 By default, the supplied "svn://repo/path/" source URL is
146 By default, the supplied "svn://repo/path/" source URL is
147 converted as a single branch. If "svn://repo/path/trunk" exists
147 converted as a single branch. If "svn://repo/path/trunk" exists
148 it replaces the default branch. If "svn://repo/path/branches"
148 it replaces the default branch. If "svn://repo/path/branches"
149 exists, its subdirectories are listed as possible branches. If
149 exists, its subdirectories are listed as possible branches. If
150 "svn://repo/path/tags" exists, it is looked for tags referencing
150 "svn://repo/path/tags" exists, it is looked for tags referencing
151 converted branches. Default "trunk", "branches" and "tags" values
151 converted branches. Default "trunk", "branches" and "tags" values
152 can be overriden with following options. Set them to paths
152 can be overriden with following options. Set them to paths
153 relative to the source URL, or leave them blank to disable
153 relative to the source URL, or leave them blank to disable
154 autodetection.
154 autodetection.
155
155
156 --config convert.svn.branches=branches (directory name)
156 --config convert.svn.branches=branches (directory name)
157 specify the directory containing branches
157 specify the directory containing branches
158 --config convert.svn.tags=tags (directory name)
158 --config convert.svn.tags=tags (directory name)
159 specify the directory containing tags
159 specify the directory containing tags
160 --config convert.svn.trunk=trunk (directory name)
160 --config convert.svn.trunk=trunk (directory name)
161 specify the name of the trunk branch
161 specify the name of the trunk branch
162
162
163 Source history can be retrieved starting at a specific revision,
163 Source history can be retrieved starting at a specific revision,
164 instead of being integrally converted. Only single branch
164 instead of being integrally converted. Only single branch
165 conversions are supported.
165 conversions are supported.
166
166
167 --config convert.svn.startrev=0 (svn revision number)
167 --config convert.svn.startrev=0 (svn revision number)
168 specify start Subversion revision.
168 specify start Subversion revision.
169
169
170 Mercurial Destination
170 Mercurial Destination
171 ---------------------
171 ---------------------
172
172
173 --config convert.hg.clonebranches=False (boolean)
173 --config convert.hg.clonebranches=False (boolean)
174 dispatch source branches in separate clones.
174 dispatch source branches in separate clones.
175 --config convert.hg.tagsbranch=default (branch name)
175 --config convert.hg.tagsbranch=default (branch name)
176 tag revisions branch name
176 tag revisions branch name
177 --config convert.hg.usebranchnames=True (boolean)
177 --config convert.hg.usebranchnames=True (boolean)
178 preserve branch names
178 preserve branch names
179
179
180 """
180 """
181 return convcmd.convert(ui, src, dest, revmapfile, **opts)
181 return convcmd.convert(ui, src, dest, revmapfile, **opts)
182
182
183 def debugsvnlog(ui, **opts):
183 def debugsvnlog(ui, **opts):
184 return convcmd.debugsvnlog(ui, **opts)
184 return convcmd.debugsvnlog(ui, **opts)
185
185
186 commands.norepo += " convert debugsvnlog"
186 commands.norepo += " convert debugsvnlog"
187
187
188 cmdtable = {
188 cmdtable = {
189 "convert":
189 "convert":
190 (convert,
190 (convert,
191 [('A', 'authors', '', _('username mapping filename')),
191 [('A', 'authors', '', _('username mapping filename')),
192 ('d', 'dest-type', '', _('destination repository type')),
192 ('d', 'dest-type', '', _('destination repository type')),
193 ('', 'filemap', '', _('remap file names using contents of file')),
193 ('', 'filemap', '', _('remap file names using contents of file')),
194 ('r', 'rev', '', _('import up to target revision REV')),
194 ('r', 'rev', '', _('import up to target revision REV')),
195 ('s', 'source-type', '', _('source repository type')),
195 ('s', 'source-type', '', _('source repository type')),
196 ('', 'splicemap', '', _('splice synthesized history into place')),
196 ('', 'splicemap', '', _('splice synthesized history into place')),
197 ('', 'datesort', None, _('try to sort changesets by date'))],
197 ('', 'datesort', None, _('try to sort changesets by date'))],
198 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')),
198 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')),
199 "debugsvnlog":
199 "debugsvnlog":
200 (debugsvnlog,
200 (debugsvnlog,
201 [],
201 [],
202 'hg debugsvnlog'),
202 'hg debugsvnlog'),
203 }
203 }
@@ -1,336 +1,336 b''
1 # hg backend for convert extension
1 # hg backend for convert extension
2
2
3 # Notes for hg->hg conversion:
3 # Notes for hg->hg conversion:
4 #
4 #
5 # * Old versions of Mercurial didn't trim the whitespace from the ends
5 # * Old versions of Mercurial didn't trim the whitespace from the ends
6 # of commit messages, but new versions do. Changesets created by
6 # of commit messages, but new versions do. Changesets created by
7 # those older versions, then converted, may thus have different
7 # those older versions, then converted, may thus have different
8 # hashes for changesets that are otherwise identical.
8 # hashes for changesets that are otherwise identical.
9 #
9 #
10 # * By default, the source revision is stored in the converted
10 # * By default, the source revision is stored in the converted
11 # revision. This will cause the converted revision to have a
11 # revision. This will cause the converted revision to have a
12 # different identity than the source. To avoid this, use the
12 # different identity than the source. To avoid this, use the
13 # following option: "--config convert.hg.saverev=false"
13 # following option: "--config convert.hg.saverev=false"
14
14
15
15
16 import os, time
16 import os, time
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18 from mercurial.repo import RepoError
18 from mercurial.repo import RepoError
19 from mercurial.node import bin, hex, nullid
19 from mercurial.node import bin, hex, nullid
20 from mercurial import hg, revlog, util, context
20 from mercurial import hg, revlog, util, context
21
21
22 from common import NoRepo, commit, converter_source, converter_sink
22 from common import NoRepo, commit, converter_source, converter_sink
23
23
24 class mercurial_sink(converter_sink):
24 class mercurial_sink(converter_sink):
25 def __init__(self, ui, path):
25 def __init__(self, ui, path):
26 converter_sink.__init__(self, ui, path)
26 converter_sink.__init__(self, ui, path)
27 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
27 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
28 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
28 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
29 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
29 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
30 self.lastbranch = None
30 self.lastbranch = None
31 if os.path.isdir(path) and len(os.listdir(path)) > 0:
31 if os.path.isdir(path) and len(os.listdir(path)) > 0:
32 try:
32 try:
33 self.repo = hg.repository(self.ui, path)
33 self.repo = hg.repository(self.ui, path)
34 if not self.repo.local():
34 if not self.repo.local():
35 raise NoRepo(_('%s is not a local Mercurial repo') % path)
35 raise NoRepo(_('%s is not a local Mercurial repo') % path)
36 except RepoError, err:
36 except RepoError, err:
37 ui.print_exc()
37 ui.print_exc()
38 raise NoRepo(err.args[0])
38 raise NoRepo(err.args[0])
39 else:
39 else:
40 try:
40 try:
41 ui.status(_('initializing destination %s repository\n') % path)
41 ui.status(_('initializing destination %s repository\n') % path)
42 self.repo = hg.repository(self.ui, path, create=True)
42 self.repo = hg.repository(self.ui, path, create=True)
43 if not self.repo.local():
43 if not self.repo.local():
44 raise NoRepo(_('%s is not a local Mercurial repo') % path)
44 raise NoRepo(_('%s is not a local Mercurial repo') % path)
45 self.created.append(path)
45 self.created.append(path)
46 except RepoError, err:
46 except RepoError, err:
47 ui.print_exc()
47 ui.print_exc()
48 raise NoRepo("could not create hg repo %s as sink" % path)
48 raise NoRepo("could not create hg repo %s as sink" % path)
49 self.lock = None
49 self.lock = None
50 self.wlock = None
50 self.wlock = None
51 self.filemapmode = False
51 self.filemapmode = False
52
52
53 def before(self):
53 def before(self):
54 self.ui.debug(_('run hg sink pre-conversion action\n'))
54 self.ui.debug(_('run hg sink pre-conversion action\n'))
55 self.wlock = self.repo.wlock()
55 self.wlock = self.repo.wlock()
56 self.lock = self.repo.lock()
56 self.lock = self.repo.lock()
57
57
58 def after(self):
58 def after(self):
59 self.ui.debug(_('run hg sink post-conversion action\n'))
59 self.ui.debug(_('run hg sink post-conversion action\n'))
60 self.lock = None
60 self.lock = None
61 self.wlock = None
61 self.wlock = None
62
62
63 def revmapfile(self):
63 def revmapfile(self):
64 return os.path.join(self.path, ".hg", "shamap")
64 return os.path.join(self.path, ".hg", "shamap")
65
65
66 def authorfile(self):
66 def authorfile(self):
67 return os.path.join(self.path, ".hg", "authormap")
67 return os.path.join(self.path, ".hg", "authormap")
68
68
69 def getheads(self):
69 def getheads(self):
70 h = self.repo.changelog.heads()
70 h = self.repo.changelog.heads()
71 return [ hex(x) for x in h ]
71 return [ hex(x) for x in h ]
72
72
73 def setbranch(self, branch, pbranches):
73 def setbranch(self, branch, pbranches):
74 if not self.clonebranches:
74 if not self.clonebranches:
75 return
75 return
76
76
77 setbranch = (branch != self.lastbranch)
77 setbranch = (branch != self.lastbranch)
78 self.lastbranch = branch
78 self.lastbranch = branch
79 if not branch:
79 if not branch:
80 branch = 'default'
80 branch = 'default'
81 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
81 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
82 pbranch = pbranches and pbranches[0][1] or 'default'
82 pbranch = pbranches and pbranches[0][1] or 'default'
83
83
84 branchpath = os.path.join(self.path, branch)
84 branchpath = os.path.join(self.path, branch)
85 if setbranch:
85 if setbranch:
86 self.after()
86 self.after()
87 try:
87 try:
88 self.repo = hg.repository(self.ui, branchpath)
88 self.repo = hg.repository(self.ui, branchpath)
89 except:
89 except:
90 self.repo = hg.repository(self.ui, branchpath, create=True)
90 self.repo = hg.repository(self.ui, branchpath, create=True)
91 self.before()
91 self.before()
92
92
93 # pbranches may bring revisions from other branches (merge parents)
93 # pbranches may bring revisions from other branches (merge parents)
94 # Make sure we have them, or pull them.
94 # Make sure we have them, or pull them.
95 missings = {}
95 missings = {}
96 for b in pbranches:
96 for b in pbranches:
97 try:
97 try:
98 self.repo.lookup(b[0])
98 self.repo.lookup(b[0])
99 except:
99 except:
100 missings.setdefault(b[1], []).append(b[0])
100 missings.setdefault(b[1], []).append(b[0])
101
101
102 if missings:
102 if missings:
103 self.after()
103 self.after()
104 for pbranch, heads in missings.iteritems():
104 for pbranch, heads in missings.iteritems():
105 pbranchpath = os.path.join(self.path, pbranch)
105 pbranchpath = os.path.join(self.path, pbranch)
106 prepo = hg.repository(self.ui, pbranchpath)
106 prepo = hg.repository(self.ui, pbranchpath)
107 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
107 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
108 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
108 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
109 self.before()
109 self.before()
110
110
111 def putcommit(self, files, copies, parents, commit, source):
111 def putcommit(self, files, copies, parents, commit, source):
112
112
113 files = dict(files)
113 files = dict(files)
114 def getfilectx(repo, memctx, f):
114 def getfilectx(repo, memctx, f):
115 v = files[f]
115 v = files[f]
116 data = source.getfile(f, v)
116 data = source.getfile(f, v)
117 e = source.getmode(f, v)
117 e = source.getmode(f, v)
118 return context.memfilectx(f, data, 'l' in e, 'x' in e, copies.get(f))
118 return context.memfilectx(f, data, 'l' in e, 'x' in e, copies.get(f))
119
119
120 pl = []
120 pl = []
121 for p in parents:
121 for p in parents:
122 if p not in pl:
122 if p not in pl:
123 pl.append(p)
123 pl.append(p)
124 parents = pl
124 parents = pl
125 nparents = len(parents)
125 nparents = len(parents)
126 if self.filemapmode and nparents == 1:
126 if self.filemapmode and nparents == 1:
127 m1node = self.repo.changelog.read(bin(parents[0]))[0]
127 m1node = self.repo.changelog.read(bin(parents[0]))[0]
128 parent = parents[0]
128 parent = parents[0]
129
129
130 if len(parents) < 2: parents.append("0" * 40)
130 if len(parents) < 2: parents.append("0" * 40)
131 if len(parents) < 2: parents.append("0" * 40)
131 if len(parents) < 2: parents.append("0" * 40)
132 p2 = parents.pop(0)
132 p2 = parents.pop(0)
133
133
134 text = commit.desc
134 text = commit.desc
135 extra = commit.extra.copy()
135 extra = commit.extra.copy()
136 if self.branchnames and commit.branch:
136 if self.branchnames and commit.branch:
137 extra['branch'] = commit.branch
137 extra['branch'] = commit.branch
138 if commit.rev:
138 if commit.rev:
139 extra['convert_revision'] = commit.rev
139 extra['convert_revision'] = commit.rev
140
140
141 while parents:
141 while parents:
142 p1 = p2
142 p1 = p2
143 p2 = parents.pop(0)
143 p2 = parents.pop(0)
144 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx,
144 ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx,
145 commit.author, commit.date, extra)
145 commit.author, commit.date, extra)
146 a = self.repo.commitctx(ctx)
146 a = self.repo.commitctx(ctx)
147 text = "(octopus merge fixup)\n"
147 text = "(octopus merge fixup)\n"
148 p2 = hex(self.repo.changelog.tip())
148 p2 = hex(self.repo.changelog.tip())
149
149
150 if self.filemapmode and nparents == 1:
150 if self.filemapmode and nparents == 1:
151 man = self.repo.manifest
151 man = self.repo.manifest
152 mnode = self.repo.changelog.read(bin(p2))[0]
152 mnode = self.repo.changelog.read(bin(p2))[0]
153 if not man.cmp(m1node, man.revision(mnode)):
153 if not man.cmp(m1node, man.revision(mnode)):
154 self.repo.rollback()
154 self.repo.rollback()
155 return parent
155 return parent
156 return p2
156 return p2
157
157
158 def puttags(self, tags):
158 def puttags(self, tags):
159 try:
159 try:
160 parentctx = self.repo[self.tagsbranch]
160 parentctx = self.repo[self.tagsbranch]
161 tagparent = parentctx.node()
161 tagparent = parentctx.node()
162 except RepoError, inst:
162 except RepoError, inst:
163 parentctx = None
163 parentctx = None
164 tagparent = nullid
164 tagparent = nullid
165
165
166 try:
166 try:
167 oldlines = util.sort(parentctx['.hgtags'].data().splitlines(1))
167 oldlines = util.sort(parentctx['.hgtags'].data().splitlines(1))
168 except:
168 except:
169 oldlines = []
169 oldlines = []
170
170
171 newlines = util.sort([("%s %s\n" % (tags[tag], tag)) for tag in tags])
171 newlines = util.sort([("%s %s\n" % (tags[tag], tag)) for tag in tags])
172
172
173 if newlines == oldlines:
173 if newlines == oldlines:
174 return None
174 return None
175 data = "".join(newlines)
175 data = "".join(newlines)
176
176
177 def getfilectx(repo, memctx, f):
177 def getfilectx(repo, memctx, f):
178 return context.memfilectx(f, data, False, False, None)
178 return context.memfilectx(f, data, False, False, None)
179
179
180 self.ui.status(_("updating tags\n"))
180 self.ui.status(_("updating tags\n"))
181 date = "%s 0" % int(time.mktime(time.gmtime()))
181 date = "%s 0" % int(time.mktime(time.gmtime()))
182 extra = {'branch': self.tagsbranch}
182 extra = {'branch': self.tagsbranch}
183 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
183 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
184 [".hgtags"], getfilectx, "convert-repo", date,
184 [".hgtags"], getfilectx, "convert-repo", date,
185 extra)
185 extra)
186 self.repo.commitctx(ctx)
186 self.repo.commitctx(ctx)
187 return hex(self.repo.changelog.tip())
187 return hex(self.repo.changelog.tip())
188
188
189 def setfilemapmode(self, active):
189 def setfilemapmode(self, active):
190 self.filemapmode = active
190 self.filemapmode = active
191
191
192 class mercurial_source(converter_source):
192 class mercurial_source(converter_source):
193 def __init__(self, ui, path, rev=None):
193 def __init__(self, ui, path, rev=None):
194 converter_source.__init__(self, ui, path, rev)
194 converter_source.__init__(self, ui, path, rev)
195 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
195 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
196 self.ignored = {}
196 self.ignored = {}
197 self.saverev = ui.configbool('convert', 'hg.saverev', True)
197 self.saverev = ui.configbool('convert', 'hg.saverev', True)
198 try:
198 try:
199 self.repo = hg.repository(self.ui, path)
199 self.repo = hg.repository(self.ui, path)
200 # try to provoke an exception if this isn't really a hg
200 # try to provoke an exception if this isn't really a hg
201 # repo, but some other bogus compatible-looking url
201 # repo, but some other bogus compatible-looking url
202 if not self.repo.local():
202 if not self.repo.local():
203 raise RepoError()
203 raise RepoError()
204 except RepoError:
204 except RepoError:
205 ui.print_exc()
205 ui.print_exc()
206 raise NoRepo("%s is not a local Mercurial repo" % path)
206 raise NoRepo("%s is not a local Mercurial repo" % path)
207 self.lastrev = None
207 self.lastrev = None
208 self.lastctx = None
208 self.lastctx = None
209 self._changescache = None
209 self._changescache = None
210 self.convertfp = None
210 self.convertfp = None
211 # Restrict converted revisions to startrev descendants
211 # Restrict converted revisions to startrev descendants
212 startnode = ui.config('convert', 'hg.startrev')
212 startnode = ui.config('convert', 'hg.startrev')
213 if startnode is not None:
213 if startnode is not None:
214 try:
214 try:
215 startnode = self.repo.lookup(startnode)
215 startnode = self.repo.lookup(startnode)
216 except repo.RepoError:
216 except repo.RepoError:
217 raise util.Abort(_('%s is not a valid start revision')
217 raise util.Abort(_('%s is not a valid start revision')
218 % startnode)
218 % startnode)
219 startrev = self.repo.changelog.rev(startnode)
219 startrev = self.repo.changelog.rev(startnode)
220 children = {startnode: 1}
220 children = {startnode: 1}
221 for rev in self.repo.changelog.descendants(startrev):
221 for rev in self.repo.changelog.descendants(startrev):
222 children[self.repo.changelog.node(rev)] = 1
222 children[self.repo.changelog.node(rev)] = 1
223 self.keep = children.__contains__
223 self.keep = children.__contains__
224 else:
224 else:
225 self.keep = util.always
225 self.keep = util.always
226
226
227 def changectx(self, rev):
227 def changectx(self, rev):
228 if self.lastrev != rev:
228 if self.lastrev != rev:
229 self.lastctx = self.repo[rev]
229 self.lastctx = self.repo[rev]
230 self.lastrev = rev
230 self.lastrev = rev
231 return self.lastctx
231 return self.lastctx
232
232
233 def parents(self, ctx):
233 def parents(self, ctx):
234 return [p.node() for p in ctx.parents()
234 return [p.node() for p in ctx.parents()
235 if p and self.keep(p.node())]
235 if p and self.keep(p.node())]
236
236
237 def getheads(self):
237 def getheads(self):
238 if self.rev:
238 if self.rev:
239 heads = [self.repo[self.rev].node()]
239 heads = [self.repo[self.rev].node()]
240 else:
240 else:
241 heads = self.repo.heads()
241 heads = self.repo.heads()
242 return [hex(h) for h in heads if self.keep(h)]
242 return [hex(h) for h in heads if self.keep(h)]
243
243
244 def getfile(self, name, rev):
244 def getfile(self, name, rev):
245 try:
245 try:
246 return self.changectx(rev)[name].data()
246 return self.changectx(rev)[name].data()
247 except revlog.LookupError, err:
247 except revlog.LookupError, err:
248 raise IOError(err)
248 raise IOError(err)
249
249
250 def getmode(self, name, rev):
250 def getmode(self, name, rev):
251 return self.changectx(rev).manifest().flags(name)
251 return self.changectx(rev).manifest().flags(name)
252
252
253 def getchanges(self, rev):
253 def getchanges(self, rev):
254 ctx = self.changectx(rev)
254 ctx = self.changectx(rev)
255 parents = self.parents(ctx)
255 parents = self.parents(ctx)
256 if not parents:
256 if not parents:
257 files = util.sort(ctx.manifest().keys())
257 files = util.sort(ctx.manifest().keys())
258 if self.ignoreerrors:
258 if self.ignoreerrors:
259 # calling getcopies() is a simple way to detect missing
259 # calling getcopies() is a simple way to detect missing
260 # revlogs and populate self.ignored
260 # revlogs and populate self.ignored
261 self.getcopies(ctx, files)
261 self.getcopies(ctx, files)
262 return [(f, rev) for f in files if f not in self.ignored], {}
262 return [(f, rev) for f in files if f not in self.ignored], {}
263 if self._changescache and self._changescache[0] == rev:
263 if self._changescache and self._changescache[0] == rev:
264 m, a, r = self._changescache[1]
264 m, a, r = self._changescache[1]
265 else:
265 else:
266 m, a, r = self.repo.status(parents[0], ctx.node())[:3]
266 m, a, r = self.repo.status(parents[0], ctx.node())[:3]
267 # getcopies() detects missing revlogs early, run it before
267 # getcopies() detects missing revlogs early, run it before
268 # filtering the changes.
268 # filtering the changes.
269 copies = self.getcopies(ctx, m + a)
269 copies = self.getcopies(ctx, m + a)
270 changes = [(name, rev) for name in m + a + r
270 changes = [(name, rev) for name in m + a + r
271 if name not in self.ignored]
271 if name not in self.ignored]
272 return util.sort(changes), copies
272 return util.sort(changes), copies
273
273
274 def getcopies(self, ctx, files):
274 def getcopies(self, ctx, files):
275 copies = {}
275 copies = {}
276 for name in files:
276 for name in files:
277 if name in self.ignored:
277 if name in self.ignored:
278 continue
278 continue
279 try:
279 try:
280 copysource, copynode = ctx.filectx(name).renamed()
280 copysource, copynode = ctx.filectx(name).renamed()
281 if copysource in self.ignored or not self.keep(copynode):
281 if copysource in self.ignored or not self.keep(copynode):
282 continue
282 continue
283 copies[name] = copysource
283 copies[name] = copysource
284 except TypeError:
284 except TypeError:
285 pass
285 pass
286 except revlog.LookupError, e:
286 except revlog.LookupError, e:
287 if not self.ignoreerrors:
287 if not self.ignoreerrors:
288 raise
288 raise
289 self.ignored[name] = 1
289 self.ignored[name] = 1
290 self.ui.warn(_('ignoring: %s\n') % e)
290 self.ui.warn(_('ignoring: %s\n') % e)
291 return copies
291 return copies
292
292
293 def getcommit(self, rev):
293 def getcommit(self, rev):
294 ctx = self.changectx(rev)
294 ctx = self.changectx(rev)
295 parents = [hex(p) for p in self.parents(ctx)]
295 parents = [hex(p) for p in self.parents(ctx)]
296 if self.saverev:
296 if self.saverev:
297 crev = rev
297 crev = rev
298 else:
298 else:
299 crev = None
299 crev = None
300 return commit(author=ctx.user(), date=util.datestr(ctx.date()),
300 return commit(author=ctx.user(), date=util.datestr(ctx.date()),
301 desc=ctx.description(), rev=crev, parents=parents,
301 desc=ctx.description(), rev=crev, parents=parents,
302 branch=ctx.branch(), extra=ctx.extra())
302 branch=ctx.branch(), extra=ctx.extra())
303
303
304 def gettags(self):
304 def gettags(self):
305 tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
305 tags = [t for t in self.repo.tagslist() if t[0] != 'tip']
306 return dict([(name, hex(node)) for name, node in tags
306 return dict([(name, hex(node)) for name, node in tags
307 if self.keep(node)])
307 if self.keep(node)])
308
308
309 def getchangedfiles(self, rev, i):
309 def getchangedfiles(self, rev, i):
310 ctx = self.changectx(rev)
310 ctx = self.changectx(rev)
311 parents = self.parents(ctx)
311 parents = self.parents(ctx)
312 if not parents and i is None:
312 if not parents and i is None:
313 i = 0
313 i = 0
314 changes = [], ctx.manifest().keys(), []
314 changes = [], ctx.manifest().keys(), []
315 else:
315 else:
316 i = i or 0
316 i = i or 0
317 changes = self.repo.status(parents[i], ctx.node())[:3]
317 changes = self.repo.status(parents[i], ctx.node())[:3]
318 changes = [[f for f in l if f not in self.ignored] for l in changes]
318 changes = [[f for f in l if f not in self.ignored] for l in changes]
319
319
320 if i == 0:
320 if i == 0:
321 self._changescache = (rev, changes)
321 self._changescache = (rev, changes)
322
322
323 return changes[0] + changes[1] + changes[2]
323 return changes[0] + changes[1] + changes[2]
324
324
325 def converted(self, rev, destrev):
325 def converted(self, rev, destrev):
326 if self.convertfp is None:
326 if self.convertfp is None:
327 self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'),
327 self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'),
328 'a')
328 'a')
329 self.convertfp.write('%s %s\n' % (destrev, rev))
329 self.convertfp.write('%s %s\n' % (destrev, rev))
330 self.convertfp.flush()
330 self.convertfp.flush()
331
331
332 def before(self):
332 def before(self):
333 self.ui.debug(_('run hg source pre-conversion action\n'))
333 self.ui.debug(_('run hg source pre-conversion action\n'))
334
334
335 def after(self):
335 def after(self):
336 self.ui.debug(_('run hg source post-conversion action\n'))
336 self.ui.debug(_('run hg source post-conversion action\n'))
@@ -1,3374 +1,3374 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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import hex, nullid, nullrev, short
8 from node import hex, nullid, nullrev, short
9 from repo import RepoError, NoCapability
9 from repo import RepoError, NoCapability
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, urllib
11 import os, re, sys, urllib
12 import hg, util, revlog, bundlerepo, extensions, copies
12 import hg, util, revlog, bundlerepo, extensions, copies
13 import difflib, patch, time, help, mdiff, tempfile
13 import difflib, patch, time, help, mdiff, tempfile
14 import version, socket
14 import version, socket
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 import merge as merge_
16 import merge as merge_
17
17
18 # Commands start here, listed alphabetically
18 # Commands start here, listed alphabetically
19
19
20 def add(ui, repo, *pats, **opts):
20 def add(ui, repo, *pats, **opts):
21 """add the specified files on the next commit
21 """add the specified files on the next commit
22
22
23 Schedule files to be version controlled and added to the repository.
23 Schedule files to be version controlled and added to the repository.
24
24
25 The files will be added to the repository at the next commit. To
25 The files will be added to the repository at the next commit. To
26 undo an add before that, see hg revert.
26 undo an add before that, see hg revert.
27
27
28 If no names are given, add all files in the repository.
28 If no names are given, add all files in the repository.
29 """
29 """
30
30
31 rejected = None
31 rejected = None
32 exacts = {}
32 exacts = {}
33 names = []
33 names = []
34 m = cmdutil.match(repo, pats, opts)
34 m = cmdutil.match(repo, pats, opts)
35 m.bad = lambda x,y: True
35 m.bad = lambda x,y: True
36 for abs in repo.walk(m):
36 for abs in repo.walk(m):
37 if m.exact(abs):
37 if m.exact(abs):
38 if ui.verbose:
38 if ui.verbose:
39 ui.status(_('adding %s\n') % m.rel(abs))
39 ui.status(_('adding %s\n') % m.rel(abs))
40 names.append(abs)
40 names.append(abs)
41 exacts[abs] = 1
41 exacts[abs] = 1
42 elif abs not in repo.dirstate:
42 elif abs not in repo.dirstate:
43 ui.status(_('adding %s\n') % m.rel(abs))
43 ui.status(_('adding %s\n') % m.rel(abs))
44 names.append(abs)
44 names.append(abs)
45 if not opts.get('dry_run'):
45 if not opts.get('dry_run'):
46 rejected = repo.add(names)
46 rejected = repo.add(names)
47 rejected = [p for p in rejected if p in exacts]
47 rejected = [p for p in rejected if p in exacts]
48 return rejected and 1 or 0
48 return rejected and 1 or 0
49
49
50 def addremove(ui, repo, *pats, **opts):
50 def addremove(ui, repo, *pats, **opts):
51 """add all new files, delete all missing files
51 """add all new files, delete all missing files
52
52
53 Add all new files and remove all missing files from the repository.
53 Add all new files and remove all missing files from the repository.
54
54
55 New files are ignored if they match any of the patterns in .hgignore. As
55 New files are ignored if they match any of the patterns in .hgignore. As
56 with add, these changes take effect at the next commit.
56 with add, these changes take effect at the next commit.
57
57
58 Use the -s option to detect renamed files. With a parameter > 0,
58 Use the -s option to detect renamed files. With a parameter > 0,
59 this compares every removed file with every added file and records
59 this compares every removed file with every added file and records
60 those similar enough as renames. This option takes a percentage
60 those similar enough as renames. This option takes a percentage
61 between 0 (disabled) and 100 (files must be identical) as its
61 between 0 (disabled) and 100 (files must be identical) as its
62 parameter. Detecting renamed files this way can be expensive.
62 parameter. Detecting renamed files this way can be expensive.
63 """
63 """
64 try:
64 try:
65 sim = float(opts.get('similarity') or 0)
65 sim = float(opts.get('similarity') or 0)
66 except ValueError:
66 except ValueError:
67 raise util.Abort(_('similarity must be a number'))
67 raise util.Abort(_('similarity must be a number'))
68 if sim < 0 or sim > 100:
68 if sim < 0 or sim > 100:
69 raise util.Abort(_('similarity must be between 0 and 100'))
69 raise util.Abort(_('similarity must be between 0 and 100'))
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
71
71
72 def annotate(ui, repo, *pats, **opts):
72 def annotate(ui, repo, *pats, **opts):
73 """show changeset information per file line
73 """show changeset information per file line
74
74
75 List changes in files, showing the revision id responsible for each line
75 List changes in files, showing the revision id responsible for each line
76
76
77 This command is useful to discover who did a change or when a change took
77 This command is useful to discover who did a change or when a change took
78 place.
78 place.
79
79
80 Without the -a option, annotate will avoid processing files it
80 Without the -a option, annotate will avoid processing files it
81 detects as binary. With -a, annotate will generate an annotation
81 detects as binary. With -a, annotate will generate an annotation
82 anyway, probably with undesirable results.
82 anyway, probably with undesirable results.
83 """
83 """
84 datefunc = ui.quiet and util.shortdate or util.datestr
84 datefunc = ui.quiet and util.shortdate or util.datestr
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
86
86
87 if not pats:
87 if not pats:
88 raise util.Abort(_('at least one file name or pattern required'))
88 raise util.Abort(_('at least one file name or pattern required'))
89
89
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
91 ('number', lambda x: str(x[0].rev())),
91 ('number', lambda x: str(x[0].rev())),
92 ('changeset', lambda x: short(x[0].node())),
92 ('changeset', lambda x: short(x[0].node())),
93 ('date', getdate),
93 ('date', getdate),
94 ('follow', lambda x: x[0].path()),
94 ('follow', lambda x: x[0].path()),
95 ]
95 ]
96
96
97 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
97 if (not opts.get('user') and not opts.get('changeset') and not opts.get('date')
98 and not opts.get('follow')):
98 and not opts.get('follow')):
99 opts['number'] = 1
99 opts['number'] = 1
100
100
101 linenumber = opts.get('line_number') is not None
101 linenumber = opts.get('line_number') is not None
102 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
102 if (linenumber and (not opts.get('changeset')) and (not opts.get('number'))):
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
103 raise util.Abort(_('at least one of -n/-c is required for -l'))
104
104
105 funcmap = [func for op, func in opmap if opts.get(op)]
105 funcmap = [func for op, func in opmap if opts.get(op)]
106 if linenumber:
106 if linenumber:
107 lastfunc = funcmap[-1]
107 lastfunc = funcmap[-1]
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
109
109
110 ctx = repo[opts.get('rev')]
110 ctx = repo[opts.get('rev')]
111
111
112 m = cmdutil.match(repo, pats, opts)
112 m = cmdutil.match(repo, pats, opts)
113 for abs in ctx.walk(m):
113 for abs in ctx.walk(m):
114 fctx = ctx[abs]
114 fctx = ctx[abs]
115 if not opts.get('text') and util.binary(fctx.data()):
115 if not opts.get('text') and util.binary(fctx.data()):
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
117 continue
117 continue
118
118
119 lines = fctx.annotate(follow=opts.get('follow'),
119 lines = fctx.annotate(follow=opts.get('follow'),
120 linenumber=linenumber)
120 linenumber=linenumber)
121 pieces = []
121 pieces = []
122
122
123 for f in funcmap:
123 for f in funcmap:
124 l = [f(n) for n, dummy in lines]
124 l = [f(n) for n, dummy in lines]
125 if l:
125 if l:
126 ml = max(map(len, l))
126 ml = max(map(len, l))
127 pieces.append(["%*s" % (ml, x) for x in l])
127 pieces.append(["%*s" % (ml, x) for x in l])
128
128
129 if pieces:
129 if pieces:
130 for p, l in zip(zip(*pieces), lines):
130 for p, l in zip(zip(*pieces), lines):
131 ui.write("%s: %s" % (" ".join(p), l[1]))
131 ui.write("%s: %s" % (" ".join(p), l[1]))
132
132
133 def archive(ui, repo, dest, **opts):
133 def archive(ui, repo, dest, **opts):
134 '''create unversioned archive of a repository revision
134 '''create unversioned archive of a repository revision
135
135
136 By default, the revision used is the parent of the working
136 By default, the revision used is the parent of the working
137 directory; use "-r" to specify a different revision.
137 directory; use "-r" to specify a different revision.
138
138
139 To specify the type of archive to create, use "-t". Valid
139 To specify the type of archive to create, use "-t". Valid
140 types are:
140 types are:
141
141
142 "files" (default): a directory full of files
142 "files" (default): a directory full of files
143 "tar": tar archive, uncompressed
143 "tar": tar archive, uncompressed
144 "tbz2": tar archive, compressed using bzip2
144 "tbz2": tar archive, compressed using bzip2
145 "tgz": tar archive, compressed using gzip
145 "tgz": tar archive, compressed using gzip
146 "uzip": zip archive, uncompressed
146 "uzip": zip archive, uncompressed
147 "zip": zip archive, compressed using deflate
147 "zip": zip archive, compressed using deflate
148
148
149 The exact name of the destination archive or directory is given
149 The exact name of the destination archive or directory is given
150 using a format string; see "hg help export" for details.
150 using a format string; see "hg help export" for details.
151
151
152 Each member added to an archive file has a directory prefix
152 Each member added to an archive file has a directory prefix
153 prepended. Use "-p" to specify a format string for the prefix.
153 prepended. Use "-p" to specify a format string for the prefix.
154 The default is the basename of the archive, with suffixes removed.
154 The default is the basename of the archive, with suffixes removed.
155 '''
155 '''
156
156
157 ctx = repo[opts.get('rev')]
157 ctx = repo[opts.get('rev')]
158 if not ctx:
158 if not ctx:
159 raise util.Abort(_('repository has no revisions'))
159 raise util.Abort(_('repository has no revisions'))
160 node = ctx.node()
160 node = ctx.node()
161 dest = cmdutil.make_filename(repo, dest, node)
161 dest = cmdutil.make_filename(repo, dest, node)
162 if os.path.realpath(dest) == repo.root:
162 if os.path.realpath(dest) == repo.root:
163 raise util.Abort(_('repository root cannot be destination'))
163 raise util.Abort(_('repository root cannot be destination'))
164 matchfn = cmdutil.match(repo, [], opts)
164 matchfn = cmdutil.match(repo, [], opts)
165 kind = opts.get('type') or 'files'
165 kind = opts.get('type') or 'files'
166 prefix = opts.get('prefix')
166 prefix = opts.get('prefix')
167 if dest == '-':
167 if dest == '-':
168 if kind == 'files':
168 if kind == 'files':
169 raise util.Abort(_('cannot archive plain files to stdout'))
169 raise util.Abort(_('cannot archive plain files to stdout'))
170 dest = sys.stdout
170 dest = sys.stdout
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
172 prefix = cmdutil.make_filename(repo, prefix, node)
172 prefix = cmdutil.make_filename(repo, prefix, node)
173 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
173 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
174 matchfn, prefix)
174 matchfn, prefix)
175
175
176 def backout(ui, repo, node=None, rev=None, **opts):
176 def backout(ui, repo, node=None, rev=None, **opts):
177 '''reverse effect of earlier changeset
177 '''reverse effect of earlier changeset
178
178
179 Commit the backed out changes as a new changeset. The new
179 Commit the backed out changes as a new changeset. The new
180 changeset is a child of the backed out changeset.
180 changeset is a child of the backed out changeset.
181
181
182 If you back out a changeset other than the tip, a new head is
182 If you back out a changeset other than the tip, a new head is
183 created. This head will be the new tip and you should merge this
183 created. This head will be the new tip and you should merge this
184 backout changeset with another head (current one by default).
184 backout changeset with another head (current one by default).
185
185
186 The --merge option remembers the parent of the working directory
186 The --merge option remembers the parent of the working directory
187 before starting the backout, then merges the new head with that
187 before starting the backout, then merges the new head with that
188 changeset afterwards. This saves you from doing the merge by
188 changeset afterwards. This saves you from doing the merge by
189 hand. The result of this merge is not committed, as for a normal
189 hand. The result of this merge is not committed, as for a normal
190 merge.
190 merge.
191
191
192 See \'hg help dates\' for a list of formats valid for -d/--date.
192 See \'hg help dates\' for a list of formats valid for -d/--date.
193 '''
193 '''
194 if rev and node:
194 if rev and node:
195 raise util.Abort(_("please specify just one revision"))
195 raise util.Abort(_("please specify just one revision"))
196
196
197 if not rev:
197 if not rev:
198 rev = node
198 rev = node
199
199
200 if not rev:
200 if not rev:
201 raise util.Abort(_("please specify a revision to backout"))
201 raise util.Abort(_("please specify a revision to backout"))
202
202
203 date = opts.get('date')
203 date = opts.get('date')
204 if date:
204 if date:
205 opts['date'] = util.parsedate(date)
205 opts['date'] = util.parsedate(date)
206
206
207 cmdutil.bail_if_changed(repo)
207 cmdutil.bail_if_changed(repo)
208 node = repo.lookup(rev)
208 node = repo.lookup(rev)
209
209
210 op1, op2 = repo.dirstate.parents()
210 op1, op2 = repo.dirstate.parents()
211 a = repo.changelog.ancestor(op1, node)
211 a = repo.changelog.ancestor(op1, node)
212 if a != node:
212 if a != node:
213 raise util.Abort(_('cannot back out change on a different branch'))
213 raise util.Abort(_('cannot back out change on a different branch'))
214
214
215 p1, p2 = repo.changelog.parents(node)
215 p1, p2 = repo.changelog.parents(node)
216 if p1 == nullid:
216 if p1 == nullid:
217 raise util.Abort(_('cannot back out a change with no parents'))
217 raise util.Abort(_('cannot back out a change with no parents'))
218 if p2 != nullid:
218 if p2 != nullid:
219 if not opts.get('parent'):
219 if not opts.get('parent'):
220 raise util.Abort(_('cannot back out a merge changeset without '
220 raise util.Abort(_('cannot back out a merge changeset without '
221 '--parent'))
221 '--parent'))
222 p = repo.lookup(opts['parent'])
222 p = repo.lookup(opts['parent'])
223 if p not in (p1, p2):
223 if p not in (p1, p2):
224 raise util.Abort(_('%s is not a parent of %s') %
224 raise util.Abort(_('%s is not a parent of %s') %
225 (short(p), short(node)))
225 (short(p), short(node)))
226 parent = p
226 parent = p
227 else:
227 else:
228 if opts.get('parent'):
228 if opts.get('parent'):
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
230 parent = p1
230 parent = p1
231
231
232 # the backout should appear on the same branch
232 # the backout should appear on the same branch
233 branch = repo.dirstate.branch()
233 branch = repo.dirstate.branch()
234 hg.clean(repo, node, show_stats=False)
234 hg.clean(repo, node, show_stats=False)
235 repo.dirstate.setbranch(branch)
235 repo.dirstate.setbranch(branch)
236 revert_opts = opts.copy()
236 revert_opts = opts.copy()
237 revert_opts['date'] = None
237 revert_opts['date'] = None
238 revert_opts['all'] = True
238 revert_opts['all'] = True
239 revert_opts['rev'] = hex(parent)
239 revert_opts['rev'] = hex(parent)
240 revert_opts['no_backup'] = None
240 revert_opts['no_backup'] = None
241 revert(ui, repo, **revert_opts)
241 revert(ui, repo, **revert_opts)
242 commit_opts = opts.copy()
242 commit_opts = opts.copy()
243 commit_opts['addremove'] = False
243 commit_opts['addremove'] = False
244 if not commit_opts['message'] and not commit_opts['logfile']:
244 if not commit_opts['message'] and not commit_opts['logfile']:
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
246 commit_opts['force_editor'] = True
246 commit_opts['force_editor'] = True
247 commit(ui, repo, **commit_opts)
247 commit(ui, repo, **commit_opts)
248 def nice(node):
248 def nice(node):
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
249 return '%d:%s' % (repo.changelog.rev(node), short(node))
250 ui.status(_('changeset %s backs out changeset %s\n') %
250 ui.status(_('changeset %s backs out changeset %s\n') %
251 (nice(repo.changelog.tip()), nice(node)))
251 (nice(repo.changelog.tip()), nice(node)))
252 if op1 != node:
252 if op1 != node:
253 hg.clean(repo, op1, show_stats=False)
253 hg.clean(repo, op1, show_stats=False)
254 if opts.get('merge'):
254 if opts.get('merge'):
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
256 hg.merge(repo, hex(repo.changelog.tip()))
257 else:
257 else:
258 ui.status(_('the backout changeset is a new head - '
258 ui.status(_('the backout changeset is a new head - '
259 'do not forget to merge\n'))
259 'do not forget to merge\n'))
260 ui.status(_('(use "backout --merge" '
260 ui.status(_('(use "backout --merge" '
261 'if you want to auto-merge)\n'))
261 'if you want to auto-merge)\n'))
262
262
263 def bisect(ui, repo, rev=None, extra=None, command=None,
263 def bisect(ui, repo, rev=None, extra=None, command=None,
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
264 reset=None, good=None, bad=None, skip=None, noupdate=None):
265 """subdivision search of changesets
265 """subdivision search of changesets
266
266
267 This command helps to find changesets which introduce problems.
267 This command helps to find changesets which introduce problems.
268 To use, mark the earliest changeset you know exhibits the problem
268 To use, mark the earliest changeset you know exhibits the problem
269 as bad, then mark the latest changeset which is free from the
269 as bad, then mark the latest changeset which is free from the
270 problem as good. Bisect will update your working directory to a
270 problem as good. Bisect will update your working directory to a
271 revision for testing (unless the --noupdate option is specified).
271 revision for testing (unless the --noupdate option is specified).
272 Once you have performed tests, mark the working directory as bad
272 Once you have performed tests, mark the working directory as bad
273 or good and bisect will either update to another candidate changeset
273 or good and bisect will either update to another candidate changeset
274 or announce that it has found the bad revision.
274 or announce that it has found the bad revision.
275
275
276 As a shortcut, you can also use the revision argument to mark a
276 As a shortcut, you can also use the revision argument to mark a
277 revision as good or bad without checking it out first.
277 revision as good or bad without checking it out first.
278
278
279 If you supply a command it will be used for automatic bisection. Its exit
279 If you supply a command it will be used for automatic bisection. Its exit
280 status will be used as flag to mark revision as bad or good. In case exit
280 status will be used as flag to mark revision as bad or good. In case exit
281 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
281 status is 0 the revision is marked as good, 125 - skipped, 127 (command not
282 found) - bisection will be aborted and any other status bigger than 0 will
282 found) - bisection will be aborted and any other status bigger than 0 will
283 mark revision as bad.
283 mark revision as bad.
284 """
284 """
285 def print_result(nodes, good):
285 def print_result(nodes, good):
286 displayer = cmdutil.show_changeset(ui, repo, {})
286 displayer = cmdutil.show_changeset(ui, repo, {})
287 transition = (good and "good" or "bad")
287 transition = (good and "good" or "bad")
288 if len(nodes) == 1:
288 if len(nodes) == 1:
289 # narrowed it down to a single revision
289 # narrowed it down to a single revision
290 ui.write(_("The first %s revision is:\n") % transition)
290 ui.write(_("The first %s revision is:\n") % transition)
291 displayer.show(changenode=nodes[0])
291 displayer.show(changenode=nodes[0])
292 else:
292 else:
293 # multiple possible revisions
293 # multiple possible revisions
294 ui.write(_("Due to skipped revisions, the first "
294 ui.write(_("Due to skipped revisions, the first "
295 "%s revision could be any of:\n") % transition)
295 "%s revision could be any of:\n") % transition)
296 for n in nodes:
296 for n in nodes:
297 displayer.show(changenode=n)
297 displayer.show(changenode=n)
298
298
299 def check_state(state, interactive=True):
299 def check_state(state, interactive=True):
300 if not state['good'] or not state['bad']:
300 if not state['good'] or not state['bad']:
301 if (good or bad or skip or reset) and interactive:
301 if (good or bad or skip or reset) and interactive:
302 return
302 return
303 if not state['good']:
303 if not state['good']:
304 raise util.Abort(_('cannot bisect (no known good revisions)'))
304 raise util.Abort(_('cannot bisect (no known good revisions)'))
305 else:
305 else:
306 raise util.Abort(_('cannot bisect (no known bad revisions)'))
306 raise util.Abort(_('cannot bisect (no known bad revisions)'))
307 return True
307 return True
308
308
309 # backward compatibility
309 # backward compatibility
310 if rev in "good bad reset init".split():
310 if rev in "good bad reset init".split():
311 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
311 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
312 cmd, rev, extra = rev, extra, None
312 cmd, rev, extra = rev, extra, None
313 if cmd == "good":
313 if cmd == "good":
314 good = True
314 good = True
315 elif cmd == "bad":
315 elif cmd == "bad":
316 bad = True
316 bad = True
317 else:
317 else:
318 reset = True
318 reset = True
319 elif extra or good + bad + skip + reset + bool(command) > 1:
319 elif extra or good + bad + skip + reset + bool(command) > 1:
320 raise util.Abort(_('incompatible arguments'))
320 raise util.Abort(_('incompatible arguments'))
321
321
322 if reset:
322 if reset:
323 p = repo.join("bisect.state")
323 p = repo.join("bisect.state")
324 if os.path.exists(p):
324 if os.path.exists(p):
325 os.unlink(p)
325 os.unlink(p)
326 return
326 return
327
327
328 state = hbisect.load_state(repo)
328 state = hbisect.load_state(repo)
329
329
330 if command:
330 if command:
331 changesets = 1
331 changesets = 1
332 while changesets:
332 while changesets:
333 # update state
333 # update state
334 status = os.spawnlp(os.P_WAIT, command)
334 status = os.spawnlp(os.P_WAIT, command)
335 node = repo.lookup(rev or '.')
335 node = repo.lookup(rev or '.')
336 if status == 125:
336 if status == 125:
337 transition = "skip"
337 transition = "skip"
338 elif status == 0:
338 elif status == 0:
339 transition = "good"
339 transition = "good"
340 # status < 0 means process was killed
340 # status < 0 means process was killed
341 elif status == 127 or status < 0:
341 elif status == 127 or status < 0:
342 break
342 break
343 else:
343 else:
344 transition = "bad"
344 transition = "bad"
345 state[transition].append(node)
345 state[transition].append(node)
346 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
346 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
347 check_state(state, interactive=False)
347 check_state(state, interactive=False)
348 # bisect
348 # bisect
349 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
349 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
350 # update to next check
350 # update to next check
351 cmdutil.bail_if_changed(repo)
351 cmdutil.bail_if_changed(repo)
352 hg.clean(repo, nodes[0], show_stats=False)
352 hg.clean(repo, nodes[0], show_stats=False)
353 hbisect.save_state(repo, state)
353 hbisect.save_state(repo, state)
354 return print_result(nodes, not status)
354 return print_result(nodes, not status)
355
355
356 # update state
356 # update state
357 node = repo.lookup(rev or '.')
357 node = repo.lookup(rev or '.')
358 if good:
358 if good:
359 state['good'].append(node)
359 state['good'].append(node)
360 elif bad:
360 elif bad:
361 state['bad'].append(node)
361 state['bad'].append(node)
362 elif skip:
362 elif skip:
363 state['skip'].append(node)
363 state['skip'].append(node)
364
364
365 hbisect.save_state(repo, state)
365 hbisect.save_state(repo, state)
366
366
367 if not check_state(state):
367 if not check_state(state):
368 return
368 return
369
369
370 # actually bisect
370 # actually bisect
371 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
371 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
372 if changesets == 0:
372 if changesets == 0:
373 print_result(nodes, good)
373 print_result(nodes, good)
374 else:
374 else:
375 assert len(nodes) == 1 # only a single node can be tested next
375 assert len(nodes) == 1 # only a single node can be tested next
376 node = nodes[0]
376 node = nodes[0]
377 # compute the approximate number of remaining tests
377 # compute the approximate number of remaining tests
378 tests, size = 0, 2
378 tests, size = 0, 2
379 while size <= changesets:
379 while size <= changesets:
380 tests, size = tests + 1, size * 2
380 tests, size = tests + 1, size * 2
381 rev = repo.changelog.rev(node)
381 rev = repo.changelog.rev(node)
382 ui.write(_("Testing changeset %s:%s "
382 ui.write(_("Testing changeset %s:%s "
383 "(%s changesets remaining, ~%s tests)\n")
383 "(%s changesets remaining, ~%s tests)\n")
384 % (rev, short(node), changesets, tests))
384 % (rev, short(node), changesets, tests))
385 if not noupdate:
385 if not noupdate:
386 cmdutil.bail_if_changed(repo)
386 cmdutil.bail_if_changed(repo)
387 return hg.clean(repo, node)
387 return hg.clean(repo, node)
388
388
389 def branch(ui, repo, label=None, **opts):
389 def branch(ui, repo, label=None, **opts):
390 """set or show the current branch name
390 """set or show the current branch name
391
391
392 With no argument, show the current branch name. With one argument,
392 With no argument, show the current branch name. With one argument,
393 set the working directory branch name (the branch does not exist in
393 set the working directory branch name (the branch does not exist in
394 the repository until the next commit).
394 the repository until the next commit).
395
395
396 Unless --force is specified, branch will not let you set a
396 Unless --force is specified, branch will not let you set a
397 branch name that shadows an existing branch.
397 branch name that shadows an existing branch.
398
398
399 Use --clean to reset the working directory branch to that of the
399 Use --clean to reset the working directory branch to that of the
400 parent of the working directory, negating a previous branch change.
400 parent of the working directory, negating a previous branch change.
401
401
402 Use the command 'hg update' to switch to an existing branch.
402 Use the command 'hg update' to switch to an existing branch.
403 """
403 """
404
404
405 if opts.get('clean'):
405 if opts.get('clean'):
406 label = repo[None].parents()[0].branch()
406 label = repo[None].parents()[0].branch()
407 repo.dirstate.setbranch(label)
407 repo.dirstate.setbranch(label)
408 ui.status(_('reset working directory to branch %s\n') % label)
408 ui.status(_('reset working directory to branch %s\n') % label)
409 elif label:
409 elif label:
410 if not opts.get('force') and label in repo.branchtags():
410 if not opts.get('force') and label in repo.branchtags():
411 if label not in [p.branch() for p in repo.parents()]:
411 if label not in [p.branch() for p in repo.parents()]:
412 raise util.Abort(_('a branch of the same name already exists'
412 raise util.Abort(_('a branch of the same name already exists'
413 ' (use --force to override)'))
413 ' (use --force to override)'))
414 repo.dirstate.setbranch(util.fromlocal(label))
414 repo.dirstate.setbranch(util.fromlocal(label))
415 ui.status(_('marked working directory as branch %s\n') % label)
415 ui.status(_('marked working directory as branch %s\n') % label)
416 else:
416 else:
417 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
417 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
418
418
419 def branches(ui, repo, active=False):
419 def branches(ui, repo, active=False):
420 """list repository named branches
420 """list repository named branches
421
421
422 List the repository's named branches, indicating which ones are
422 List the repository's named branches, indicating which ones are
423 inactive. If active is specified, only show active branches.
423 inactive. If active is specified, only show active branches.
424
424
425 A branch is considered active if it contains repository heads.
425 A branch is considered active if it contains repository heads.
426
426
427 Use the command 'hg update' to switch to an existing branch.
427 Use the command 'hg update' to switch to an existing branch.
428 """
428 """
429 hexfunc = ui.debugflag and hex or short
429 hexfunc = ui.debugflag and hex or short
430 activebranches = [util.tolocal(repo[n].branch())
430 activebranches = [util.tolocal(repo[n].branch())
431 for n in repo.heads()]
431 for n in repo.heads()]
432 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
432 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
433 for tag, node in repo.branchtags().items()])
433 for tag, node in repo.branchtags().items()])
434 branches.reverse()
434 branches.reverse()
435
435
436 for isactive, node, tag in branches:
436 for isactive, node, tag in branches:
437 if (not active) or isactive:
437 if (not active) or isactive:
438 if ui.quiet:
438 if ui.quiet:
439 ui.write("%s\n" % tag)
439 ui.write("%s\n" % tag)
440 else:
440 else:
441 rev = str(node).rjust(31 - util.locallen(tag))
441 rev = str(node).rjust(31 - util.locallen(tag))
442 isinactive = ((not isactive) and " (inactive)") or ''
442 isinactive = ((not isactive) and " (inactive)") or ''
443 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
443 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
444 ui.write("%s %s:%s%s\n" % data)
444 ui.write("%s %s:%s%s\n" % data)
445
445
446 def bundle(ui, repo, fname, dest=None, **opts):
446 def bundle(ui, repo, fname, dest=None, **opts):
447 """create a changegroup file
447 """create a changegroup file
448
448
449 Generate a compressed changegroup file collecting changesets not
449 Generate a compressed changegroup file collecting changesets not
450 found in the other repository.
450 found in the other repository.
451
451
452 If no destination repository is specified the destination is
452 If no destination repository is specified the destination is
453 assumed to have all the nodes specified by one or more --base
453 assumed to have all the nodes specified by one or more --base
454 parameters. To create a bundle containing all changesets, use
454 parameters. To create a bundle containing all changesets, use
455 --all (or --base null). To change the compression method applied,
455 --all (or --base null). To change the compression method applied,
456 use the -t option (by default, bundles are compressed using bz2).
456 use the -t option (by default, bundles are compressed using bz2).
457
457
458 The bundle file can then be transferred using conventional means and
458 The bundle file can then be transferred using conventional means and
459 applied to another repository with the unbundle or pull command.
459 applied to another repository with the unbundle or pull command.
460 This is useful when direct push and pull are not available or when
460 This is useful when direct push and pull are not available or when
461 exporting an entire repository is undesirable.
461 exporting an entire repository is undesirable.
462
462
463 Applying bundles preserves all changeset contents including
463 Applying bundles preserves all changeset contents including
464 permissions, copy/rename information, and revision history.
464 permissions, copy/rename information, and revision history.
465 """
465 """
466 revs = opts.get('rev') or None
466 revs = opts.get('rev') or None
467 if revs:
467 if revs:
468 revs = [repo.lookup(rev) for rev in revs]
468 revs = [repo.lookup(rev) for rev in revs]
469 if opts.get('all'):
469 if opts.get('all'):
470 base = ['null']
470 base = ['null']
471 else:
471 else:
472 base = opts.get('base')
472 base = opts.get('base')
473 if base:
473 if base:
474 if dest:
474 if dest:
475 raise util.Abort(_("--base is incompatible with specifiying "
475 raise util.Abort(_("--base is incompatible with specifiying "
476 "a destination"))
476 "a destination"))
477 base = [repo.lookup(rev) for rev in base]
477 base = [repo.lookup(rev) for rev in base]
478 # create the right base
478 # create the right base
479 # XXX: nodesbetween / changegroup* should be "fixed" instead
479 # XXX: nodesbetween / changegroup* should be "fixed" instead
480 o = []
480 o = []
481 has = {nullid: None}
481 has = {nullid: None}
482 for n in base:
482 for n in base:
483 has.update(repo.changelog.reachable(n))
483 has.update(repo.changelog.reachable(n))
484 if revs:
484 if revs:
485 visit = list(revs)
485 visit = list(revs)
486 else:
486 else:
487 visit = repo.changelog.heads()
487 visit = repo.changelog.heads()
488 seen = {}
488 seen = {}
489 while visit:
489 while visit:
490 n = visit.pop(0)
490 n = visit.pop(0)
491 parents = [p for p in repo.changelog.parents(n) if p not in has]
491 parents = [p for p in repo.changelog.parents(n) if p not in has]
492 if len(parents) == 0:
492 if len(parents) == 0:
493 o.insert(0, n)
493 o.insert(0, n)
494 else:
494 else:
495 for p in parents:
495 for p in parents:
496 if p not in seen:
496 if p not in seen:
497 seen[p] = 1
497 seen[p] = 1
498 visit.append(p)
498 visit.append(p)
499 else:
499 else:
500 cmdutil.setremoteconfig(ui, opts)
500 cmdutil.setremoteconfig(ui, opts)
501 dest, revs, checkout = hg.parseurl(
501 dest, revs, checkout = hg.parseurl(
502 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
502 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
503 other = hg.repository(ui, dest)
503 other = hg.repository(ui, dest)
504 o = repo.findoutgoing(other, force=opts.get('force'))
504 o = repo.findoutgoing(other, force=opts.get('force'))
505
505
506 if revs:
506 if revs:
507 cg = repo.changegroupsubset(o, revs, 'bundle')
507 cg = repo.changegroupsubset(o, revs, 'bundle')
508 else:
508 else:
509 cg = repo.changegroup(o, 'bundle')
509 cg = repo.changegroup(o, 'bundle')
510
510
511 bundletype = opts.get('type', 'bzip2').lower()
511 bundletype = opts.get('type', 'bzip2').lower()
512 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
512 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
513 bundletype = btypes.get(bundletype)
513 bundletype = btypes.get(bundletype)
514 if bundletype not in changegroup.bundletypes:
514 if bundletype not in changegroup.bundletypes:
515 raise util.Abort(_('unknown bundle type specified with --type'))
515 raise util.Abort(_('unknown bundle type specified with --type'))
516
516
517 changegroup.writebundle(cg, fname, bundletype)
517 changegroup.writebundle(cg, fname, bundletype)
518
518
519 def cat(ui, repo, file1, *pats, **opts):
519 def cat(ui, repo, file1, *pats, **opts):
520 """output the current or given revision of files
520 """output the current or given revision of files
521
521
522 Print the specified files as they were at the given revision.
522 Print the specified files as they were at the given revision.
523 If no revision is given, the parent of the working directory is used,
523 If no revision is given, the parent of the working directory is used,
524 or tip if no revision is checked out.
524 or tip if no revision is checked out.
525
525
526 Output may be to a file, in which case the name of the file is
526 Output may be to a file, in which case the name of the file is
527 given using a format string. The formatting rules are the same as
527 given using a format string. The formatting rules are the same as
528 for the export command, with the following additions:
528 for the export command, with the following additions:
529
529
530 %s basename of file being printed
530 %s basename of file being printed
531 %d dirname of file being printed, or '.' if in repo root
531 %d dirname of file being printed, or '.' if in repo root
532 %p root-relative path name of file being printed
532 %p root-relative path name of file being printed
533 """
533 """
534 ctx = repo[opts.get('rev')]
534 ctx = repo[opts.get('rev')]
535 err = 1
535 err = 1
536 m = cmdutil.match(repo, (file1,) + pats, opts)
536 m = cmdutil.match(repo, (file1,) + pats, opts)
537 for abs in ctx.walk(m):
537 for abs in ctx.walk(m):
538 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
538 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
539 data = ctx[abs].data()
539 data = ctx[abs].data()
540 if opts.get('decode'):
540 if opts.get('decode'):
541 data = repo.wwritedata(abs, data)
541 data = repo.wwritedata(abs, data)
542 fp.write(data)
542 fp.write(data)
543 err = 0
543 err = 0
544 return err
544 return err
545
545
546 def clone(ui, source, dest=None, **opts):
546 def clone(ui, source, dest=None, **opts):
547 """make a copy of an existing repository
547 """make a copy of an existing repository
548
548
549 Create a copy of an existing repository in a new directory.
549 Create a copy of an existing repository in a new directory.
550
550
551 If no destination directory name is specified, it defaults to the
551 If no destination directory name is specified, it defaults to the
552 basename of the source.
552 basename of the source.
553
553
554 The location of the source is added to the new repository's
554 The location of the source is added to the new repository's
555 .hg/hgrc file, as the default to be used for future pulls.
555 .hg/hgrc file, as the default to be used for future pulls.
556
556
557 For efficiency, hardlinks are used for cloning whenever the source
557 For efficiency, hardlinks are used for cloning whenever the source
558 and destination are on the same filesystem (note this applies only
558 and destination are on the same filesystem (note this applies only
559 to the repository data, not to the checked out files). Some
559 to the repository data, not to the checked out files). Some
560 filesystems, such as AFS, implement hardlinking incorrectly, but
560 filesystems, such as AFS, implement hardlinking incorrectly, but
561 do not report errors. In these cases, use the --pull option to
561 do not report errors. In these cases, use the --pull option to
562 avoid hardlinking.
562 avoid hardlinking.
563
563
564 In some cases, you can clone repositories and checked out files
564 In some cases, you can clone repositories and checked out files
565 using full hardlinks with
565 using full hardlinks with
566
566
567 $ cp -al REPO REPOCLONE
567 $ cp -al REPO REPOCLONE
568
568
569 This is the fastest way to clone, but it is not always safe. The
569 This is the fastest way to clone, but it is not always safe. The
570 operation is not atomic (making sure REPO is not modified during
570 operation is not atomic (making sure REPO is not modified during
571 the operation is up to you) and you have to make sure your editor
571 the operation is up to you) and you have to make sure your editor
572 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
572 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
573 this is not compatible with certain extensions that place their
573 this is not compatible with certain extensions that place their
574 metadata under the .hg directory, such as mq.
574 metadata under the .hg directory, such as mq.
575
575
576 If you use the -r option to clone up to a specific revision, no
576 If you use the -r option to clone up to a specific revision, no
577 subsequent revisions will be present in the cloned repository.
577 subsequent revisions will be present in the cloned repository.
578 This option implies --pull, even on local repositories.
578 This option implies --pull, even on local repositories.
579
579
580 If the -U option is used, the new clone will contain only a repository
580 If the -U option is used, the new clone will contain only a repository
581 (.hg) and no working copy (the working copy parent is the null revision).
581 (.hg) and no working copy (the working copy parent is the null revision).
582
582
583 See pull for valid source format details.
583 See pull for valid source format details.
584
584
585 It is possible to specify an ssh:// URL as the destination, but no
585 It is possible to specify an ssh:// URL as the destination, but no
586 .hg/hgrc and working directory will be created on the remote side.
586 .hg/hgrc and working directory will be created on the remote side.
587 Look at the help text for the pull command for important details
587 Look at the help text for the pull command for important details
588 about ssh:// URLs.
588 about ssh:// URLs.
589 """
589 """
590 cmdutil.setremoteconfig(ui, opts)
590 cmdutil.setremoteconfig(ui, opts)
591 hg.clone(ui, source, dest,
591 hg.clone(ui, source, dest,
592 pull=opts.get('pull'),
592 pull=opts.get('pull'),
593 stream=opts.get('uncompressed'),
593 stream=opts.get('uncompressed'),
594 rev=opts.get('rev'),
594 rev=opts.get('rev'),
595 update=not opts.get('noupdate'))
595 update=not opts.get('noupdate'))
596
596
597 def commit(ui, repo, *pats, **opts):
597 def commit(ui, repo, *pats, **opts):
598 """commit the specified files or all outstanding changes
598 """commit the specified files or all outstanding changes
599
599
600 Commit changes to the given files into the repository.
600 Commit changes to the given files into the repository.
601
601
602 If a list of files is omitted, all changes reported by "hg status"
602 If a list of files is omitted, all changes reported by "hg status"
603 will be committed.
603 will be committed.
604
604
605 If you are committing the result of a merge, do not provide any
605 If you are committing the result of a merge, do not provide any
606 file names or -I/-X filters.
606 file names or -I/-X filters.
607
607
608 If no commit message is specified, the configured editor is started to
608 If no commit message is specified, the configured editor is started to
609 enter a message.
609 enter a message.
610
610
611 See 'hg help dates' for a list of formats valid for -d/--date.
611 See 'hg help dates' for a list of formats valid for -d/--date.
612 """
612 """
613 def commitfunc(ui, repo, message, match, opts):
613 def commitfunc(ui, repo, message, match, opts):
614 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
614 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
615 match, force_editor=opts.get('force_editor'))
615 match, force_editor=opts.get('force_editor'))
616
616
617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
617 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
618 if not node:
618 if not node:
619 return
619 return
620 cl = repo.changelog
620 cl = repo.changelog
621 rev = cl.rev(node)
621 rev = cl.rev(node)
622 parents = cl.parentrevs(rev)
622 parents = cl.parentrevs(rev)
623 if rev - 1 in parents:
623 if rev - 1 in parents:
624 # one of the parents was the old tip
624 # one of the parents was the old tip
625 pass
625 pass
626 elif (parents == (nullrev, nullrev) or
626 elif (parents == (nullrev, nullrev) or
627 len(cl.heads(cl.node(parents[0]))) > 1 and
627 len(cl.heads(cl.node(parents[0]))) > 1 and
628 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
628 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
629 ui.status(_('created new head\n'))
629 ui.status(_('created new head\n'))
630
630
631 if ui.debugflag:
631 if ui.debugflag:
632 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
632 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
633 elif ui.verbose:
633 elif ui.verbose:
634 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
634 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
635
635
636 def copy(ui, repo, *pats, **opts):
636 def copy(ui, repo, *pats, **opts):
637 """mark files as copied for the next commit
637 """mark files as copied for the next commit
638
638
639 Mark dest as having copies of source files. If dest is a
639 Mark dest as having copies of source files. If dest is a
640 directory, copies are put in that directory. If dest is a file,
640 directory, copies are put in that directory. If dest is a file,
641 there can only be one source.
641 there can only be one source.
642
642
643 By default, this command copies the contents of files as they
643 By default, this command copies the contents of files as they
644 stand in the working directory. If invoked with --after, the
644 stand in the working directory. If invoked with --after, the
645 operation is recorded, but no copying is performed.
645 operation is recorded, but no copying is performed.
646
646
647 This command takes effect in the next commit. To undo a copy
647 This command takes effect in the next commit. To undo a copy
648 before that, see hg revert.
648 before that, see hg revert.
649 """
649 """
650 wlock = repo.wlock(False)
650 wlock = repo.wlock(False)
651 try:
651 try:
652 return cmdutil.copy(ui, repo, pats, opts)
652 return cmdutil.copy(ui, repo, pats, opts)
653 finally:
653 finally:
654 del wlock
654 del wlock
655
655
656 def debugancestor(ui, repo, *args):
656 def debugancestor(ui, repo, *args):
657 """find the ancestor revision of two revisions in a given index"""
657 """find the ancestor revision of two revisions in a given index"""
658 if len(args) == 3:
658 if len(args) == 3:
659 index, rev1, rev2 = args
659 index, rev1, rev2 = args
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
660 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
661 lookup = r.lookup
661 lookup = r.lookup
662 elif len(args) == 2:
662 elif len(args) == 2:
663 if not repo:
663 if not repo:
664 raise util.Abort(_("There is no Mercurial repository here "
664 raise util.Abort(_("There is no Mercurial repository here "
665 "(.hg not found)"))
665 "(.hg not found)"))
666 rev1, rev2 = args
666 rev1, rev2 = args
667 r = repo.changelog
667 r = repo.changelog
668 lookup = repo.lookup
668 lookup = repo.lookup
669 else:
669 else:
670 raise util.Abort(_('either two or three arguments required'))
670 raise util.Abort(_('either two or three arguments required'))
671 a = r.ancestor(lookup(rev1), lookup(rev2))
671 a = r.ancestor(lookup(rev1), lookup(rev2))
672 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
672 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
673
673
674 def debugcomplete(ui, cmd='', **opts):
674 def debugcomplete(ui, cmd='', **opts):
675 """returns the completion list associated with the given command"""
675 """returns the completion list associated with the given command"""
676
676
677 if opts.get('options'):
677 if opts.get('options'):
678 options = []
678 options = []
679 otables = [globalopts]
679 otables = [globalopts]
680 if cmd:
680 if cmd:
681 aliases, entry = cmdutil.findcmd(cmd, table, False)
681 aliases, entry = cmdutil.findcmd(cmd, table, False)
682 otables.append(entry[1])
682 otables.append(entry[1])
683 for t in otables:
683 for t in otables:
684 for o in t:
684 for o in t:
685 if o[0]:
685 if o[0]:
686 options.append('-%s' % o[0])
686 options.append('-%s' % o[0])
687 options.append('--%s' % o[1])
687 options.append('--%s' % o[1])
688 ui.write("%s\n" % "\n".join(options))
688 ui.write("%s\n" % "\n".join(options))
689 return
689 return
690
690
691 ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table))))
691 ui.write("%s\n" % "\n".join(util.sort(cmdutil.findpossible(cmd, table))))
692
692
693 def debugfsinfo(ui, path = "."):
693 def debugfsinfo(ui, path = "."):
694 file('.debugfsinfo', 'w').write('')
694 file('.debugfsinfo', 'w').write('')
695 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
695 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
696 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
696 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
697 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
697 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
698 and 'yes' or 'no'))
698 and 'yes' or 'no'))
699 os.unlink('.debugfsinfo')
699 os.unlink('.debugfsinfo')
700
700
701 def debugrebuildstate(ui, repo, rev="tip"):
701 def debugrebuildstate(ui, repo, rev="tip"):
702 """rebuild the dirstate as it would look like for the given revision"""
702 """rebuild the dirstate as it would look like for the given revision"""
703 ctx = repo[rev]
703 ctx = repo[rev]
704 wlock = repo.wlock()
704 wlock = repo.wlock()
705 try:
705 try:
706 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
706 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
707 finally:
707 finally:
708 del wlock
708 del wlock
709
709
710 def debugcheckstate(ui, repo):
710 def debugcheckstate(ui, repo):
711 """validate the correctness of the current dirstate"""
711 """validate the correctness of the current dirstate"""
712 parent1, parent2 = repo.dirstate.parents()
712 parent1, parent2 = repo.dirstate.parents()
713 m1 = repo[parent1].manifest()
713 m1 = repo[parent1].manifest()
714 m2 = repo[parent2].manifest()
714 m2 = repo[parent2].manifest()
715 errors = 0
715 errors = 0
716 for f in repo.dirstate:
716 for f in repo.dirstate:
717 state = repo.dirstate[f]
717 state = repo.dirstate[f]
718 if state in "nr" and f not in m1:
718 if state in "nr" and f not in m1:
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
719 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
720 errors += 1
720 errors += 1
721 if state in "a" and f in m1:
721 if state in "a" and f in m1:
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
722 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
723 errors += 1
723 errors += 1
724 if state in "m" and f not in m1 and f not in m2:
724 if state in "m" and f not in m1 and f not in m2:
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
725 ui.warn(_("%s in state %s, but not in either manifest\n") %
726 (f, state))
726 (f, state))
727 errors += 1
727 errors += 1
728 for f in m1:
728 for f in m1:
729 state = repo.dirstate[f]
729 state = repo.dirstate[f]
730 if state not in "nrm":
730 if state not in "nrm":
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
731 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
732 errors += 1
732 errors += 1
733 if errors:
733 if errors:
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
734 error = _(".hg/dirstate inconsistent with current parent's manifest")
735 raise util.Abort(error)
735 raise util.Abort(error)
736
736
737 def showconfig(ui, repo, *values, **opts):
737 def showconfig(ui, repo, *values, **opts):
738 """show combined config settings from all hgrc files
738 """show combined config settings from all hgrc files
739
739
740 With no args, print names and values of all config items.
740 With no args, print names and values of all config items.
741
741
742 With one arg of the form section.name, print just the value of
742 With one arg of the form section.name, print just the value of
743 that config item.
743 that config item.
744
744
745 With multiple args, print names and values of all config items
745 With multiple args, print names and values of all config items
746 with matching section names."""
746 with matching section names."""
747
747
748 untrusted = bool(opts.get('untrusted'))
748 untrusted = bool(opts.get('untrusted'))
749 if values:
749 if values:
750 if len([v for v in values if '.' in v]) > 1:
750 if len([v for v in values if '.' in v]) > 1:
751 raise util.Abort(_('only one config item permitted'))
751 raise util.Abort(_('only one config item permitted'))
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
752 for section, name, value in ui.walkconfig(untrusted=untrusted):
753 sectname = section + '.' + name
753 sectname = section + '.' + name
754 if values:
754 if values:
755 for v in values:
755 for v in values:
756 if v == section:
756 if v == section:
757 ui.write('%s=%s\n' % (sectname, value))
757 ui.write('%s=%s\n' % (sectname, value))
758 elif v == sectname:
758 elif v == sectname:
759 ui.write(value, '\n')
759 ui.write(value, '\n')
760 else:
760 else:
761 ui.write('%s=%s\n' % (sectname, value))
761 ui.write('%s=%s\n' % (sectname, value))
762
762
763 def debugsetparents(ui, repo, rev1, rev2=None):
763 def debugsetparents(ui, repo, rev1, rev2=None):
764 """manually set the parents of the current working directory
764 """manually set the parents of the current working directory
765
765
766 This is useful for writing repository conversion tools, but should
766 This is useful for writing repository conversion tools, but should
767 be used with care.
767 be used with care.
768 """
768 """
769
769
770 if not rev2:
770 if not rev2:
771 rev2 = hex(nullid)
771 rev2 = hex(nullid)
772
772
773 wlock = repo.wlock()
773 wlock = repo.wlock()
774 try:
774 try:
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
775 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
776 finally:
776 finally:
777 del wlock
777 del wlock
778
778
779 def debugstate(ui, repo, nodates=None):
779 def debugstate(ui, repo, nodates=None):
780 """show the contents of the current dirstate"""
780 """show the contents of the current dirstate"""
781 timestr = ""
781 timestr = ""
782 showdate = not nodates
782 showdate = not nodates
783 for file_, ent in util.sort(repo.dirstate._map.items()):
783 for file_, ent in util.sort(repo.dirstate._map.items()):
784 if showdate:
784 if showdate:
785 if ent[3] == -1:
785 if ent[3] == -1:
786 # Pad or slice to locale representation
786 # Pad or slice to locale representation
787 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
787 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
788 timestr = 'unset'
788 timestr = 'unset'
789 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
789 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
790 else:
790 else:
791 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
791 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
792 if ent[1] & 020000:
792 if ent[1] & 020000:
793 mode = 'lnk'
793 mode = 'lnk'
794 else:
794 else:
795 mode = '%3o' % (ent[1] & 0777)
795 mode = '%3o' % (ent[1] & 0777)
796 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
796 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
797 for f in repo.dirstate.copies():
797 for f in repo.dirstate.copies():
798 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
798 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
799
799
800 def debugdata(ui, file_, rev):
800 def debugdata(ui, file_, rev):
801 """dump the contents of a data file revision"""
801 """dump the contents of a data file revision"""
802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
802 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
803 try:
803 try:
804 ui.write(r.revision(r.lookup(rev)))
804 ui.write(r.revision(r.lookup(rev)))
805 except KeyError:
805 except KeyError:
806 raise util.Abort(_('invalid revision identifier %s') % rev)
806 raise util.Abort(_('invalid revision identifier %s') % rev)
807
807
808 def debugdate(ui, date, range=None, **opts):
808 def debugdate(ui, date, range=None, **opts):
809 """parse and display a date"""
809 """parse and display a date"""
810 if opts["extended"]:
810 if opts["extended"]:
811 d = util.parsedate(date, util.extendeddateformats)
811 d = util.parsedate(date, util.extendeddateformats)
812 else:
812 else:
813 d = util.parsedate(date)
813 d = util.parsedate(date)
814 ui.write("internal: %s %s\n" % d)
814 ui.write("internal: %s %s\n" % d)
815 ui.write("standard: %s\n" % util.datestr(d))
815 ui.write("standard: %s\n" % util.datestr(d))
816 if range:
816 if range:
817 m = util.matchdate(range)
817 m = util.matchdate(range)
818 ui.write("match: %s\n" % m(d[0]))
818 ui.write("match: %s\n" % m(d[0]))
819
819
820 def debugindex(ui, file_):
820 def debugindex(ui, file_):
821 """dump the contents of an index file"""
821 """dump the contents of an index file"""
822 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
822 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
823 ui.write(" rev offset length base linkrev" +
823 ui.write(" rev offset length base linkrev" +
824 " nodeid p1 p2\n")
824 " nodeid p1 p2\n")
825 for i in r:
825 for i in r:
826 node = r.node(i)
826 node = r.node(i)
827 try:
827 try:
828 pp = r.parents(node)
828 pp = r.parents(node)
829 except:
829 except:
830 pp = [nullid, nullid]
830 pp = [nullid, nullid]
831 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
831 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
832 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
832 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
833 short(node), short(pp[0]), short(pp[1])))
833 short(node), short(pp[0]), short(pp[1])))
834
834
835 def debugindexdot(ui, file_):
835 def debugindexdot(ui, file_):
836 """dump an index DAG as a .dot file"""
836 """dump an index DAG as a .dot file"""
837 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
837 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
838 ui.write("digraph G {\n")
838 ui.write("digraph G {\n")
839 for i in r:
839 for i in r:
840 node = r.node(i)
840 node = r.node(i)
841 pp = r.parents(node)
841 pp = r.parents(node)
842 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
842 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
843 if pp[1] != nullid:
843 if pp[1] != nullid:
844 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
844 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
845 ui.write("}\n")
845 ui.write("}\n")
846
846
847 def debuginstall(ui):
847 def debuginstall(ui):
848 '''test Mercurial installation'''
848 '''test Mercurial installation'''
849
849
850 def writetemp(contents):
850 def writetemp(contents):
851 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
851 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
852 f = os.fdopen(fd, "wb")
852 f = os.fdopen(fd, "wb")
853 f.write(contents)
853 f.write(contents)
854 f.close()
854 f.close()
855 return name
855 return name
856
856
857 problems = 0
857 problems = 0
858
858
859 # encoding
859 # encoding
860 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
860 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
861 try:
861 try:
862 util.fromlocal("test")
862 util.fromlocal("test")
863 except util.Abort, inst:
863 except util.Abort, inst:
864 ui.write(" %s\n" % inst)
864 ui.write(" %s\n" % inst)
865 ui.write(_(" (check that your locale is properly set)\n"))
865 ui.write(_(" (check that your locale is properly set)\n"))
866 problems += 1
866 problems += 1
867
867
868 # compiled modules
868 # compiled modules
869 ui.status(_("Checking extensions...\n"))
869 ui.status(_("Checking extensions...\n"))
870 try:
870 try:
871 import bdiff, mpatch, base85
871 import bdiff, mpatch, base85
872 except Exception, inst:
872 except Exception, inst:
873 ui.write(" %s\n" % inst)
873 ui.write(" %s\n" % inst)
874 ui.write(_(" One or more extensions could not be found"))
874 ui.write(_(" One or more extensions could not be found"))
875 ui.write(_(" (check that you compiled the extensions)\n"))
875 ui.write(_(" (check that you compiled the extensions)\n"))
876 problems += 1
876 problems += 1
877
877
878 # templates
878 # templates
879 ui.status(_("Checking templates...\n"))
879 ui.status(_("Checking templates...\n"))
880 try:
880 try:
881 import templater
881 import templater
882 t = templater.templater(templater.templatepath("map-cmdline.default"))
882 t = templater.templater(templater.templatepath("map-cmdline.default"))
883 except Exception, inst:
883 except Exception, inst:
884 ui.write(" %s\n" % inst)
884 ui.write(" %s\n" % inst)
885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
885 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
886 problems += 1
886 problems += 1
887
887
888 # patch
888 # patch
889 ui.status(_("Checking patch...\n"))
889 ui.status(_("Checking patch...\n"))
890 patchproblems = 0
890 patchproblems = 0
891 a = "1\n2\n3\n4\n"
891 a = "1\n2\n3\n4\n"
892 b = "1\n2\n3\ninsert\n4\n"
892 b = "1\n2\n3\ninsert\n4\n"
893 fa = writetemp(a)
893 fa = writetemp(a)
894 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
894 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
895 os.path.basename(fa))
895 os.path.basename(fa))
896 fd = writetemp(d)
896 fd = writetemp(d)
897
897
898 files = {}
898 files = {}
899 try:
899 try:
900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
900 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
901 except util.Abort, e:
901 except util.Abort, e:
902 ui.write(_(" patch call failed:\n"))
902 ui.write(_(" patch call failed:\n"))
903 ui.write(" " + str(e) + "\n")
903 ui.write(" " + str(e) + "\n")
904 patchproblems += 1
904 patchproblems += 1
905 else:
905 else:
906 if list(files) != [os.path.basename(fa)]:
906 if list(files) != [os.path.basename(fa)]:
907 ui.write(_(" unexpected patch output!\n"))
907 ui.write(_(" unexpected patch output!\n"))
908 patchproblems += 1
908 patchproblems += 1
909 a = file(fa).read()
909 a = file(fa).read()
910 if a != b:
910 if a != b:
911 ui.write(_(" patch test failed!\n"))
911 ui.write(_(" patch test failed!\n"))
912 patchproblems += 1
912 patchproblems += 1
913
913
914 if patchproblems:
914 if patchproblems:
915 if ui.config('ui', 'patch'):
915 if ui.config('ui', 'patch'):
916 ui.write(_(" (Current patch tool may be incompatible with patch,"
916 ui.write(_(" (Current patch tool may be incompatible with patch,"
917 " or misconfigured. Please check your .hgrc file)\n"))
917 " or misconfigured. Please check your .hgrc file)\n"))
918 else:
918 else:
919 ui.write(_(" Internal patcher failure, please report this error"
919 ui.write(_(" Internal patcher failure, please report this error"
920 " to http://www.selenic.com/mercurial/bts\n"))
920 " to http://www.selenic.com/mercurial/bts\n"))
921 problems += patchproblems
921 problems += patchproblems
922
922
923 os.unlink(fa)
923 os.unlink(fa)
924 os.unlink(fd)
924 os.unlink(fd)
925
925
926 # editor
926 # editor
927 ui.status(_("Checking commit editor...\n"))
927 ui.status(_("Checking commit editor...\n"))
928 editor = ui.geteditor()
928 editor = ui.geteditor()
929 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
929 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
930 if not cmdpath:
930 if not cmdpath:
931 if editor == 'vi':
931 if editor == 'vi':
932 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
932 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
933 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
934 else:
934 else:
935 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
935 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
936 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
936 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
937 problems += 1
937 problems += 1
938
938
939 # check username
939 # check username
940 ui.status(_("Checking username...\n"))
940 ui.status(_("Checking username...\n"))
941 user = os.environ.get("HGUSER")
941 user = os.environ.get("HGUSER")
942 if user is None:
942 if user is None:
943 user = ui.config("ui", "username")
943 user = ui.config("ui", "username")
944 if user is None:
944 if user is None:
945 user = os.environ.get("EMAIL")
945 user = os.environ.get("EMAIL")
946 if not user:
946 if not user:
947 ui.warn(" ")
947 ui.warn(" ")
948 ui.username()
948 ui.username()
949 ui.write(_(" (specify a username in your .hgrc file)\n"))
949 ui.write(_(" (specify a username in your .hgrc file)\n"))
950
950
951 if not problems:
951 if not problems:
952 ui.status(_("No problems detected\n"))
952 ui.status(_("No problems detected\n"))
953 else:
953 else:
954 ui.write(_("%s problems detected,"
954 ui.write(_("%s problems detected,"
955 " please check your install!\n") % problems)
955 " please check your install!\n") % problems)
956
956
957 return problems
957 return problems
958
958
959 def debugrename(ui, repo, file1, *pats, **opts):
959 def debugrename(ui, repo, file1, *pats, **opts):
960 """dump rename information"""
960 """dump rename information"""
961
961
962 ctx = repo[opts.get('rev')]
962 ctx = repo[opts.get('rev')]
963 m = cmdutil.match(repo, (file1,) + pats, opts)
963 m = cmdutil.match(repo, (file1,) + pats, opts)
964 for abs in ctx.walk(m):
964 for abs in ctx.walk(m):
965 fctx = ctx[abs]
965 fctx = ctx[abs]
966 o = fctx.filelog().renamed(fctx.filenode())
966 o = fctx.filelog().renamed(fctx.filenode())
967 rel = m.rel(abs)
967 rel = m.rel(abs)
968 if o:
968 if o:
969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
969 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
970 else:
970 else:
971 ui.write(_("%s not renamed\n") % rel)
971 ui.write(_("%s not renamed\n") % rel)
972
972
973 def debugwalk(ui, repo, *pats, **opts):
973 def debugwalk(ui, repo, *pats, **opts):
974 """show how files match on given patterns"""
974 """show how files match on given patterns"""
975 m = cmdutil.match(repo, pats, opts)
975 m = cmdutil.match(repo, pats, opts)
976 items = list(repo.walk(m))
976 items = list(repo.walk(m))
977 if not items:
977 if not items:
978 return
978 return
979 fmt = 'f %%-%ds %%-%ds %%s' % (
979 fmt = 'f %%-%ds %%-%ds %%s' % (
980 max([len(abs) for abs in items]),
980 max([len(abs) for abs in items]),
981 max([len(m.rel(abs)) for abs in items]))
981 max([len(m.rel(abs)) for abs in items]))
982 for abs in items:
982 for abs in items:
983 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
983 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
984 ui.write("%s\n" % line.rstrip())
984 ui.write("%s\n" % line.rstrip())
985
985
986 def diff(ui, repo, *pats, **opts):
986 def diff(ui, repo, *pats, **opts):
987 """diff repository (or selected files)
987 """diff repository (or selected files)
988
988
989 Show differences between revisions for the specified files.
989 Show differences between revisions for the specified files.
990
990
991 Differences between files are shown using the unified diff format.
991 Differences between files are shown using the unified diff format.
992
992
993 NOTE: diff may generate unexpected results for merges, as it will
993 NOTE: diff may generate unexpected results for merges, as it will
994 default to comparing against the working directory's first parent
994 default to comparing against the working directory's first parent
995 changeset if no revisions are specified.
995 changeset if no revisions are specified.
996
996
997 When two revision arguments are given, then changes are shown
997 When two revision arguments are given, then changes are shown
998 between those revisions. If only one revision is specified then
998 between those revisions. If only one revision is specified then
999 that revision is compared to the working directory, and, when no
999 that revision is compared to the working directory, and, when no
1000 revisions are specified, the working directory files are compared
1000 revisions are specified, the working directory files are compared
1001 to its parent.
1001 to its parent.
1002
1002
1003 Without the -a option, diff will avoid generating diffs of files
1003 Without the -a option, diff will avoid generating diffs of files
1004 it detects as binary. With -a, diff will generate a diff anyway,
1004 it detects as binary. With -a, diff will generate a diff anyway,
1005 probably with undesirable results.
1005 probably with undesirable results.
1006 """
1006 """
1007 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1007 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1008
1008
1009 m = cmdutil.match(repo, pats, opts)
1009 m = cmdutil.match(repo, pats, opts)
1010 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1010 patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1011
1011
1012 def export(ui, repo, *changesets, **opts):
1012 def export(ui, repo, *changesets, **opts):
1013 """dump the header and diffs for one or more changesets
1013 """dump the header and diffs for one or more changesets
1014
1014
1015 Print the changeset header and diffs for one or more revisions.
1015 Print the changeset header and diffs for one or more revisions.
1016
1016
1017 The information shown in the changeset header is: author,
1017 The information shown in the changeset header is: author,
1018 changeset hash, parent(s) and commit comment.
1018 changeset hash, parent(s) and commit comment.
1019
1019
1020 NOTE: export may generate unexpected diff output for merge changesets,
1020 NOTE: export may generate unexpected diff output for merge changesets,
1021 as it will compare the merge changeset against its first parent only.
1021 as it will compare the merge changeset against its first parent only.
1022
1022
1023 Output may be to a file, in which case the name of the file is
1023 Output may be to a file, in which case the name of the file is
1024 given using a format string. The formatting rules are as follows:
1024 given using a format string. The formatting rules are as follows:
1025
1025
1026 %% literal "%" character
1026 %% literal "%" character
1027 %H changeset hash (40 bytes of hexadecimal)
1027 %H changeset hash (40 bytes of hexadecimal)
1028 %N number of patches being generated
1028 %N number of patches being generated
1029 %R changeset revision number
1029 %R changeset revision number
1030 %b basename of the exporting repository
1030 %b basename of the exporting repository
1031 %h short-form changeset hash (12 bytes of hexadecimal)
1031 %h short-form changeset hash (12 bytes of hexadecimal)
1032 %n zero-padded sequence number, starting at 1
1032 %n zero-padded sequence number, starting at 1
1033 %r zero-padded changeset revision number
1033 %r zero-padded changeset revision number
1034
1034
1035 Without the -a option, export will avoid generating diffs of files
1035 Without the -a option, export will avoid generating diffs of files
1036 it detects as binary. With -a, export will generate a diff anyway,
1036 it detects as binary. With -a, export will generate a diff anyway,
1037 probably with undesirable results.
1037 probably with undesirable results.
1038
1038
1039 With the --switch-parent option, the diff will be against the second
1039 With the --switch-parent option, the diff will be against the second
1040 parent. It can be useful to review a merge.
1040 parent. It can be useful to review a merge.
1041 """
1041 """
1042 if not changesets:
1042 if not changesets:
1043 raise util.Abort(_("export requires at least one changeset"))
1043 raise util.Abort(_("export requires at least one changeset"))
1044 revs = cmdutil.revrange(repo, changesets)
1044 revs = cmdutil.revrange(repo, changesets)
1045 if len(revs) > 1:
1045 if len(revs) > 1:
1046 ui.note(_('exporting patches:\n'))
1046 ui.note(_('exporting patches:\n'))
1047 else:
1047 else:
1048 ui.note(_('exporting patch:\n'))
1048 ui.note(_('exporting patch:\n'))
1049 patch.export(repo, revs, template=opts.get('output'),
1049 patch.export(repo, revs, template=opts.get('output'),
1050 switch_parent=opts.get('switch_parent'),
1050 switch_parent=opts.get('switch_parent'),
1051 opts=patch.diffopts(ui, opts))
1051 opts=patch.diffopts(ui, opts))
1052
1052
1053 def grep(ui, repo, pattern, *pats, **opts):
1053 def grep(ui, repo, pattern, *pats, **opts):
1054 """search for a pattern in specified files and revisions
1054 """search for a pattern in specified files and revisions
1055
1055
1056 Search revisions of files for a regular expression.
1056 Search revisions of files for a regular expression.
1057
1057
1058 This command behaves differently than Unix grep. It only accepts
1058 This command behaves differently than Unix grep. It only accepts
1059 Python/Perl regexps. It searches repository history, not the
1059 Python/Perl regexps. It searches repository history, not the
1060 working directory. It always prints the revision number in which
1060 working directory. It always prints the revision number in which
1061 a match appears.
1061 a match appears.
1062
1062
1063 By default, grep only prints output for the first revision of a
1063 By default, grep only prints output for the first revision of a
1064 file in which it finds a match. To get it to print every revision
1064 file in which it finds a match. To get it to print every revision
1065 that contains a change in match status ("-" for a match that
1065 that contains a change in match status ("-" for a match that
1066 becomes a non-match, or "+" for a non-match that becomes a match),
1066 becomes a non-match, or "+" for a non-match that becomes a match),
1067 use the --all flag.
1067 use the --all flag.
1068 """
1068 """
1069 reflags = 0
1069 reflags = 0
1070 if opts.get('ignore_case'):
1070 if opts.get('ignore_case'):
1071 reflags |= re.I
1071 reflags |= re.I
1072 try:
1072 try:
1073 regexp = re.compile(pattern, reflags)
1073 regexp = re.compile(pattern, reflags)
1074 except Exception, inst:
1074 except Exception, inst:
1075 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1075 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1076 return None
1076 return None
1077 sep, eol = ':', '\n'
1077 sep, eol = ':', '\n'
1078 if opts.get('print0'):
1078 if opts.get('print0'):
1079 sep = eol = '\0'
1079 sep = eol = '\0'
1080
1080
1081 fcache = {}
1081 fcache = {}
1082 def getfile(fn):
1082 def getfile(fn):
1083 if fn not in fcache:
1083 if fn not in fcache:
1084 fcache[fn] = repo.file(fn)
1084 fcache[fn] = repo.file(fn)
1085 return fcache[fn]
1085 return fcache[fn]
1086
1086
1087 def matchlines(body):
1087 def matchlines(body):
1088 begin = 0
1088 begin = 0
1089 linenum = 0
1089 linenum = 0
1090 while True:
1090 while True:
1091 match = regexp.search(body, begin)
1091 match = regexp.search(body, begin)
1092 if not match:
1092 if not match:
1093 break
1093 break
1094 mstart, mend = match.span()
1094 mstart, mend = match.span()
1095 linenum += body.count('\n', begin, mstart) + 1
1095 linenum += body.count('\n', begin, mstart) + 1
1096 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1096 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1097 begin = body.find('\n', mend) + 1 or len(body)
1097 begin = body.find('\n', mend) + 1 or len(body)
1098 lend = begin - 1
1098 lend = begin - 1
1099 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1099 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1100
1100
1101 class linestate(object):
1101 class linestate(object):
1102 def __init__(self, line, linenum, colstart, colend):
1102 def __init__(self, line, linenum, colstart, colend):
1103 self.line = line
1103 self.line = line
1104 self.linenum = linenum
1104 self.linenum = linenum
1105 self.colstart = colstart
1105 self.colstart = colstart
1106 self.colend = colend
1106 self.colend = colend
1107
1107
1108 def __hash__(self):
1108 def __hash__(self):
1109 return hash((self.linenum, self.line))
1109 return hash((self.linenum, self.line))
1110
1110
1111 def __eq__(self, other):
1111 def __eq__(self, other):
1112 return self.line == other.line
1112 return self.line == other.line
1113
1113
1114 matches = {}
1114 matches = {}
1115 copies = {}
1115 copies = {}
1116 def grepbody(fn, rev, body):
1116 def grepbody(fn, rev, body):
1117 matches[rev].setdefault(fn, [])
1117 matches[rev].setdefault(fn, [])
1118 m = matches[rev][fn]
1118 m = matches[rev][fn]
1119 for lnum, cstart, cend, line in matchlines(body):
1119 for lnum, cstart, cend, line in matchlines(body):
1120 s = linestate(line, lnum, cstart, cend)
1120 s = linestate(line, lnum, cstart, cend)
1121 m.append(s)
1121 m.append(s)
1122
1122
1123 def difflinestates(a, b):
1123 def difflinestates(a, b):
1124 sm = difflib.SequenceMatcher(None, a, b)
1124 sm = difflib.SequenceMatcher(None, a, b)
1125 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1125 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1126 if tag == 'insert':
1126 if tag == 'insert':
1127 for i in xrange(blo, bhi):
1127 for i in xrange(blo, bhi):
1128 yield ('+', b[i])
1128 yield ('+', b[i])
1129 elif tag == 'delete':
1129 elif tag == 'delete':
1130 for i in xrange(alo, ahi):
1130 for i in xrange(alo, ahi):
1131 yield ('-', a[i])
1131 yield ('-', a[i])
1132 elif tag == 'replace':
1132 elif tag == 'replace':
1133 for i in xrange(alo, ahi):
1133 for i in xrange(alo, ahi):
1134 yield ('-', a[i])
1134 yield ('-', a[i])
1135 for i in xrange(blo, bhi):
1135 for i in xrange(blo, bhi):
1136 yield ('+', b[i])
1136 yield ('+', b[i])
1137
1137
1138 prev = {}
1138 prev = {}
1139 def display(fn, rev, states, prevstates):
1139 def display(fn, rev, states, prevstates):
1140 datefunc = ui.quiet and util.shortdate or util.datestr
1140 datefunc = ui.quiet and util.shortdate or util.datestr
1141 found = False
1141 found = False
1142 filerevmatches = {}
1142 filerevmatches = {}
1143 r = prev.get(fn, -1)
1143 r = prev.get(fn, -1)
1144 if opts.get('all'):
1144 if opts.get('all'):
1145 iter = difflinestates(states, prevstates)
1145 iter = difflinestates(states, prevstates)
1146 else:
1146 else:
1147 iter = [('', l) for l in prevstates]
1147 iter = [('', l) for l in prevstates]
1148 for change, l in iter:
1148 for change, l in iter:
1149 cols = [fn, str(r)]
1149 cols = [fn, str(r)]
1150 if opts.get('line_number'):
1150 if opts.get('line_number'):
1151 cols.append(str(l.linenum))
1151 cols.append(str(l.linenum))
1152 if opts.get('all'):
1152 if opts.get('all'):
1153 cols.append(change)
1153 cols.append(change)
1154 if opts.get('user'):
1154 if opts.get('user'):
1155 cols.append(ui.shortuser(get(r)[1]))
1155 cols.append(ui.shortuser(get(r)[1]))
1156 if opts.get('date'):
1156 if opts.get('date'):
1157 cols.append(datefunc(get(r)[2]))
1157 cols.append(datefunc(get(r)[2]))
1158 if opts.get('files_with_matches'):
1158 if opts.get('files_with_matches'):
1159 c = (fn, r)
1159 c = (fn, r)
1160 if c in filerevmatches:
1160 if c in filerevmatches:
1161 continue
1161 continue
1162 filerevmatches[c] = 1
1162 filerevmatches[c] = 1
1163 else:
1163 else:
1164 cols.append(l.line)
1164 cols.append(l.line)
1165 ui.write(sep.join(cols), eol)
1165 ui.write(sep.join(cols), eol)
1166 found = True
1166 found = True
1167 return found
1167 return found
1168
1168
1169 fstate = {}
1169 fstate = {}
1170 skip = {}
1170 skip = {}
1171 get = util.cachefunc(lambda r: repo[r].changeset())
1171 get = util.cachefunc(lambda r: repo[r].changeset())
1172 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1172 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1173 found = False
1173 found = False
1174 follow = opts.get('follow')
1174 follow = opts.get('follow')
1175 for st, rev, fns in changeiter:
1175 for st, rev, fns in changeiter:
1176 if st == 'window':
1176 if st == 'window':
1177 matches.clear()
1177 matches.clear()
1178 elif st == 'add':
1178 elif st == 'add':
1179 ctx = repo[rev]
1179 ctx = repo[rev]
1180 matches[rev] = {}
1180 matches[rev] = {}
1181 for fn in fns:
1181 for fn in fns:
1182 if fn in skip:
1182 if fn in skip:
1183 continue
1183 continue
1184 try:
1184 try:
1185 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1185 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1186 fstate.setdefault(fn, [])
1186 fstate.setdefault(fn, [])
1187 if follow:
1187 if follow:
1188 copied = getfile(fn).renamed(ctx.filenode(fn))
1188 copied = getfile(fn).renamed(ctx.filenode(fn))
1189 if copied:
1189 if copied:
1190 copies.setdefault(rev, {})[fn] = copied[0]
1190 copies.setdefault(rev, {})[fn] = copied[0]
1191 except revlog.LookupError:
1191 except revlog.LookupError:
1192 pass
1192 pass
1193 elif st == 'iter':
1193 elif st == 'iter':
1194 for fn, m in util.sort(matches[rev].items()):
1194 for fn, m in util.sort(matches[rev].items()):
1195 copy = copies.get(rev, {}).get(fn)
1195 copy = copies.get(rev, {}).get(fn)
1196 if fn in skip:
1196 if fn in skip:
1197 if copy:
1197 if copy:
1198 skip[copy] = True
1198 skip[copy] = True
1199 continue
1199 continue
1200 if fn in prev or fstate[fn]:
1200 if fn in prev or fstate[fn]:
1201 r = display(fn, rev, m, fstate[fn])
1201 r = display(fn, rev, m, fstate[fn])
1202 found = found or r
1202 found = found or r
1203 if r and not opts.get('all'):
1203 if r and not opts.get('all'):
1204 skip[fn] = True
1204 skip[fn] = True
1205 if copy:
1205 if copy:
1206 skip[copy] = True
1206 skip[copy] = True
1207 fstate[fn] = m
1207 fstate[fn] = m
1208 if copy:
1208 if copy:
1209 fstate[copy] = m
1209 fstate[copy] = m
1210 prev[fn] = rev
1210 prev[fn] = rev
1211
1211
1212 for fn, state in util.sort(fstate.items()):
1212 for fn, state in util.sort(fstate.items()):
1213 if fn in skip:
1213 if fn in skip:
1214 continue
1214 continue
1215 if fn not in copies.get(prev[fn], {}):
1215 if fn not in copies.get(prev[fn], {}):
1216 found = display(fn, rev, {}, state) or found
1216 found = display(fn, rev, {}, state) or found
1217 return (not found and 1) or 0
1217 return (not found and 1) or 0
1218
1218
1219 def heads(ui, repo, *branchrevs, **opts):
1219 def heads(ui, repo, *branchrevs, **opts):
1220 """show current repository heads or show branch heads
1220 """show current repository heads or show branch heads
1221
1221
1222 With no arguments, show all repository head changesets.
1222 With no arguments, show all repository head changesets.
1223
1223
1224 If branch or revisions names are given this will show the heads of
1224 If branch or revisions names are given this will show the heads of
1225 the specified branches or the branches those revisions are tagged
1225 the specified branches or the branches those revisions are tagged
1226 with.
1226 with.
1227
1227
1228 Repository "heads" are changesets that don't have child
1228 Repository "heads" are changesets that don't have child
1229 changesets. They are where development generally takes place and
1229 changesets. They are where development generally takes place and
1230 are the usual targets for update and merge operations.
1230 are the usual targets for update and merge operations.
1231
1231
1232 Branch heads are changesets that have a given branch tag, but have
1232 Branch heads are changesets that have a given branch tag, but have
1233 no child changesets with that tag. They are usually where
1233 no child changesets with that tag. They are usually where
1234 development on the given branch takes place.
1234 development on the given branch takes place.
1235 """
1235 """
1236 if opts.get('rev'):
1236 if opts.get('rev'):
1237 start = repo.lookup(opts['rev'])
1237 start = repo.lookup(opts['rev'])
1238 else:
1238 else:
1239 start = None
1239 start = None
1240 if not branchrevs:
1240 if not branchrevs:
1241 # Assume we're looking repo-wide heads if no revs were specified.
1241 # Assume we're looking repo-wide heads if no revs were specified.
1242 heads = repo.heads(start)
1242 heads = repo.heads(start)
1243 else:
1243 else:
1244 heads = []
1244 heads = []
1245 visitedset = util.set()
1245 visitedset = util.set()
1246 for branchrev in branchrevs:
1246 for branchrev in branchrevs:
1247 branch = repo[branchrev].branch()
1247 branch = repo[branchrev].branch()
1248 if branch in visitedset:
1248 if branch in visitedset:
1249 continue
1249 continue
1250 visitedset.add(branch)
1250 visitedset.add(branch)
1251 bheads = repo.branchheads(branch, start)
1251 bheads = repo.branchheads(branch, start)
1252 if not bheads:
1252 if not bheads:
1253 if branch != branchrev:
1253 if branch != branchrev:
1254 ui.warn(_("no changes on branch %s containing %s are "
1254 ui.warn(_("no changes on branch %s containing %s are "
1255 "reachable from %s\n")
1255 "reachable from %s\n")
1256 % (branch, branchrev, opts.get('rev')))
1256 % (branch, branchrev, opts.get('rev')))
1257 else:
1257 else:
1258 ui.warn(_("no changes on branch %s are reachable from %s\n")
1258 ui.warn(_("no changes on branch %s are reachable from %s\n")
1259 % (branch, opts.get('rev')))
1259 % (branch, opts.get('rev')))
1260 heads.extend(bheads)
1260 heads.extend(bheads)
1261 if not heads:
1261 if not heads:
1262 return 1
1262 return 1
1263 displayer = cmdutil.show_changeset(ui, repo, opts)
1263 displayer = cmdutil.show_changeset(ui, repo, opts)
1264 for n in heads:
1264 for n in heads:
1265 displayer.show(changenode=n)
1265 displayer.show(changenode=n)
1266
1266
1267 def help_(ui, name=None, with_version=False):
1267 def help_(ui, name=None, with_version=False):
1268 """show help for a given topic or a help overview
1268 """show help for a given topic or a help overview
1269
1269
1270 With no arguments, print a list of commands and short help.
1270 With no arguments, print a list of commands and short help.
1271
1271
1272 Given a topic, extension, or command name, print help for that topic."""
1272 Given a topic, extension, or command name, print help for that topic."""
1273 option_lists = []
1273 option_lists = []
1274
1274
1275 def addglobalopts(aliases):
1275 def addglobalopts(aliases):
1276 if ui.verbose:
1276 if ui.verbose:
1277 option_lists.append((_("global options:"), globalopts))
1277 option_lists.append((_("global options:"), globalopts))
1278 if name == 'shortlist':
1278 if name == 'shortlist':
1279 option_lists.append((_('use "hg help" for the full list '
1279 option_lists.append((_('use "hg help" for the full list '
1280 'of commands'), ()))
1280 'of commands'), ()))
1281 else:
1281 else:
1282 if name == 'shortlist':
1282 if name == 'shortlist':
1283 msg = _('use "hg help" for the full list of commands '
1283 msg = _('use "hg help" for the full list of commands '
1284 'or "hg -v" for details')
1284 'or "hg -v" for details')
1285 elif aliases:
1285 elif aliases:
1286 msg = _('use "hg -v help%s" to show aliases and '
1286 msg = _('use "hg -v help%s" to show aliases and '
1287 'global options') % (name and " " + name or "")
1287 'global options') % (name and " " + name or "")
1288 else:
1288 else:
1289 msg = _('use "hg -v help %s" to show global options') % name
1289 msg = _('use "hg -v help %s" to show global options') % name
1290 option_lists.append((msg, ()))
1290 option_lists.append((msg, ()))
1291
1291
1292 def helpcmd(name):
1292 def helpcmd(name):
1293 if with_version:
1293 if with_version:
1294 version_(ui)
1294 version_(ui)
1295 ui.write('\n')
1295 ui.write('\n')
1296
1296
1297 try:
1297 try:
1298 aliases, i = cmdutil.findcmd(name, table, False)
1298 aliases, i = cmdutil.findcmd(name, table, False)
1299 except cmdutil.AmbiguousCommand, inst:
1299 except cmdutil.AmbiguousCommand, inst:
1300 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1300 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1301 helplist(_('list of commands:\n\n'), select)
1301 helplist(_('list of commands:\n\n'), select)
1302 return
1302 return
1303
1303
1304 # synopsis
1304 # synopsis
1305 ui.write("%s\n" % i[2])
1305 ui.write("%s\n" % i[2])
1306
1306
1307 # aliases
1307 # aliases
1308 if not ui.quiet and len(aliases) > 1:
1308 if not ui.quiet and len(aliases) > 1:
1309 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1309 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1310
1310
1311 # description
1311 # description
1312 doc = gettext(i[0].__doc__)
1312 doc = gettext(i[0].__doc__)
1313 if not doc:
1313 if not doc:
1314 doc = _("(No help text available)")
1314 doc = _("(No help text available)")
1315 if ui.quiet:
1315 if ui.quiet:
1316 doc = doc.splitlines(0)[0]
1316 doc = doc.splitlines(0)[0]
1317 ui.write("\n%s\n" % doc.rstrip())
1317 ui.write("\n%s\n" % doc.rstrip())
1318
1318
1319 if not ui.quiet:
1319 if not ui.quiet:
1320 # options
1320 # options
1321 if i[1]:
1321 if i[1]:
1322 option_lists.append((_("options:\n"), i[1]))
1322 option_lists.append((_("options:\n"), i[1]))
1323
1323
1324 addglobalopts(False)
1324 addglobalopts(False)
1325
1325
1326 def helplist(header, select=None):
1326 def helplist(header, select=None):
1327 h = {}
1327 h = {}
1328 cmds = {}
1328 cmds = {}
1329 for c, e in table.items():
1329 for c, e in table.items():
1330 f = c.split("|", 1)[0]
1330 f = c.split("|", 1)[0]
1331 if select and not select(f):
1331 if select and not select(f):
1332 continue
1332 continue
1333 if (not select and name != 'shortlist' and
1333 if (not select and name != 'shortlist' and
1334 e[0].__module__ != __name__):
1334 e[0].__module__ != __name__):
1335 continue
1335 continue
1336 if name == "shortlist" and not f.startswith("^"):
1336 if name == "shortlist" and not f.startswith("^"):
1337 continue
1337 continue
1338 f = f.lstrip("^")
1338 f = f.lstrip("^")
1339 if not ui.debugflag and f.startswith("debug"):
1339 if not ui.debugflag and f.startswith("debug"):
1340 continue
1340 continue
1341 doc = gettext(e[0].__doc__)
1341 doc = gettext(e[0].__doc__)
1342 if not doc:
1342 if not doc:
1343 doc = _("(No help text available)")
1343 doc = _("(No help text available)")
1344 h[f] = doc.splitlines(0)[0].rstrip()
1344 h[f] = doc.splitlines(0)[0].rstrip()
1345 cmds[f] = c.lstrip("^")
1345 cmds[f] = c.lstrip("^")
1346
1346
1347 if not h:
1347 if not h:
1348 ui.status(_('no commands defined\n'))
1348 ui.status(_('no commands defined\n'))
1349 return
1349 return
1350
1350
1351 ui.status(header)
1351 ui.status(header)
1352 fns = util.sort(h)
1352 fns = util.sort(h)
1353 m = max(map(len, fns))
1353 m = max(map(len, fns))
1354 for f in fns:
1354 for f in fns:
1355 if ui.verbose:
1355 if ui.verbose:
1356 commands = cmds[f].replace("|",", ")
1356 commands = cmds[f].replace("|",", ")
1357 ui.write(" %s:\n %s\n"%(commands, h[f]))
1357 ui.write(" %s:\n %s\n"%(commands, h[f]))
1358 else:
1358 else:
1359 ui.write(' %-*s %s\n' % (m, f, h[f]))
1359 ui.write(' %-*s %s\n' % (m, f, h[f]))
1360
1360
1361 exts = list(extensions.extensions())
1361 exts = list(extensions.extensions())
1362 if exts and name != 'shortlist':
1362 if exts and name != 'shortlist':
1363 ui.write(_('\nenabled extensions:\n\n'))
1363 ui.write(_('\nenabled extensions:\n\n'))
1364 maxlength = 0
1364 maxlength = 0
1365 exthelps = []
1365 exthelps = []
1366 for ename, ext in exts:
1366 for ename, ext in exts:
1367 doc = (ext.__doc__ or _('(no help text available)'))
1367 doc = (ext.__doc__ or _('(no help text available)'))
1368 ename = ename.split('.')[-1]
1368 ename = ename.split('.')[-1]
1369 maxlength = max(len(ename), maxlength)
1369 maxlength = max(len(ename), maxlength)
1370 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1370 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1371 for ename, text in exthelps:
1371 for ename, text in exthelps:
1372 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1372 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1373
1373
1374 if not ui.quiet:
1374 if not ui.quiet:
1375 addglobalopts(True)
1375 addglobalopts(True)
1376
1376
1377 def helptopic(name):
1377 def helptopic(name):
1378 for names, header, doc in help.helptable:
1378 for names, header, doc in help.helptable:
1379 if name in names:
1379 if name in names:
1380 break
1380 break
1381 else:
1381 else:
1382 raise cmdutil.UnknownCommand(name)
1382 raise cmdutil.UnknownCommand(name)
1383
1383
1384 # description
1384 # description
1385 if not doc:
1385 if not doc:
1386 doc = _("(No help text available)")
1386 doc = _("(No help text available)")
1387 if callable(doc):
1387 if callable(doc):
1388 doc = doc()
1388 doc = doc()
1389
1389
1390 ui.write("%s\n" % header)
1390 ui.write("%s\n" % header)
1391 ui.write("%s\n" % doc.rstrip())
1391 ui.write("%s\n" % doc.rstrip())
1392
1392
1393 def helpext(name):
1393 def helpext(name):
1394 try:
1394 try:
1395 mod = extensions.find(name)
1395 mod = extensions.find(name)
1396 except KeyError:
1396 except KeyError:
1397 raise cmdutil.UnknownCommand(name)
1397 raise cmdutil.UnknownCommand(name)
1398
1398
1399 doc = gettext(mod.__doc__) or _('No help text available')
1399 doc = gettext(mod.__doc__) or _('No help text available')
1400 doc = doc.splitlines(0)
1400 doc = doc.splitlines(0)
1401 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1401 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1402 for d in doc[1:]:
1402 for d in doc[1:]:
1403 ui.write(d, '\n')
1403 ui.write(d, '\n')
1404
1404
1405 ui.status('\n')
1405 ui.status('\n')
1406
1406
1407 try:
1407 try:
1408 ct = mod.cmdtable
1408 ct = mod.cmdtable
1409 except AttributeError:
1409 except AttributeError:
1410 ct = {}
1410 ct = {}
1411
1411
1412 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1412 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1413 helplist(_('list of commands:\n\n'), modcmds.has_key)
1413 helplist(_('list of commands:\n\n'), modcmds.has_key)
1414
1414
1415 if name and name != 'shortlist':
1415 if name and name != 'shortlist':
1416 i = None
1416 i = None
1417 for f in (helpcmd, helptopic, helpext):
1417 for f in (helpcmd, helptopic, helpext):
1418 try:
1418 try:
1419 f(name)
1419 f(name)
1420 i = None
1420 i = None
1421 break
1421 break
1422 except cmdutil.UnknownCommand, inst:
1422 except cmdutil.UnknownCommand, inst:
1423 i = inst
1423 i = inst
1424 if i:
1424 if i:
1425 raise i
1425 raise i
1426
1426
1427 else:
1427 else:
1428 # program name
1428 # program name
1429 if ui.verbose or with_version:
1429 if ui.verbose or with_version:
1430 version_(ui)
1430 version_(ui)
1431 else:
1431 else:
1432 ui.status(_("Mercurial Distributed SCM\n"))
1432 ui.status(_("Mercurial Distributed SCM\n"))
1433 ui.status('\n')
1433 ui.status('\n')
1434
1434
1435 # list of commands
1435 # list of commands
1436 if name == "shortlist":
1436 if name == "shortlist":
1437 header = _('basic commands:\n\n')
1437 header = _('basic commands:\n\n')
1438 else:
1438 else:
1439 header = _('list of commands:\n\n')
1439 header = _('list of commands:\n\n')
1440
1440
1441 helplist(header)
1441 helplist(header)
1442
1442
1443 # list all option lists
1443 # list all option lists
1444 opt_output = []
1444 opt_output = []
1445 for title, options in option_lists:
1445 for title, options in option_lists:
1446 opt_output.append(("\n%s" % title, None))
1446 opt_output.append(("\n%s" % title, None))
1447 for shortopt, longopt, default, desc in options:
1447 for shortopt, longopt, default, desc in options:
1448 if "DEPRECATED" in desc and not ui.verbose: continue
1448 if "DEPRECATED" in desc and not ui.verbose: continue
1449 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1449 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1450 longopt and " --%s" % longopt),
1450 longopt and " --%s" % longopt),
1451 "%s%s" % (desc,
1451 "%s%s" % (desc,
1452 default
1452 default
1453 and _(" (default: %s)") % default
1453 and _(" (default: %s)") % default
1454 or "")))
1454 or "")))
1455
1455
1456 if not name:
1456 if not name:
1457 ui.write(_("\nadditional help topics:\n\n"))
1457 ui.write(_("\nadditional help topics:\n\n"))
1458 topics = []
1458 topics = []
1459 for names, header, doc in help.helptable:
1459 for names, header, doc in help.helptable:
1460 names = [(-len(name), name) for name in names]
1460 names = [(-len(name), name) for name in names]
1461 names.sort()
1461 names.sort()
1462 topics.append((names[0][1], header))
1462 topics.append((names[0][1], header))
1463 topics_len = max([len(s[0]) for s in topics])
1463 topics_len = max([len(s[0]) for s in topics])
1464 for t, desc in topics:
1464 for t, desc in topics:
1465 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1465 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1466
1466
1467 if opt_output:
1467 if opt_output:
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1468 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1469 for first, second in opt_output:
1469 for first, second in opt_output:
1470 if second:
1470 if second:
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1471 ui.write(" %-*s %s\n" % (opts_len, first, second))
1472 else:
1472 else:
1473 ui.write("%s\n" % first)
1473 ui.write("%s\n" % first)
1474
1474
1475 def identify(ui, repo, source=None,
1475 def identify(ui, repo, source=None,
1476 rev=None, num=None, id=None, branch=None, tags=None):
1476 rev=None, num=None, id=None, branch=None, tags=None):
1477 """identify the working copy or specified revision
1477 """identify the working copy or specified revision
1478
1478
1479 With no revision, print a summary of the current state of the repo.
1479 With no revision, print a summary of the current state of the repo.
1480
1480
1481 With a path, do a lookup in another repository.
1481 With a path, do a lookup in another repository.
1482
1482
1483 This summary identifies the repository state using one or two parent
1483 This summary identifies the repository state using one or two parent
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1484 hash identifiers, followed by a "+" if there are uncommitted changes
1485 in the working directory, a list of tags for this revision and a branch
1485 in the working directory, a list of tags for this revision and a branch
1486 name for non-default branches.
1486 name for non-default branches.
1487 """
1487 """
1488
1488
1489 if not repo and not source:
1489 if not repo and not source:
1490 raise util.Abort(_("There is no Mercurial repository here "
1490 raise util.Abort(_("There is no Mercurial repository here "
1491 "(.hg not found)"))
1491 "(.hg not found)"))
1492
1492
1493 hexfunc = ui.debugflag and hex or short
1493 hexfunc = ui.debugflag and hex or short
1494 default = not (num or id or branch or tags)
1494 default = not (num or id or branch or tags)
1495 output = []
1495 output = []
1496
1496
1497 if source:
1497 if source:
1498 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1498 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1499 srepo = hg.repository(ui, source)
1499 srepo = hg.repository(ui, source)
1500 if not rev and revs:
1500 if not rev and revs:
1501 rev = revs[0]
1501 rev = revs[0]
1502 if not rev:
1502 if not rev:
1503 rev = "tip"
1503 rev = "tip"
1504 if num or branch or tags:
1504 if num or branch or tags:
1505 raise util.Abort(
1505 raise util.Abort(
1506 "can't query remote revision number, branch, or tags")
1506 "can't query remote revision number, branch, or tags")
1507 output = [hexfunc(srepo.lookup(rev))]
1507 output = [hexfunc(srepo.lookup(rev))]
1508 elif not rev:
1508 elif not rev:
1509 ctx = repo[None]
1509 ctx = repo[None]
1510 parents = ctx.parents()
1510 parents = ctx.parents()
1511 changed = False
1511 changed = False
1512 if default or id or num:
1512 if default or id or num:
1513 changed = ctx.files() + ctx.deleted()
1513 changed = ctx.files() + ctx.deleted()
1514 if default or id:
1514 if default or id:
1515 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1515 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1516 (changed) and "+" or "")]
1516 (changed) and "+" or "")]
1517 if num:
1517 if num:
1518 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1518 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1519 (changed) and "+" or ""))
1519 (changed) and "+" or ""))
1520 else:
1520 else:
1521 ctx = repo[rev]
1521 ctx = repo[rev]
1522 if default or id:
1522 if default or id:
1523 output = [hexfunc(ctx.node())]
1523 output = [hexfunc(ctx.node())]
1524 if num:
1524 if num:
1525 output.append(str(ctx.rev()))
1525 output.append(str(ctx.rev()))
1526
1526
1527 if not source and default and not ui.quiet:
1527 if not source and default and not ui.quiet:
1528 b = util.tolocal(ctx.branch())
1528 b = util.tolocal(ctx.branch())
1529 if b != 'default':
1529 if b != 'default':
1530 output.append("(%s)" % b)
1530 output.append("(%s)" % b)
1531
1531
1532 # multiple tags for a single parent separated by '/'
1532 # multiple tags for a single parent separated by '/'
1533 t = "/".join(ctx.tags())
1533 t = "/".join(ctx.tags())
1534 if t:
1534 if t:
1535 output.append(t)
1535 output.append(t)
1536
1536
1537 if branch:
1537 if branch:
1538 output.append(util.tolocal(ctx.branch()))
1538 output.append(util.tolocal(ctx.branch()))
1539
1539
1540 if tags:
1540 if tags:
1541 output.extend(ctx.tags())
1541 output.extend(ctx.tags())
1542
1542
1543 ui.write("%s\n" % ' '.join(output))
1543 ui.write("%s\n" % ' '.join(output))
1544
1544
1545 def import_(ui, repo, patch1, *patches, **opts):
1545 def import_(ui, repo, patch1, *patches, **opts):
1546 """import an ordered set of patches
1546 """import an ordered set of patches
1547
1547
1548 Import a list of patches and commit them individually.
1548 Import a list of patches and commit them individually.
1549
1549
1550 If there are outstanding changes in the working directory, import
1550 If there are outstanding changes in the working directory, import
1551 will abort unless given the -f flag.
1551 will abort unless given the -f flag.
1552
1552
1553 You can import a patch straight from a mail message. Even patches
1553 You can import a patch straight from a mail message. Even patches
1554 as attachments work (body part must be type text/plain or
1554 as attachments work (body part must be type text/plain or
1555 text/x-patch to be used). From and Subject headers of email
1555 text/x-patch to be used). From and Subject headers of email
1556 message are used as default committer and commit message. All
1556 message are used as default committer and commit message. All
1557 text/plain body parts before first diff are added to commit
1557 text/plain body parts before first diff are added to commit
1558 message.
1558 message.
1559
1559
1560 If the imported patch was generated by hg export, user and description
1560 If the imported patch was generated by hg export, user and description
1561 from patch override values from message headers and body. Values
1561 from patch override values from message headers and body. Values
1562 given on command line with -m and -u override these.
1562 given on command line with -m and -u override these.
1563
1563
1564 If --exact is specified, import will set the working directory
1564 If --exact is specified, import will set the working directory
1565 to the parent of each patch before applying it, and will abort
1565 to the parent of each patch before applying it, and will abort
1566 if the resulting changeset has a different ID than the one
1566 if the resulting changeset has a different ID than the one
1567 recorded in the patch. This may happen due to character set
1567 recorded in the patch. This may happen due to character set
1568 problems or other deficiencies in the text patch format.
1568 problems or other deficiencies in the text patch format.
1569
1569
1570 To read a patch from standard input, use patch name "-".
1570 To read a patch from standard input, use patch name "-".
1571 See 'hg help dates' for a list of formats valid for -d/--date.
1571 See 'hg help dates' for a list of formats valid for -d/--date.
1572 """
1572 """
1573 patches = (patch1,) + patches
1573 patches = (patch1,) + patches
1574
1574
1575 date = opts.get('date')
1575 date = opts.get('date')
1576 if date:
1576 if date:
1577 opts['date'] = util.parsedate(date)
1577 opts['date'] = util.parsedate(date)
1578
1578
1579 if opts.get('exact') or not opts.get('force'):
1579 if opts.get('exact') or not opts.get('force'):
1580 cmdutil.bail_if_changed(repo)
1580 cmdutil.bail_if_changed(repo)
1581
1581
1582 d = opts["base"]
1582 d = opts["base"]
1583 strip = opts["strip"]
1583 strip = opts["strip"]
1584 wlock = lock = None
1584 wlock = lock = None
1585 try:
1585 try:
1586 wlock = repo.wlock()
1586 wlock = repo.wlock()
1587 lock = repo.lock()
1587 lock = repo.lock()
1588 for p in patches:
1588 for p in patches:
1589 pf = os.path.join(d, p)
1589 pf = os.path.join(d, p)
1590
1590
1591 if pf == '-':
1591 if pf == '-':
1592 ui.status(_("applying patch from stdin\n"))
1592 ui.status(_("applying patch from stdin\n"))
1593 data = patch.extract(ui, sys.stdin)
1593 data = patch.extract(ui, sys.stdin)
1594 else:
1594 else:
1595 ui.status(_("applying %s\n") % p)
1595 ui.status(_("applying %s\n") % p)
1596 if os.path.exists(pf):
1596 if os.path.exists(pf):
1597 data = patch.extract(ui, file(pf, 'rb'))
1597 data = patch.extract(ui, file(pf, 'rb'))
1598 else:
1598 else:
1599 data = patch.extract(ui, urllib.urlopen(pf))
1599 data = patch.extract(ui, urllib.urlopen(pf))
1600 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1600 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1601
1601
1602 if tmpname is None:
1602 if tmpname is None:
1603 raise util.Abort(_('no diffs found'))
1603 raise util.Abort(_('no diffs found'))
1604
1604
1605 try:
1605 try:
1606 cmdline_message = cmdutil.logmessage(opts)
1606 cmdline_message = cmdutil.logmessage(opts)
1607 if cmdline_message:
1607 if cmdline_message:
1608 # pickup the cmdline msg
1608 # pickup the cmdline msg
1609 message = cmdline_message
1609 message = cmdline_message
1610 elif message:
1610 elif message:
1611 # pickup the patch msg
1611 # pickup the patch msg
1612 message = message.strip()
1612 message = message.strip()
1613 else:
1613 else:
1614 # launch the editor
1614 # launch the editor
1615 message = None
1615 message = None
1616 ui.debug(_('message:\n%s\n') % message)
1616 ui.debug(_('message:\n%s\n') % message)
1617
1617
1618 wp = repo.parents()
1618 wp = repo.parents()
1619 if opts.get('exact'):
1619 if opts.get('exact'):
1620 if not nodeid or not p1:
1620 if not nodeid or not p1:
1621 raise util.Abort(_('not a mercurial patch'))
1621 raise util.Abort(_('not a mercurial patch'))
1622 p1 = repo.lookup(p1)
1622 p1 = repo.lookup(p1)
1623 p2 = repo.lookup(p2 or hex(nullid))
1623 p2 = repo.lookup(p2 or hex(nullid))
1624
1624
1625 if p1 != wp[0].node():
1625 if p1 != wp[0].node():
1626 hg.clean(repo, p1)
1626 hg.clean(repo, p1)
1627 repo.dirstate.setparents(p1, p2)
1627 repo.dirstate.setparents(p1, p2)
1628 elif p2:
1628 elif p2:
1629 try:
1629 try:
1630 p1 = repo.lookup(p1)
1630 p1 = repo.lookup(p1)
1631 p2 = repo.lookup(p2)
1631 p2 = repo.lookup(p2)
1632 if p1 == wp[0].node():
1632 if p1 == wp[0].node():
1633 repo.dirstate.setparents(p1, p2)
1633 repo.dirstate.setparents(p1, p2)
1634 except RepoError:
1634 except RepoError:
1635 pass
1635 pass
1636 if opts.get('exact') or opts.get('import_branch'):
1636 if opts.get('exact') or opts.get('import_branch'):
1637 repo.dirstate.setbranch(branch or 'default')
1637 repo.dirstate.setbranch(branch or 'default')
1638
1638
1639 files = {}
1639 files = {}
1640 try:
1640 try:
1641 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1641 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1642 files=files)
1642 files=files)
1643 finally:
1643 finally:
1644 files = patch.updatedir(ui, repo, files)
1644 files = patch.updatedir(ui, repo, files)
1645 if not opts.get('no_commit'):
1645 if not opts.get('no_commit'):
1646 n = repo.commit(files, message, opts.get('user') or user,
1646 n = repo.commit(files, message, opts.get('user') or user,
1647 opts.get('date') or date)
1647 opts.get('date') or date)
1648 if opts.get('exact'):
1648 if opts.get('exact'):
1649 if hex(n) != nodeid:
1649 if hex(n) != nodeid:
1650 repo.rollback()
1650 repo.rollback()
1651 raise util.Abort(_('patch is damaged'
1651 raise util.Abort(_('patch is damaged'
1652 ' or loses information'))
1652 ' or loses information'))
1653 # Force a dirstate write so that the next transaction
1653 # Force a dirstate write so that the next transaction
1654 # backups an up-do-date file.
1654 # backups an up-do-date file.
1655 repo.dirstate.write()
1655 repo.dirstate.write()
1656 finally:
1656 finally:
1657 os.unlink(tmpname)
1657 os.unlink(tmpname)
1658 finally:
1658 finally:
1659 del lock, wlock
1659 del lock, wlock
1660
1660
1661 def incoming(ui, repo, source="default", **opts):
1661 def incoming(ui, repo, source="default", **opts):
1662 """show new changesets found in source
1662 """show new changesets found in source
1663
1663
1664 Show new changesets found in the specified path/URL or the default
1664 Show new changesets found in the specified path/URL or the default
1665 pull location. These are the changesets that would be pulled if a pull
1665 pull location. These are the changesets that would be pulled if a pull
1666 was requested.
1666 was requested.
1667
1667
1668 For remote repository, using --bundle avoids downloading the changesets
1668 For remote repository, using --bundle avoids downloading the changesets
1669 twice if the incoming is followed by a pull.
1669 twice if the incoming is followed by a pull.
1670
1670
1671 See pull for valid source format details.
1671 See pull for valid source format details.
1672 """
1672 """
1673 limit = cmdutil.loglimit(opts)
1673 limit = cmdutil.loglimit(opts)
1674 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1674 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1675 cmdutil.setremoteconfig(ui, opts)
1675 cmdutil.setremoteconfig(ui, opts)
1676
1676
1677 other = hg.repository(ui, source)
1677 other = hg.repository(ui, source)
1678 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1678 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1679 if revs:
1679 if revs:
1680 revs = [other.lookup(rev) for rev in revs]
1680 revs = [other.lookup(rev) for rev in revs]
1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1681 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1682 if not incoming:
1682 if not incoming:
1683 try:
1683 try:
1684 os.unlink(opts["bundle"])
1684 os.unlink(opts["bundle"])
1685 except:
1685 except:
1686 pass
1686 pass
1687 ui.status(_("no changes found\n"))
1687 ui.status(_("no changes found\n"))
1688 return 1
1688 return 1
1689
1689
1690 cleanup = None
1690 cleanup = None
1691 try:
1691 try:
1692 fname = opts["bundle"]
1692 fname = opts["bundle"]
1693 if fname or not other.local():
1693 if fname or not other.local():
1694 # create a bundle (uncompressed if other repo is not local)
1694 # create a bundle (uncompressed if other repo is not local)
1695 if revs is None:
1695 if revs is None:
1696 cg = other.changegroup(incoming, "incoming")
1696 cg = other.changegroup(incoming, "incoming")
1697 else:
1697 else:
1698 cg = other.changegroupsubset(incoming, revs, 'incoming')
1698 cg = other.changegroupsubset(incoming, revs, 'incoming')
1699 bundletype = other.local() and "HG10BZ" or "HG10UN"
1699 bundletype = other.local() and "HG10BZ" or "HG10UN"
1700 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1700 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1701 # keep written bundle?
1701 # keep written bundle?
1702 if opts["bundle"]:
1702 if opts["bundle"]:
1703 cleanup = None
1703 cleanup = None
1704 if not other.local():
1704 if not other.local():
1705 # use the created uncompressed bundlerepo
1705 # use the created uncompressed bundlerepo
1706 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1706 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1707
1707
1708 o = other.changelog.nodesbetween(incoming, revs)[0]
1708 o = other.changelog.nodesbetween(incoming, revs)[0]
1709 if opts.get('newest_first'):
1709 if opts.get('newest_first'):
1710 o.reverse()
1710 o.reverse()
1711 displayer = cmdutil.show_changeset(ui, other, opts)
1711 displayer = cmdutil.show_changeset(ui, other, opts)
1712 count = 0
1712 count = 0
1713 for n in o:
1713 for n in o:
1714 if count >= limit:
1714 if count >= limit:
1715 break
1715 break
1716 parents = [p for p in other.changelog.parents(n) if p != nullid]
1716 parents = [p for p in other.changelog.parents(n) if p != nullid]
1717 if opts.get('no_merges') and len(parents) == 2:
1717 if opts.get('no_merges') and len(parents) == 2:
1718 continue
1718 continue
1719 count += 1
1719 count += 1
1720 displayer.show(changenode=n)
1720 displayer.show(changenode=n)
1721 finally:
1721 finally:
1722 if hasattr(other, 'close'):
1722 if hasattr(other, 'close'):
1723 other.close()
1723 other.close()
1724 if cleanup:
1724 if cleanup:
1725 os.unlink(cleanup)
1725 os.unlink(cleanup)
1726
1726
1727 def init(ui, dest=".", **opts):
1727 def init(ui, dest=".", **opts):
1728 """create a new repository in the given directory
1728 """create a new repository in the given directory
1729
1729
1730 Initialize a new repository in the given directory. If the given
1730 Initialize a new repository in the given directory. If the given
1731 directory does not exist, it is created.
1731 directory does not exist, it is created.
1732
1732
1733 If no directory is given, the current directory is used.
1733 If no directory is given, the current directory is used.
1734
1734
1735 It is possible to specify an ssh:// URL as the destination.
1735 It is possible to specify an ssh:// URL as the destination.
1736 Look at the help text for the pull command for important details
1736 Look at the help text for the pull command for important details
1737 about ssh:// URLs.
1737 about ssh:// URLs.
1738 """
1738 """
1739 cmdutil.setremoteconfig(ui, opts)
1739 cmdutil.setremoteconfig(ui, opts)
1740 hg.repository(ui, dest, create=1)
1740 hg.repository(ui, dest, create=1)
1741
1741
1742 def locate(ui, repo, *pats, **opts):
1742 def locate(ui, repo, *pats, **opts):
1743 """locate files matching specific patterns
1743 """locate files matching specific patterns
1744
1744
1745 Print all files under Mercurial control whose names match the
1745 Print all files under Mercurial control whose names match the
1746 given patterns.
1746 given patterns.
1747
1747
1748 This command searches the entire repository by default. To search
1748 This command searches the entire repository by default. To search
1749 just the current directory and its subdirectories, use
1749 just the current directory and its subdirectories, use
1750 "--include .".
1750 "--include .".
1751
1751
1752 If no patterns are given to match, this command prints all file
1752 If no patterns are given to match, this command prints all file
1753 names.
1753 names.
1754
1754
1755 If you want to feed the output of this command into the "xargs"
1755 If you want to feed the output of this command into the "xargs"
1756 command, use the "-0" option to both this command and "xargs".
1756 command, use the "-0" option to both this command and "xargs".
1757 This will avoid the problem of "xargs" treating single filenames
1757 This will avoid the problem of "xargs" treating single filenames
1758 that contain white space as multiple filenames.
1758 that contain white space as multiple filenames.
1759 """
1759 """
1760 end = opts.get('print0') and '\0' or '\n'
1760 end = opts.get('print0') and '\0' or '\n'
1761 rev = opts.get('rev') or None
1761 rev = opts.get('rev') or None
1762
1762
1763 ret = 1
1763 ret = 1
1764 m = cmdutil.match(repo, pats, opts, default='relglob')
1764 m = cmdutil.match(repo, pats, opts, default='relglob')
1765 m.bad = lambda x,y: False
1765 m.bad = lambda x,y: False
1766 for abs in repo[rev].walk(m):
1766 for abs in repo[rev].walk(m):
1767 if not rev and abs not in repo.dirstate:
1767 if not rev and abs not in repo.dirstate:
1768 continue
1768 continue
1769 if opts.get('fullpath'):
1769 if opts.get('fullpath'):
1770 ui.write(os.path.join(repo.root, abs), end)
1770 ui.write(os.path.join(repo.root, abs), end)
1771 else:
1771 else:
1772 ui.write(((pats and m.rel(abs)) or abs), end)
1772 ui.write(((pats and m.rel(abs)) or abs), end)
1773 ret = 0
1773 ret = 0
1774
1774
1775 return ret
1775 return ret
1776
1776
1777 def log(ui, repo, *pats, **opts):
1777 def log(ui, repo, *pats, **opts):
1778 """show revision history of entire repository or files
1778 """show revision history of entire repository or files
1779
1779
1780 Print the revision history of the specified files or the entire
1780 Print the revision history of the specified files or the entire
1781 project.
1781 project.
1782
1782
1783 File history is shown without following rename or copy history of
1783 File history is shown without following rename or copy history of
1784 files. Use -f/--follow with a file name to follow history across
1784 files. Use -f/--follow with a file name to follow history across
1785 renames and copies. --follow without a file name will only show
1785 renames and copies. --follow without a file name will only show
1786 ancestors or descendants of the starting revision. --follow-first
1786 ancestors or descendants of the starting revision. --follow-first
1787 only follows the first parent of merge revisions.
1787 only follows the first parent of merge revisions.
1788
1788
1789 If no revision range is specified, the default is tip:0 unless
1789 If no revision range is specified, the default is tip:0 unless
1790 --follow is set, in which case the working directory parent is
1790 --follow is set, in which case the working directory parent is
1791 used as the starting revision.
1791 used as the starting revision.
1792
1792
1793 See 'hg help dates' for a list of formats valid for -d/--date.
1793 See 'hg help dates' for a list of formats valid for -d/--date.
1794
1794
1795 By default this command outputs: changeset id and hash, tags,
1795 By default this command outputs: changeset id and hash, tags,
1796 non-trivial parents, user, date and time, and a summary for each
1796 non-trivial parents, user, date and time, and a summary for each
1797 commit. When the -v/--verbose switch is used, the list of changed
1797 commit. When the -v/--verbose switch is used, the list of changed
1798 files and full commit message is shown.
1798 files and full commit message is shown.
1799
1799
1800 NOTE: log -p may generate unexpected diff output for merge
1800 NOTE: log -p may generate unexpected diff output for merge
1801 changesets, as it will compare the merge changeset against its
1801 changesets, as it will compare the merge changeset against its
1802 first parent only. Also, the files: list will only reflect files
1802 first parent only. Also, the files: list will only reflect files
1803 that are different from BOTH parents.
1803 that are different from BOTH parents.
1804
1804
1805 """
1805 """
1806
1806
1807 get = util.cachefunc(lambda r: repo[r].changeset())
1807 get = util.cachefunc(lambda r: repo[r].changeset())
1808 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1808 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1809
1809
1810 limit = cmdutil.loglimit(opts)
1810 limit = cmdutil.loglimit(opts)
1811 count = 0
1811 count = 0
1812
1812
1813 if opts.get('copies') and opts.get('rev'):
1813 if opts.get('copies') and opts.get('rev'):
1814 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1814 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1815 else:
1815 else:
1816 endrev = len(repo)
1816 endrev = len(repo)
1817 rcache = {}
1817 rcache = {}
1818 ncache = {}
1818 ncache = {}
1819 def getrenamed(fn, rev):
1819 def getrenamed(fn, rev):
1820 '''looks up all renames for a file (up to endrev) the first
1820 '''looks up all renames for a file (up to endrev) the first
1821 time the file is given. It indexes on the changerev and only
1821 time the file is given. It indexes on the changerev and only
1822 parses the manifest if linkrev != changerev.
1822 parses the manifest if linkrev != changerev.
1823 Returns rename info for fn at changerev rev.'''
1823 Returns rename info for fn at changerev rev.'''
1824 if fn not in rcache:
1824 if fn not in rcache:
1825 rcache[fn] = {}
1825 rcache[fn] = {}
1826 ncache[fn] = {}
1826 ncache[fn] = {}
1827 fl = repo.file(fn)
1827 fl = repo.file(fn)
1828 for i in fl:
1828 for i in fl:
1829 node = fl.node(i)
1829 node = fl.node(i)
1830 lr = fl.linkrev(node)
1830 lr = fl.linkrev(node)
1831 renamed = fl.renamed(node)
1831 renamed = fl.renamed(node)
1832 rcache[fn][lr] = renamed
1832 rcache[fn][lr] = renamed
1833 if renamed:
1833 if renamed:
1834 ncache[fn][node] = renamed
1834 ncache[fn][node] = renamed
1835 if lr >= endrev:
1835 if lr >= endrev:
1836 break
1836 break
1837 if rev in rcache[fn]:
1837 if rev in rcache[fn]:
1838 return rcache[fn][rev]
1838 return rcache[fn][rev]
1839
1839
1840 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1840 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1841 # filectx logic.
1841 # filectx logic.
1842
1842
1843 try:
1843 try:
1844 return repo[rev][fn].renamed()
1844 return repo[rev][fn].renamed()
1845 except revlog.LookupError:
1845 except revlog.LookupError:
1846 pass
1846 pass
1847 return None
1847 return None
1848
1848
1849 df = False
1849 df = False
1850 if opts["date"]:
1850 if opts["date"]:
1851 df = util.matchdate(opts["date"])
1851 df = util.matchdate(opts["date"])
1852
1852
1853 only_branches = opts.get('only_branch')
1853 only_branches = opts.get('only_branch')
1854
1854
1855 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1855 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1856 for st, rev, fns in changeiter:
1856 for st, rev, fns in changeiter:
1857 if st == 'add':
1857 if st == 'add':
1858 changenode = repo.changelog.node(rev)
1858 changenode = repo.changelog.node(rev)
1859 parents = [p for p in repo.changelog.parentrevs(rev)
1859 parents = [p for p in repo.changelog.parentrevs(rev)
1860 if p != nullrev]
1860 if p != nullrev]
1861 if opts.get('no_merges') and len(parents) == 2:
1861 if opts.get('no_merges') and len(parents) == 2:
1862 continue
1862 continue
1863 if opts.get('only_merges') and len(parents) != 2:
1863 if opts.get('only_merges') and len(parents) != 2:
1864 continue
1864 continue
1865
1865
1866 if only_branches:
1866 if only_branches:
1867 revbranch = get(rev)[5]['branch']
1867 revbranch = get(rev)[5]['branch']
1868 if revbranch not in only_branches:
1868 if revbranch not in only_branches:
1869 continue
1869 continue
1870
1870
1871 if df:
1871 if df:
1872 changes = get(rev)
1872 changes = get(rev)
1873 if not df(changes[2][0]):
1873 if not df(changes[2][0]):
1874 continue
1874 continue
1875
1875
1876 if opts.get('keyword'):
1876 if opts.get('keyword'):
1877 changes = get(rev)
1877 changes = get(rev)
1878 miss = 0
1878 miss = 0
1879 for k in [kw.lower() for kw in opts['keyword']]:
1879 for k in [kw.lower() for kw in opts['keyword']]:
1880 if not (k in changes[1].lower() or
1880 if not (k in changes[1].lower() or
1881 k in changes[4].lower() or
1881 k in changes[4].lower() or
1882 k in " ".join(changes[3]).lower()):
1882 k in " ".join(changes[3]).lower()):
1883 miss = 1
1883 miss = 1
1884 break
1884 break
1885 if miss:
1885 if miss:
1886 continue
1886 continue
1887
1887
1888 if opts['user']:
1888 if opts['user']:
1889 changes = get(rev)
1889 changes = get(rev)
1890 miss = 0
1890 miss = 0
1891 for k in opts['user']:
1891 for k in opts['user']:
1892 if k != changes[1]:
1892 if k != changes[1]:
1893 miss = 1
1893 miss = 1
1894 break
1894 break
1895 if miss:
1895 if miss:
1896 continue
1896 continue
1897
1897
1898 copies = []
1898 copies = []
1899 if opts.get('copies') and rev:
1899 if opts.get('copies') and rev:
1900 for fn in get(rev)[3]:
1900 for fn in get(rev)[3]:
1901 rename = getrenamed(fn, rev)
1901 rename = getrenamed(fn, rev)
1902 if rename:
1902 if rename:
1903 copies.append((fn, rename[0]))
1903 copies.append((fn, rename[0]))
1904 displayer.show(rev, changenode, copies=copies)
1904 displayer.show(rev, changenode, copies=copies)
1905 elif st == 'iter':
1905 elif st == 'iter':
1906 if count == limit: break
1906 if count == limit: break
1907 if displayer.flush(rev):
1907 if displayer.flush(rev):
1908 count += 1
1908 count += 1
1909
1909
1910 def manifest(ui, repo, node=None, rev=None):
1910 def manifest(ui, repo, node=None, rev=None):
1911 """output the current or given revision of the project manifest
1911 """output the current or given revision of the project manifest
1912
1912
1913 Print a list of version controlled files for the given revision.
1913 Print a list of version controlled files for the given revision.
1914 If no revision is given, the parent of the working directory is used,
1914 If no revision is given, the parent of the working directory is used,
1915 or tip if no revision is checked out.
1915 or tip if no revision is checked out.
1916
1916
1917 The manifest is the list of files being version controlled. If no revision
1917 The manifest is the list of files being version controlled. If no revision
1918 is given then the first parent of the working directory is used.
1918 is given then the first parent of the working directory is used.
1919
1919
1920 With -v flag, print file permissions, symlink and executable bits. With
1920 With -v flag, print file permissions, symlink and executable bits. With
1921 --debug flag, print file revision hashes.
1921 --debug flag, print file revision hashes.
1922 """
1922 """
1923
1923
1924 if rev and node:
1924 if rev and node:
1925 raise util.Abort(_("please specify just one revision"))
1925 raise util.Abort(_("please specify just one revision"))
1926
1926
1927 if not node:
1927 if not node:
1928 node = rev
1928 node = rev
1929
1929
1930 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1930 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1931 ctx = repo[node]
1931 ctx = repo[node]
1932 for f in ctx:
1932 for f in ctx:
1933 if ui.debugflag:
1933 if ui.debugflag:
1934 ui.write("%40s " % hex(ctx.manifest()[f]))
1934 ui.write("%40s " % hex(ctx.manifest()[f]))
1935 if ui.verbose:
1935 if ui.verbose:
1936 ui.write(decor[ctx.flags(f)])
1936 ui.write(decor[ctx.flags(f)])
1937 ui.write("%s\n" % f)
1937 ui.write("%s\n" % f)
1938
1938
1939 def merge(ui, repo, node=None, force=None, rev=None):
1939 def merge(ui, repo, node=None, force=None, rev=None):
1940 """merge working directory with another revision
1940 """merge working directory with another revision
1941
1941
1942 Merge the contents of the current working directory and the
1942 Merge the contents of the current working directory and the
1943 requested revision. Files that changed between either parent are
1943 requested revision. Files that changed between either parent are
1944 marked as changed for the next commit and a commit must be
1944 marked as changed for the next commit and a commit must be
1945 performed before any further updates are allowed.
1945 performed before any further updates are allowed.
1946
1946
1947 If no revision is specified, the working directory's parent is a
1947 If no revision is specified, the working directory's parent is a
1948 head revision, and the current branch contains exactly one other head,
1948 head revision, and the current branch contains exactly one other head,
1949 the other head is merged with by default. Otherwise, an explicit
1949 the other head is merged with by default. Otherwise, an explicit
1950 revision to merge with must be provided.
1950 revision to merge with must be provided.
1951 """
1951 """
1952
1952
1953 if rev and node:
1953 if rev and node:
1954 raise util.Abort(_("please specify just one revision"))
1954 raise util.Abort(_("please specify just one revision"))
1955 if not node:
1955 if not node:
1956 node = rev
1956 node = rev
1957
1957
1958 if not node:
1958 if not node:
1959 branch = repo.changectx(None).branch()
1959 branch = repo.changectx(None).branch()
1960 bheads = repo.branchheads(branch)
1960 bheads = repo.branchheads(branch)
1961 if len(bheads) > 2:
1961 if len(bheads) > 2:
1962 raise util.Abort(_("branch '%s' has %d heads - "
1962 raise util.Abort(_("branch '%s' has %d heads - "
1963 "please merge with an explicit rev") %
1963 "please merge with an explicit rev") %
1964 (branch, len(bheads)))
1964 (branch, len(bheads)))
1965
1965
1966 parent = repo.dirstate.parents()[0]
1966 parent = repo.dirstate.parents()[0]
1967 if len(bheads) == 1:
1967 if len(bheads) == 1:
1968 if len(repo.heads()) > 1:
1968 if len(repo.heads()) > 1:
1969 raise util.Abort(_("branch '%s' has one head - "
1969 raise util.Abort(_("branch '%s' has one head - "
1970 "please merge with an explicit rev") %
1970 "please merge with an explicit rev") %
1971 branch)
1971 branch)
1972 msg = _('there is nothing to merge')
1972 msg = _('there is nothing to merge')
1973 if parent != repo.lookup(repo[None].branch()):
1973 if parent != repo.lookup(repo[None].branch()):
1974 msg = _('%s - use "hg update" instead') % msg
1974 msg = _('%s - use "hg update" instead') % msg
1975 raise util.Abort(msg)
1975 raise util.Abort(msg)
1976
1976
1977 if parent not in bheads:
1977 if parent not in bheads:
1978 raise util.Abort(_('working dir not at a head rev - '
1978 raise util.Abort(_('working dir not at a head rev - '
1979 'use "hg update" or merge with an explicit rev'))
1979 'use "hg update" or merge with an explicit rev'))
1980 node = parent == bheads[0] and bheads[-1] or bheads[0]
1980 node = parent == bheads[0] and bheads[-1] or bheads[0]
1981 return hg.merge(repo, node, force=force)
1981 return hg.merge(repo, node, force=force)
1982
1982
1983 def outgoing(ui, repo, dest=None, **opts):
1983 def outgoing(ui, repo, dest=None, **opts):
1984 """show changesets not found in destination
1984 """show changesets not found in destination
1985
1985
1986 Show changesets not found in the specified destination repository or
1986 Show changesets not found in the specified destination repository or
1987 the default push location. These are the changesets that would be pushed
1987 the default push location. These are the changesets that would be pushed
1988 if a push was requested.
1988 if a push was requested.
1989
1989
1990 See pull for valid destination format details.
1990 See pull for valid destination format details.
1991 """
1991 """
1992 limit = cmdutil.loglimit(opts)
1992 limit = cmdutil.loglimit(opts)
1993 dest, revs, checkout = hg.parseurl(
1993 dest, revs, checkout = hg.parseurl(
1994 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
1994 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
1995 cmdutil.setremoteconfig(ui, opts)
1995 cmdutil.setremoteconfig(ui, opts)
1996 if revs:
1996 if revs:
1997 revs = [repo.lookup(rev) for rev in revs]
1997 revs = [repo.lookup(rev) for rev in revs]
1998
1998
1999 other = hg.repository(ui, dest)
1999 other = hg.repository(ui, dest)
2000 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2000 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2001 o = repo.findoutgoing(other, force=opts.get('force'))
2001 o = repo.findoutgoing(other, force=opts.get('force'))
2002 if not o:
2002 if not o:
2003 ui.status(_("no changes found\n"))
2003 ui.status(_("no changes found\n"))
2004 return 1
2004 return 1
2005 o = repo.changelog.nodesbetween(o, revs)[0]
2005 o = repo.changelog.nodesbetween(o, revs)[0]
2006 if opts.get('newest_first'):
2006 if opts.get('newest_first'):
2007 o.reverse()
2007 o.reverse()
2008 displayer = cmdutil.show_changeset(ui, repo, opts)
2008 displayer = cmdutil.show_changeset(ui, repo, opts)
2009 count = 0
2009 count = 0
2010 for n in o:
2010 for n in o:
2011 if count >= limit:
2011 if count >= limit:
2012 break
2012 break
2013 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2013 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2014 if opts.get('no_merges') and len(parents) == 2:
2014 if opts.get('no_merges') and len(parents) == 2:
2015 continue
2015 continue
2016 count += 1
2016 count += 1
2017 displayer.show(changenode=n)
2017 displayer.show(changenode=n)
2018
2018
2019 def parents(ui, repo, file_=None, **opts):
2019 def parents(ui, repo, file_=None, **opts):
2020 """show the parents of the working dir or revision
2020 """show the parents of the working dir or revision
2021
2021
2022 Print the working directory's parent revisions. If a
2022 Print the working directory's parent revisions. If a
2023 revision is given via --rev, the parent of that revision
2023 revision is given via --rev, the parent of that revision
2024 will be printed. If a file argument is given, revision in
2024 will be printed. If a file argument is given, revision in
2025 which the file was last changed (before the working directory
2025 which the file was last changed (before the working directory
2026 revision or the argument to --rev if given) is printed.
2026 revision or the argument to --rev if given) is printed.
2027 """
2027 """
2028 rev = opts.get('rev')
2028 rev = opts.get('rev')
2029 if rev:
2029 if rev:
2030 ctx = repo[rev]
2030 ctx = repo[rev]
2031 else:
2031 else:
2032 ctx = repo[None]
2032 ctx = repo[None]
2033
2033
2034 if file_:
2034 if file_:
2035 m = cmdutil.match(repo, (file_,), opts)
2035 m = cmdutil.match(repo, (file_,), opts)
2036 if m.anypats() or len(m.files()) != 1:
2036 if m.anypats() or len(m.files()) != 1:
2037 raise util.Abort(_('can only specify an explicit file name'))
2037 raise util.Abort(_('can only specify an explicit file name'))
2038 file_ = m.files()[0]
2038 file_ = m.files()[0]
2039 filenodes = []
2039 filenodes = []
2040 for cp in ctx.parents():
2040 for cp in ctx.parents():
2041 if not cp:
2041 if not cp:
2042 continue
2042 continue
2043 try:
2043 try:
2044 filenodes.append(cp.filenode(file_))
2044 filenodes.append(cp.filenode(file_))
2045 except revlog.LookupError:
2045 except revlog.LookupError:
2046 pass
2046 pass
2047 if not filenodes:
2047 if not filenodes:
2048 raise util.Abort(_("'%s' not found in manifest!") % file_)
2048 raise util.Abort(_("'%s' not found in manifest!") % file_)
2049 fl = repo.file(file_)
2049 fl = repo.file(file_)
2050 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
2050 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
2051 else:
2051 else:
2052 p = [cp.node() for cp in ctx.parents()]
2052 p = [cp.node() for cp in ctx.parents()]
2053
2053
2054 displayer = cmdutil.show_changeset(ui, repo, opts)
2054 displayer = cmdutil.show_changeset(ui, repo, opts)
2055 for n in p:
2055 for n in p:
2056 if n != nullid:
2056 if n != nullid:
2057 displayer.show(changenode=n)
2057 displayer.show(changenode=n)
2058
2058
2059 def paths(ui, repo, search=None):
2059 def paths(ui, repo, search=None):
2060 """show definition of symbolic path names
2060 """show definition of symbolic path names
2061
2061
2062 Show definition of symbolic path name NAME. If no name is given, show
2062 Show definition of symbolic path name NAME. If no name is given, show
2063 definition of available names.
2063 definition of available names.
2064
2064
2065 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2065 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2066 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2066 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2067 """
2067 """
2068 if search:
2068 if search:
2069 for name, path in ui.configitems("paths"):
2069 for name, path in ui.configitems("paths"):
2070 if name == search:
2070 if name == search:
2071 ui.write("%s\n" % util.hidepassword(path))
2071 ui.write("%s\n" % util.hidepassword(path))
2072 return
2072 return
2073 ui.warn(_("not found!\n"))
2073 ui.warn(_("not found!\n"))
2074 return 1
2074 return 1
2075 else:
2075 else:
2076 for name, path in ui.configitems("paths"):
2076 for name, path in ui.configitems("paths"):
2077 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2077 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2078
2078
2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2079 def postincoming(ui, repo, modheads, optupdate, checkout):
2080 if modheads == 0:
2080 if modheads == 0:
2081 return
2081 return
2082 if optupdate:
2082 if optupdate:
2083 if modheads <= 1 or checkout:
2083 if modheads <= 1 or checkout:
2084 return hg.update(repo, checkout)
2084 return hg.update(repo, checkout)
2085 else:
2085 else:
2086 ui.status(_("not updating, since new heads added\n"))
2086 ui.status(_("not updating, since new heads added\n"))
2087 if modheads > 1:
2087 if modheads > 1:
2088 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2088 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2089 else:
2089 else:
2090 ui.status(_("(run 'hg update' to get a working copy)\n"))
2090 ui.status(_("(run 'hg update' to get a working copy)\n"))
2091
2091
2092 def pull(ui, repo, source="default", **opts):
2092 def pull(ui, repo, source="default", **opts):
2093 """pull changes from the specified source
2093 """pull changes from the specified source
2094
2094
2095 Pull changes from a remote repository to a local one.
2095 Pull changes from a remote repository to a local one.
2096
2096
2097 This finds all changes from the repository at the specified path
2097 This finds all changes from the repository at the specified path
2098 or URL and adds them to the local repository. By default, this
2098 or URL and adds them to the local repository. By default, this
2099 does not update the copy of the project in the working directory.
2099 does not update the copy of the project in the working directory.
2100
2100
2101 Valid URLs are of the form:
2101 Valid URLs are of the form:
2102
2102
2103 local/filesystem/path (or file://local/filesystem/path)
2103 local/filesystem/path (or file://local/filesystem/path)
2104 http://[user[:pass]@]host[:port]/[path]
2104 http://[user[:pass]@]host[:port]/[path]
2105 https://[user[:pass]@]host[:port]/[path]
2105 https://[user[:pass]@]host[:port]/[path]
2106 ssh://[user[:pass]@]host[:port]/[path]
2106 ssh://[user[:pass]@]host[:port]/[path]
2107
2107
2108 Paths in the local filesystem can either point to Mercurial
2108 Paths in the local filesystem can either point to Mercurial
2109 repositories or to bundle files (as created by 'hg bundle' or
2109 repositories or to bundle files (as created by 'hg bundle' or
2110 'hg incoming --bundle').
2110 'hg incoming --bundle').
2111
2111
2112 An optional identifier after # indicates a particular branch, tag,
2112 An optional identifier after # indicates a particular branch, tag,
2113 or changeset to pull.
2113 or changeset to pull.
2114
2114
2115 Some notes about using SSH with Mercurial:
2115 Some notes about using SSH with Mercurial:
2116 - SSH requires an accessible shell account on the destination machine
2116 - SSH requires an accessible shell account on the destination machine
2117 and a copy of hg in the remote path or specified with as remotecmd.
2117 and a copy of hg in the remote path or specified with as remotecmd.
2118 - path is relative to the remote user's home directory by default.
2118 - path is relative to the remote user's home directory by default.
2119 Use an extra slash at the start of a path to specify an absolute path:
2119 Use an extra slash at the start of a path to specify an absolute path:
2120 ssh://example.com//tmp/repository
2120 ssh://example.com//tmp/repository
2121 - Mercurial doesn't use its own compression via SSH; the right thing
2121 - Mercurial doesn't use its own compression via SSH; the right thing
2122 to do is to configure it in your ~/.ssh/config, e.g.:
2122 to do is to configure it in your ~/.ssh/config, e.g.:
2123 Host *.mylocalnetwork.example.com
2123 Host *.mylocalnetwork.example.com
2124 Compression no
2124 Compression no
2125 Host *
2125 Host *
2126 Compression yes
2126 Compression yes
2127 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2127 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2128 with the --ssh command line option.
2128 with the --ssh command line option.
2129 """
2129 """
2130 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2130 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2131 cmdutil.setremoteconfig(ui, opts)
2131 cmdutil.setremoteconfig(ui, opts)
2132
2132
2133 other = hg.repository(ui, source)
2133 other = hg.repository(ui, source)
2134 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2134 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2135 if revs:
2135 if revs:
2136 try:
2136 try:
2137 revs = [other.lookup(rev) for rev in revs]
2137 revs = [other.lookup(rev) for rev in revs]
2138 except NoCapability:
2138 except NoCapability:
2139 error = _("Other repository doesn't support revision lookup, "
2139 error = _("Other repository doesn't support revision lookup, "
2140 "so a rev cannot be specified.")
2140 "so a rev cannot be specified.")
2141 raise util.Abort(error)
2141 raise util.Abort(error)
2142
2142
2143 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2143 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2144 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2144 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2145
2145
2146 def push(ui, repo, dest=None, **opts):
2146 def push(ui, repo, dest=None, **opts):
2147 """push changes to the specified destination
2147 """push changes to the specified destination
2148
2148
2149 Push changes from the local repository to the given destination.
2149 Push changes from the local repository to the given destination.
2150
2150
2151 This is the symmetrical operation for pull. It helps to move
2151 This is the symmetrical operation for pull. It helps to move
2152 changes from the current repository to a different one. If the
2152 changes from the current repository to a different one. If the
2153 destination is local this is identical to a pull in that directory
2153 destination is local this is identical to a pull in that directory
2154 from the current one.
2154 from the current one.
2155
2155
2156 By default, push will refuse to run if it detects the result would
2156 By default, push will refuse to run if it detects the result would
2157 increase the number of remote heads. This generally indicates the
2157 increase the number of remote heads. This generally indicates the
2158 the client has forgotten to pull and merge before pushing.
2158 the client has forgotten to pull and merge before pushing.
2159
2159
2160 Valid URLs are of the form:
2160 Valid URLs are of the form:
2161
2161
2162 local/filesystem/path (or file://local/filesystem/path)
2162 local/filesystem/path (or file://local/filesystem/path)
2163 ssh://[user[:pass]@]host[:port]/[path]
2163 ssh://[user[:pass]@]host[:port]/[path]
2164 http://[user[:pass]@]host[:port]/[path]
2164 http://[user[:pass]@]host[:port]/[path]
2165 https://[user[:pass]@]host[:port]/[path]
2165 https://[user[:pass]@]host[:port]/[path]
2166
2166
2167 An optional identifier after # indicates a particular branch, tag,
2167 An optional identifier after # indicates a particular branch, tag,
2168 or changeset to push. If -r is used, the named changeset and all its
2168 or changeset to push. If -r is used, the named changeset and all its
2169 ancestors will be pushed to the remote repository.
2169 ancestors will be pushed to the remote repository.
2170
2170
2171 Look at the help text for the pull command for important details
2171 Look at the help text for the pull command for important details
2172 about ssh:// URLs.
2172 about ssh:// URLs.
2173
2173
2174 Pushing to http:// and https:// URLs is only possible, if this
2174 Pushing to http:// and https:// URLs is only possible, if this
2175 feature is explicitly enabled on the remote Mercurial server.
2175 feature is explicitly enabled on the remote Mercurial server.
2176 """
2176 """
2177 dest, revs, checkout = hg.parseurl(
2177 dest, revs, checkout = hg.parseurl(
2178 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2178 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2179 cmdutil.setremoteconfig(ui, opts)
2179 cmdutil.setremoteconfig(ui, opts)
2180
2180
2181 other = hg.repository(ui, dest)
2181 other = hg.repository(ui, dest)
2182 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
2182 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
2183 if revs:
2183 if revs:
2184 revs = [repo.lookup(rev) for rev in revs]
2184 revs = [repo.lookup(rev) for rev in revs]
2185 r = repo.push(other, opts.get('force'), revs=revs)
2185 r = repo.push(other, opts.get('force'), revs=revs)
2186 return r == 0
2186 return r == 0
2187
2187
2188 def rawcommit(ui, repo, *pats, **opts):
2188 def rawcommit(ui, repo, *pats, **opts):
2189 """raw commit interface (DEPRECATED)
2189 """raw commit interface (DEPRECATED)
2190
2190
2191 (DEPRECATED)
2191 (DEPRECATED)
2192 Lowlevel commit, for use in helper scripts.
2192 Lowlevel commit, for use in helper scripts.
2193
2193
2194 This command is not intended to be used by normal users, as it is
2194 This command is not intended to be used by normal users, as it is
2195 primarily useful for importing from other SCMs.
2195 primarily useful for importing from other SCMs.
2196
2196
2197 This command is now deprecated and will be removed in a future
2197 This command is now deprecated and will be removed in a future
2198 release, please use debugsetparents and commit instead.
2198 release, please use debugsetparents and commit instead.
2199 """
2199 """
2200
2200
2201 ui.warn(_("(the rawcommit command is deprecated)\n"))
2201 ui.warn(_("(the rawcommit command is deprecated)\n"))
2202
2202
2203 message = cmdutil.logmessage(opts)
2203 message = cmdutil.logmessage(opts)
2204
2204
2205 files = cmdutil.match(repo, pats, opts).files()
2205 files = cmdutil.match(repo, pats, opts).files()
2206 if opts.get('files'):
2206 if opts.get('files'):
2207 files += open(opts['files']).read().splitlines()
2207 files += open(opts['files']).read().splitlines()
2208
2208
2209 parents = [repo.lookup(p) for p in opts['parent']]
2209 parents = [repo.lookup(p) for p in opts['parent']]
2210
2210
2211 try:
2211 try:
2212 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2212 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2213 except ValueError, inst:
2213 except ValueError, inst:
2214 raise util.Abort(str(inst))
2214 raise util.Abort(str(inst))
2215
2215
2216 def recover(ui, repo):
2216 def recover(ui, repo):
2217 """roll back an interrupted transaction
2217 """roll back an interrupted transaction
2218
2218
2219 Recover from an interrupted commit or pull.
2219 Recover from an interrupted commit or pull.
2220
2220
2221 This command tries to fix the repository status after an interrupted
2221 This command tries to fix the repository status after an interrupted
2222 operation. It should only be necessary when Mercurial suggests it.
2222 operation. It should only be necessary when Mercurial suggests it.
2223 """
2223 """
2224 if repo.recover():
2224 if repo.recover():
2225 return hg.verify(repo)
2225 return hg.verify(repo)
2226 return 1
2226 return 1
2227
2227
2228 def remove(ui, repo, *pats, **opts):
2228 def remove(ui, repo, *pats, **opts):
2229 """remove the specified files on the next commit
2229 """remove the specified files on the next commit
2230
2230
2231 Schedule the indicated files for removal from the repository.
2231 Schedule the indicated files for removal from the repository.
2232
2232
2233 This only removes files from the current branch, not from the entire
2233 This only removes files from the current branch, not from the entire
2234 project history. -A can be used to remove only files that have already
2234 project history. -A can be used to remove only files that have already
2235 been deleted, -f can be used to force deletion, and -Af can be used
2235 been deleted, -f can be used to force deletion, and -Af can be used
2236 to remove files from the next revision without deleting them.
2236 to remove files from the next revision without deleting them.
2237
2237
2238 The following table details the behavior of remove for different file
2238 The following table details the behavior of remove for different file
2239 states (columns) and option combinations (rows). The file states are
2239 states (columns) and option combinations (rows). The file states are
2240 Added, Clean, Modified and Missing (as reported by hg status). The
2240 Added, Clean, Modified and Missing (as reported by hg status). The
2241 actions are Warn, Remove (from branch) and Delete (from disk).
2241 actions are Warn, Remove (from branch) and Delete (from disk).
2242
2242
2243 A C M !
2243 A C M !
2244 none W RD W R
2244 none W RD W R
2245 -f R RD RD R
2245 -f R RD RD R
2246 -A W W W R
2246 -A W W W R
2247 -Af R R R R
2247 -Af R R R R
2248
2248
2249 This command schedules the files to be removed at the next commit.
2249 This command schedules the files to be removed at the next commit.
2250 To undo a remove before that, see hg revert.
2250 To undo a remove before that, see hg revert.
2251 """
2251 """
2252
2252
2253 after, force = opts.get('after'), opts.get('force')
2253 after, force = opts.get('after'), opts.get('force')
2254 if not pats and not after:
2254 if not pats and not after:
2255 raise util.Abort(_('no files specified'))
2255 raise util.Abort(_('no files specified'))
2256
2256
2257 m = cmdutil.match(repo, pats, opts)
2257 m = cmdutil.match(repo, pats, opts)
2258 s = repo.status(match=m, clean=True)
2258 s = repo.status(match=m, clean=True)
2259 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2259 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2260
2260
2261 def warn(files, reason):
2261 def warn(files, reason):
2262 for f in files:
2262 for f in files:
2263 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2263 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2264 % (m.rel(f), reason))
2264 % (m.rel(f), reason))
2265
2265
2266 if force:
2266 if force:
2267 remove, forget = modified + deleted + clean, added
2267 remove, forget = modified + deleted + clean, added
2268 elif after:
2268 elif after:
2269 remove, forget = deleted, []
2269 remove, forget = deleted, []
2270 warn(modified + added + clean, _('still exists'))
2270 warn(modified + added + clean, _('still exists'))
2271 else:
2271 else:
2272 remove, forget = deleted + clean, []
2272 remove, forget = deleted + clean, []
2273 warn(modified, _('is modified'))
2273 warn(modified, _('is modified'))
2274 warn(added, _('has been marked for add'))
2274 warn(added, _('has been marked for add'))
2275
2275
2276 for f in util.sort(remove + forget):
2276 for f in util.sort(remove + forget):
2277 if ui.verbose or not m.exact(f):
2277 if ui.verbose or not m.exact(f):
2278 ui.status(_('removing %s\n') % m.rel(f))
2278 ui.status(_('removing %s\n') % m.rel(f))
2279
2279
2280 repo.forget(forget)
2280 repo.forget(forget)
2281 repo.remove(remove, unlink=not after)
2281 repo.remove(remove, unlink=not after)
2282
2282
2283 def rename(ui, repo, *pats, **opts):
2283 def rename(ui, repo, *pats, **opts):
2284 """rename files; equivalent of copy + remove
2284 """rename files; equivalent of copy + remove
2285
2285
2286 Mark dest as copies of sources; mark sources for deletion. If
2286 Mark dest as copies of sources; mark sources for deletion. If
2287 dest is a directory, copies are put in that directory. If dest is
2287 dest is a directory, copies are put in that directory. If dest is
2288 a file, there can only be one source.
2288 a file, there can only be one source.
2289
2289
2290 By default, this command copies the contents of files as they
2290 By default, this command copies the contents of files as they
2291 stand in the working directory. If invoked with --after, the
2291 stand in the working directory. If invoked with --after, the
2292 operation is recorded, but no copying is performed.
2292 operation is recorded, but no copying is performed.
2293
2293
2294 This command takes effect in the next commit. To undo a rename
2294 This command takes effect in the next commit. To undo a rename
2295 before that, see hg revert.
2295 before that, see hg revert.
2296 """
2296 """
2297 wlock = repo.wlock(False)
2297 wlock = repo.wlock(False)
2298 try:
2298 try:
2299 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2299 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2300 finally:
2300 finally:
2301 del wlock
2301 del wlock
2302
2302
2303 def resolve(ui, repo, *pats, **opts):
2303 def resolve(ui, repo, *pats, **opts):
2304 """resolve file merges from a branch merge or update
2304 """resolve file merges from a branch merge or update
2305
2305
2306 This command will attempt to resolve unresolved merges from the
2306 This command will attempt to resolve unresolved merges from the
2307 last update or merge command. This will use the local file
2307 last update or merge command. This will use the local file
2308 revision preserved at the last update or merge to cleanly retry
2308 revision preserved at the last update or merge to cleanly retry
2309 the file merge attempt. With no file or options specified, this
2309 the file merge attempt. With no file or options specified, this
2310 command will attempt to resolve all unresolved files.
2310 command will attempt to resolve all unresolved files.
2311
2311
2312 The codes used to show the status of files are:
2312 The codes used to show the status of files are:
2313 U = unresolved
2313 U = unresolved
2314 R = resolved
2314 R = resolved
2315 """
2315 """
2316
2316
2317 if len([x for x in opts if opts[x]]) > 1:
2317 if len([x for x in opts if opts[x]]) > 1:
2318 raise util.Abort(_("too many options specified"))
2318 raise util.Abort(_("too many options specified"))
2319
2319
2320 ms = merge_.mergestate(repo)
2320 ms = merge_.mergestate(repo)
2321 m = cmdutil.match(repo, pats, opts)
2321 m = cmdutil.match(repo, pats, opts)
2322
2322
2323 for f in ms:
2323 for f in ms:
2324 if m(f):
2324 if m(f):
2325 if opts.get("list"):
2325 if opts.get("list"):
2326 ui.write("%s %s\n" % (ms[f].upper(), f))
2326 ui.write("%s %s\n" % (ms[f].upper(), f))
2327 elif opts.get("mark"):
2327 elif opts.get("mark"):
2328 ms.mark(f, "r")
2328 ms.mark(f, "r")
2329 elif opts.get("unmark"):
2329 elif opts.get("unmark"):
2330 ms.mark(f, "u")
2330 ms.mark(f, "u")
2331 else:
2331 else:
2332 wctx = repo[None]
2332 wctx = repo[None]
2333 mctx = wctx.parents()[-1]
2333 mctx = wctx.parents()[-1]
2334 ms.resolve(f, wctx, mctx)
2334 ms.resolve(f, wctx, mctx)
2335
2335
2336 def revert(ui, repo, *pats, **opts):
2336 def revert(ui, repo, *pats, **opts):
2337 """restore individual files or dirs to an earlier state
2337 """restore individual files or dirs to an earlier state
2338
2338
2339 (use update -r to check out earlier revisions, revert does not
2339 (use update -r to check out earlier revisions, revert does not
2340 change the working dir parents)
2340 change the working dir parents)
2341
2341
2342 With no revision specified, revert the named files or directories
2342 With no revision specified, revert the named files or directories
2343 to the contents they had in the parent of the working directory.
2343 to the contents they had in the parent of the working directory.
2344 This restores the contents of the affected files to an unmodified
2344 This restores the contents of the affected files to an unmodified
2345 state and unschedules adds, removes, copies, and renames. If the
2345 state and unschedules adds, removes, copies, and renames. If the
2346 working directory has two parents, you must explicitly specify the
2346 working directory has two parents, you must explicitly specify the
2347 revision to revert to.
2347 revision to revert to.
2348
2348
2349 Using the -r option, revert the given files or directories to their
2349 Using the -r option, revert the given files or directories to their
2350 contents as of a specific revision. This can be helpful to "roll
2350 contents as of a specific revision. This can be helpful to "roll
2351 back" some or all of an earlier change.
2351 back" some or all of an earlier change.
2352 See 'hg help dates' for a list of formats valid for -d/--date.
2352 See 'hg help dates' for a list of formats valid for -d/--date.
2353
2353
2354 Revert modifies the working directory. It does not commit any
2354 Revert modifies the working directory. It does not commit any
2355 changes, or change the parent of the working directory. If you
2355 changes, or change the parent of the working directory. If you
2356 revert to a revision other than the parent of the working
2356 revert to a revision other than the parent of the working
2357 directory, the reverted files will thus appear modified
2357 directory, the reverted files will thus appear modified
2358 afterwards.
2358 afterwards.
2359
2359
2360 If a file has been deleted, it is restored. If the executable
2360 If a file has been deleted, it is restored. If the executable
2361 mode of a file was changed, it is reset.
2361 mode of a file was changed, it is reset.
2362
2362
2363 If names are given, all files matching the names are reverted.
2363 If names are given, all files matching the names are reverted.
2364 If no arguments are given, no files are reverted.
2364 If no arguments are given, no files are reverted.
2365
2365
2366 Modified files are saved with a .orig suffix before reverting.
2366 Modified files are saved with a .orig suffix before reverting.
2367 To disable these backups, use --no-backup.
2367 To disable these backups, use --no-backup.
2368 """
2368 """
2369
2369
2370 if opts["date"]:
2370 if opts["date"]:
2371 if opts["rev"]:
2371 if opts["rev"]:
2372 raise util.Abort(_("you can't specify a revision and a date"))
2372 raise util.Abort(_("you can't specify a revision and a date"))
2373 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2373 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2374
2374
2375 if not pats and not opts.get('all'):
2375 if not pats and not opts.get('all'):
2376 raise util.Abort(_('no files or directories specified; '
2376 raise util.Abort(_('no files or directories specified; '
2377 'use --all to revert the whole repo'))
2377 'use --all to revert the whole repo'))
2378
2378
2379 parent, p2 = repo.dirstate.parents()
2379 parent, p2 = repo.dirstate.parents()
2380 if not opts.get('rev') and p2 != nullid:
2380 if not opts.get('rev') and p2 != nullid:
2381 raise util.Abort(_('uncommitted merge - please provide a '
2381 raise util.Abort(_('uncommitted merge - please provide a '
2382 'specific revision'))
2382 'specific revision'))
2383 ctx = repo[opts.get('rev')]
2383 ctx = repo[opts.get('rev')]
2384 node = ctx.node()
2384 node = ctx.node()
2385 mf = ctx.manifest()
2385 mf = ctx.manifest()
2386 if node == parent:
2386 if node == parent:
2387 pmf = mf
2387 pmf = mf
2388 else:
2388 else:
2389 pmf = None
2389 pmf = None
2390
2390
2391 # need all matching names in dirstate and manifest of target rev,
2391 # need all matching names in dirstate and manifest of target rev,
2392 # so have to walk both. do not print errors if files exist in one
2392 # so have to walk both. do not print errors if files exist in one
2393 # but not other.
2393 # but not other.
2394
2394
2395 names = {}
2395 names = {}
2396
2396
2397 wlock = repo.wlock()
2397 wlock = repo.wlock()
2398 try:
2398 try:
2399 # walk dirstate.
2399 # walk dirstate.
2400 files = []
2400 files = []
2401
2401
2402 m = cmdutil.match(repo, pats, opts)
2402 m = cmdutil.match(repo, pats, opts)
2403 m.bad = lambda x,y: False
2403 m.bad = lambda x,y: False
2404 for abs in repo.walk(m):
2404 for abs in repo.walk(m):
2405 names[abs] = m.rel(abs), m.exact(abs)
2405 names[abs] = m.rel(abs), m.exact(abs)
2406
2406
2407 # walk target manifest.
2407 # walk target manifest.
2408
2408
2409 def badfn(path, msg):
2409 def badfn(path, msg):
2410 if path in names:
2410 if path in names:
2411 return False
2411 return False
2412 path_ = path + '/'
2412 path_ = path + '/'
2413 for f in names:
2413 for f in names:
2414 if f.startswith(path_):
2414 if f.startswith(path_):
2415 return False
2415 return False
2416 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2416 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2417 return False
2417 return False
2418
2418
2419 m = cmdutil.match(repo, pats, opts)
2419 m = cmdutil.match(repo, pats, opts)
2420 m.bad = badfn
2420 m.bad = badfn
2421 for abs in repo[node].walk(m):
2421 for abs in repo[node].walk(m):
2422 if abs not in names:
2422 if abs not in names:
2423 names[abs] = m.rel(abs), m.exact(abs)
2423 names[abs] = m.rel(abs), m.exact(abs)
2424
2424
2425 m = cmdutil.matchfiles(repo, names)
2425 m = cmdutil.matchfiles(repo, names)
2426 changes = repo.status(match=m)[:4]
2426 changes = repo.status(match=m)[:4]
2427 modified, added, removed, deleted = map(dict.fromkeys, changes)
2427 modified, added, removed, deleted = map(dict.fromkeys, changes)
2428
2428
2429 # if f is a rename, also revert the source
2429 # if f is a rename, also revert the source
2430 cwd = repo.getcwd()
2430 cwd = repo.getcwd()
2431 for f in added:
2431 for f in added:
2432 src = repo.dirstate.copied(f)
2432 src = repo.dirstate.copied(f)
2433 if src and src not in names and repo.dirstate[src] == 'r':
2433 if src and src not in names and repo.dirstate[src] == 'r':
2434 removed[src] = None
2434 removed[src] = None
2435 names[src] = (repo.pathto(src, cwd), True)
2435 names[src] = (repo.pathto(src, cwd), True)
2436
2436
2437 def removeforget(abs):
2437 def removeforget(abs):
2438 if repo.dirstate[abs] == 'a':
2438 if repo.dirstate[abs] == 'a':
2439 return _('forgetting %s\n')
2439 return _('forgetting %s\n')
2440 return _('removing %s\n')
2440 return _('removing %s\n')
2441
2441
2442 revert = ([], _('reverting %s\n'))
2442 revert = ([], _('reverting %s\n'))
2443 add = ([], _('adding %s\n'))
2443 add = ([], _('adding %s\n'))
2444 remove = ([], removeforget)
2444 remove = ([], removeforget)
2445 undelete = ([], _('undeleting %s\n'))
2445 undelete = ([], _('undeleting %s\n'))
2446
2446
2447 disptable = (
2447 disptable = (
2448 # dispatch table:
2448 # dispatch table:
2449 # file state
2449 # file state
2450 # action if in target manifest
2450 # action if in target manifest
2451 # action if not in target manifest
2451 # action if not in target manifest
2452 # make backup if in target manifest
2452 # make backup if in target manifest
2453 # make backup if not in target manifest
2453 # make backup if not in target manifest
2454 (modified, revert, remove, True, True),
2454 (modified, revert, remove, True, True),
2455 (added, revert, remove, True, False),
2455 (added, revert, remove, True, False),
2456 (removed, undelete, None, False, False),
2456 (removed, undelete, None, False, False),
2457 (deleted, revert, remove, False, False),
2457 (deleted, revert, remove, False, False),
2458 )
2458 )
2459
2459
2460 for abs, (rel, exact) in util.sort(names.items()):
2460 for abs, (rel, exact) in util.sort(names.items()):
2461 mfentry = mf.get(abs)
2461 mfentry = mf.get(abs)
2462 target = repo.wjoin(abs)
2462 target = repo.wjoin(abs)
2463 def handle(xlist, dobackup):
2463 def handle(xlist, dobackup):
2464 xlist[0].append(abs)
2464 xlist[0].append(abs)
2465 if dobackup and not opts.get('no_backup') and util.lexists(target):
2465 if dobackup and not opts.get('no_backup') and util.lexists(target):
2466 bakname = "%s.orig" % rel
2466 bakname = "%s.orig" % rel
2467 ui.note(_('saving current version of %s as %s\n') %
2467 ui.note(_('saving current version of %s as %s\n') %
2468 (rel, bakname))
2468 (rel, bakname))
2469 if not opts.get('dry_run'):
2469 if not opts.get('dry_run'):
2470 util.copyfile(target, bakname)
2470 util.copyfile(target, bakname)
2471 if ui.verbose or not exact:
2471 if ui.verbose or not exact:
2472 msg = xlist[1]
2472 msg = xlist[1]
2473 if not isinstance(msg, basestring):
2473 if not isinstance(msg, basestring):
2474 msg = msg(abs)
2474 msg = msg(abs)
2475 ui.status(msg % rel)
2475 ui.status(msg % rel)
2476 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2476 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2477 if abs not in table: continue
2477 if abs not in table: continue
2478 # file has changed in dirstate
2478 # file has changed in dirstate
2479 if mfentry:
2479 if mfentry:
2480 handle(hitlist, backuphit)
2480 handle(hitlist, backuphit)
2481 elif misslist is not None:
2481 elif misslist is not None:
2482 handle(misslist, backupmiss)
2482 handle(misslist, backupmiss)
2483 break
2483 break
2484 else:
2484 else:
2485 if abs not in repo.dirstate:
2485 if abs not in repo.dirstate:
2486 if mfentry:
2486 if mfentry:
2487 handle(add, True)
2487 handle(add, True)
2488 elif exact:
2488 elif exact:
2489 ui.warn(_('file not managed: %s\n') % rel)
2489 ui.warn(_('file not managed: %s\n') % rel)
2490 continue
2490 continue
2491 # file has not changed in dirstate
2491 # file has not changed in dirstate
2492 if node == parent:
2492 if node == parent:
2493 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2493 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2494 continue
2494 continue
2495 if pmf is None:
2495 if pmf is None:
2496 # only need parent manifest in this unlikely case,
2496 # only need parent manifest in this unlikely case,
2497 # so do not read by default
2497 # so do not read by default
2498 pmf = repo[parent].manifest()
2498 pmf = repo[parent].manifest()
2499 if abs in pmf:
2499 if abs in pmf:
2500 if mfentry:
2500 if mfentry:
2501 # if version of file is same in parent and target
2501 # if version of file is same in parent and target
2502 # manifests, do nothing
2502 # manifests, do nothing
2503 if (pmf[abs] != mfentry or
2503 if (pmf[abs] != mfentry or
2504 pmf.flags(abs) != mf.flags(abs)):
2504 pmf.flags(abs) != mf.flags(abs)):
2505 handle(revert, False)
2505 handle(revert, False)
2506 else:
2506 else:
2507 handle(remove, False)
2507 handle(remove, False)
2508
2508
2509 if not opts.get('dry_run'):
2509 if not opts.get('dry_run'):
2510 def checkout(f):
2510 def checkout(f):
2511 fc = ctx[f]
2511 fc = ctx[f]
2512 repo.wwrite(f, fc.data(), fc.flags())
2512 repo.wwrite(f, fc.data(), fc.flags())
2513
2513
2514 audit_path = util.path_auditor(repo.root)
2514 audit_path = util.path_auditor(repo.root)
2515 for f in remove[0]:
2515 for f in remove[0]:
2516 if repo.dirstate[f] == 'a':
2516 if repo.dirstate[f] == 'a':
2517 repo.dirstate.forget(f)
2517 repo.dirstate.forget(f)
2518 continue
2518 continue
2519 audit_path(f)
2519 audit_path(f)
2520 try:
2520 try:
2521 util.unlink(repo.wjoin(f))
2521 util.unlink(repo.wjoin(f))
2522 except OSError:
2522 except OSError:
2523 pass
2523 pass
2524 repo.dirstate.remove(f)
2524 repo.dirstate.remove(f)
2525
2525
2526 normal = None
2526 normal = None
2527 if node == parent:
2527 if node == parent:
2528 # We're reverting to our parent. If possible, we'd like status
2528 # We're reverting to our parent. If possible, we'd like status
2529 # to report the file as clean. We have to use normallookup for
2529 # to report the file as clean. We have to use normallookup for
2530 # merges to avoid losing information about merged/dirty files.
2530 # merges to avoid losing information about merged/dirty files.
2531 if p2 != nullid:
2531 if p2 != nullid:
2532 normal = repo.dirstate.normallookup
2532 normal = repo.dirstate.normallookup
2533 else:
2533 else:
2534 normal = repo.dirstate.normal
2534 normal = repo.dirstate.normal
2535 for f in revert[0]:
2535 for f in revert[0]:
2536 checkout(f)
2536 checkout(f)
2537 if normal:
2537 if normal:
2538 normal(f)
2538 normal(f)
2539
2539
2540 for f in add[0]:
2540 for f in add[0]:
2541 checkout(f)
2541 checkout(f)
2542 repo.dirstate.add(f)
2542 repo.dirstate.add(f)
2543
2543
2544 normal = repo.dirstate.normallookup
2544 normal = repo.dirstate.normallookup
2545 if node == parent and p2 == nullid:
2545 if node == parent and p2 == nullid:
2546 normal = repo.dirstate.normal
2546 normal = repo.dirstate.normal
2547 for f in undelete[0]:
2547 for f in undelete[0]:
2548 checkout(f)
2548 checkout(f)
2549 normal(f)
2549 normal(f)
2550
2550
2551 finally:
2551 finally:
2552 del wlock
2552 del wlock
2553
2553
2554 def rollback(ui, repo):
2554 def rollback(ui, repo):
2555 """roll back the last transaction
2555 """roll back the last transaction
2556
2556
2557 This command should be used with care. There is only one level of
2557 This command should be used with care. There is only one level of
2558 rollback, and there is no way to undo a rollback. It will also
2558 rollback, and there is no way to undo a rollback. It will also
2559 restore the dirstate at the time of the last transaction, losing
2559 restore the dirstate at the time of the last transaction, losing
2560 any dirstate changes since that time.
2560 any dirstate changes since that time.
2561
2561
2562 Transactions are used to encapsulate the effects of all commands
2562 Transactions are used to encapsulate the effects of all commands
2563 that create new changesets or propagate existing changesets into a
2563 that create new changesets or propagate existing changesets into a
2564 repository. For example, the following commands are transactional,
2564 repository. For example, the following commands are transactional,
2565 and their effects can be rolled back:
2565 and their effects can be rolled back:
2566
2566
2567 commit
2567 commit
2568 import
2568 import
2569 pull
2569 pull
2570 push (with this repository as destination)
2570 push (with this repository as destination)
2571 unbundle
2571 unbundle
2572
2572
2573 This command is not intended for use on public repositories. Once
2573 This command is not intended for use on public repositories. Once
2574 changes are visible for pull by other users, rolling a transaction
2574 changes are visible for pull by other users, rolling a transaction
2575 back locally is ineffective (someone else may already have pulled
2575 back locally is ineffective (someone else may already have pulled
2576 the changes). Furthermore, a race is possible with readers of the
2576 the changes). Furthermore, a race is possible with readers of the
2577 repository; for example an in-progress pull from the repository
2577 repository; for example an in-progress pull from the repository
2578 may fail if a rollback is performed.
2578 may fail if a rollback is performed.
2579 """
2579 """
2580 repo.rollback()
2580 repo.rollback()
2581
2581
2582 def root(ui, repo):
2582 def root(ui, repo):
2583 """print the root (top) of the current working dir
2583 """print the root (top) of the current working dir
2584
2584
2585 Print the root directory of the current repository.
2585 Print the root directory of the current repository.
2586 """
2586 """
2587 ui.write(repo.root + "\n")
2587 ui.write(repo.root + "\n")
2588
2588
2589 def serve(ui, repo, **opts):
2589 def serve(ui, repo, **opts):
2590 """export the repository via HTTP
2590 """export the repository via HTTP
2591
2591
2592 Start a local HTTP repository browser and pull server.
2592 Start a local HTTP repository browser and pull server.
2593
2593
2594 By default, the server logs accesses to stdout and errors to
2594 By default, the server logs accesses to stdout and errors to
2595 stderr. Use the "-A" and "-E" options to log to files.
2595 stderr. Use the "-A" and "-E" options to log to files.
2596 """
2596 """
2597
2597
2598 if opts["stdio"]:
2598 if opts["stdio"]:
2599 if repo is None:
2599 if repo is None:
2600 raise RepoError(_("There is no Mercurial repository here"
2600 raise RepoError(_("There is no Mercurial repository here"
2601 " (.hg not found)"))
2601 " (.hg not found)"))
2602 s = sshserver.sshserver(ui, repo)
2602 s = sshserver.sshserver(ui, repo)
2603 s.serve_forever()
2603 s.serve_forever()
2604
2604
2605 parentui = ui.parentui or ui
2605 parentui = ui.parentui or ui
2606 optlist = ("name templates style address port prefix ipv6"
2606 optlist = ("name templates style address port prefix ipv6"
2607 " accesslog errorlog webdir_conf certificate")
2607 " accesslog errorlog webdir_conf certificate")
2608 for o in optlist.split():
2608 for o in optlist.split():
2609 if opts[o]:
2609 if opts[o]:
2610 parentui.setconfig("web", o, str(opts[o]))
2610 parentui.setconfig("web", o, str(opts[o]))
2611 if (repo is not None) and (repo.ui != parentui):
2611 if (repo is not None) and (repo.ui != parentui):
2612 repo.ui.setconfig("web", o, str(opts[o]))
2612 repo.ui.setconfig("web", o, str(opts[o]))
2613
2613
2614 if repo is None and not ui.config("web", "webdir_conf"):
2614 if repo is None and not ui.config("web", "webdir_conf"):
2615 raise RepoError(_("There is no Mercurial repository here"
2615 raise RepoError(_("There is no Mercurial repository here"
2616 " (.hg not found)"))
2616 " (.hg not found)"))
2617
2617
2618 class service:
2618 class service:
2619 def init(self):
2619 def init(self):
2620 util.set_signal_handler()
2620 util.set_signal_handler()
2621 self.httpd = hgweb.server.create_server(parentui, repo)
2621 self.httpd = hgweb.server.create_server(parentui, repo)
2622
2622
2623 if not ui.verbose: return
2623 if not ui.verbose: return
2624
2624
2625 if self.httpd.prefix:
2625 if self.httpd.prefix:
2626 prefix = self.httpd.prefix.strip('/') + '/'
2626 prefix = self.httpd.prefix.strip('/') + '/'
2627 else:
2627 else:
2628 prefix = ''
2628 prefix = ''
2629
2629
2630 port = ':%d' % self.httpd.port
2630 port = ':%d' % self.httpd.port
2631 if port == ':80':
2631 if port == ':80':
2632 port = ''
2632 port = ''
2633
2633
2634 bindaddr = self.httpd.addr
2634 bindaddr = self.httpd.addr
2635 if bindaddr == '0.0.0.0':
2635 if bindaddr == '0.0.0.0':
2636 bindaddr = '*'
2636 bindaddr = '*'
2637 elif ':' in bindaddr: # IPv6
2637 elif ':' in bindaddr: # IPv6
2638 bindaddr = '[%s]' % bindaddr
2638 bindaddr = '[%s]' % bindaddr
2639
2639
2640 fqaddr = self.httpd.fqaddr
2640 fqaddr = self.httpd.fqaddr
2641 if ':' in fqaddr:
2641 if ':' in fqaddr:
2642 fqaddr = '[%s]' % fqaddr
2642 fqaddr = '[%s]' % fqaddr
2643 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2643 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2644 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2644 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2645
2645
2646 def run(self):
2646 def run(self):
2647 self.httpd.serve_forever()
2647 self.httpd.serve_forever()
2648
2648
2649 service = service()
2649 service = service()
2650
2650
2651 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2651 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2652
2652
2653 def status(ui, repo, *pats, **opts):
2653 def status(ui, repo, *pats, **opts):
2654 """show changed files in the working directory
2654 """show changed files in the working directory
2655
2655
2656 Show status of files in the repository. If names are given, only
2656 Show status of files in the repository. If names are given, only
2657 files that match are shown. Files that are clean or ignored or
2657 files that match are shown. Files that are clean or ignored or
2658 source of a copy/move operation, are not listed unless -c (clean),
2658 source of a copy/move operation, are not listed unless -c (clean),
2659 -i (ignored), -C (copies) or -A is given. Unless options described
2659 -i (ignored), -C (copies) or -A is given. Unless options described
2660 with "show only ..." are given, the options -mardu are used.
2660 with "show only ..." are given, the options -mardu are used.
2661
2661
2662 Option -q/--quiet hides untracked (unknown and ignored) files
2662 Option -q/--quiet hides untracked (unknown and ignored) files
2663 unless explicitly requested with -u/--unknown or -i/-ignored.
2663 unless explicitly requested with -u/--unknown or -i/-ignored.
2664
2664
2665 NOTE: status may appear to disagree with diff if permissions have
2665 NOTE: status may appear to disagree with diff if permissions have
2666 changed or a merge has occurred. The standard diff format does not
2666 changed or a merge has occurred. The standard diff format does not
2667 report permission changes and diff only reports changes relative
2667 report permission changes and diff only reports changes relative
2668 to one merge parent.
2668 to one merge parent.
2669
2669
2670 If one revision is given, it is used as the base revision.
2670 If one revision is given, it is used as the base revision.
2671 If two revisions are given, the difference between them is shown.
2671 If two revisions are given, the difference between them is shown.
2672
2672
2673 The codes used to show the status of files are:
2673 The codes used to show the status of files are:
2674 M = modified
2674 M = modified
2675 A = added
2675 A = added
2676 R = removed
2676 R = removed
2677 C = clean
2677 C = clean
2678 ! = deleted, but still tracked
2678 ! = deleted, but still tracked
2679 ? = not tracked
2679 ? = not tracked
2680 I = ignored
2680 I = ignored
2681 = the previous added file was copied from here
2681 = the previous added file was copied from here
2682 """
2682 """
2683
2683
2684 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2684 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2685 cwd = (pats and repo.getcwd()) or ''
2685 cwd = (pats and repo.getcwd()) or ''
2686 end = opts.get('print0') and '\0' or '\n'
2686 end = opts.get('print0') and '\0' or '\n'
2687 copy = {}
2687 copy = {}
2688 states = 'modified added removed deleted unknown ignored clean'.split()
2688 states = 'modified added removed deleted unknown ignored clean'.split()
2689 show = [k for k in states if opts[k]]
2689 show = [k for k in states if opts[k]]
2690 if opts.get('all'):
2690 if opts.get('all'):
2691 show += ui.quiet and (states[:4] + ['clean']) or states
2691 show += ui.quiet and (states[:4] + ['clean']) or states
2692 if not show:
2692 if not show:
2693 show = ui.quiet and states[:4] or states[:5]
2693 show = ui.quiet and states[:4] or states[:5]
2694
2694
2695 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2695 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2696 'ignored' in show, 'clean' in show, 'unknown' in show)
2696 'ignored' in show, 'clean' in show, 'unknown' in show)
2697 changestates = zip(states, 'MAR!?IC', stat)
2697 changestates = zip(states, 'MAR!?IC', stat)
2698
2698
2699 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2699 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2700 ctxn = repo[nullid]
2700 ctxn = repo[nullid]
2701 ctx1 = repo[node1]
2701 ctx1 = repo[node1]
2702 ctx2 = repo[node2]
2702 ctx2 = repo[node2]
2703 added = stat[1]
2703 added = stat[1]
2704 if node2 is None:
2704 if node2 is None:
2705 added = stat[0] + stat[1] # merged?
2705 added = stat[0] + stat[1] # merged?
2706
2706
2707 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2707 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2708 if k in added:
2708 if k in added:
2709 copy[k] = v
2709 copy[k] = v
2710 elif v in added:
2710 elif v in added:
2711 copy[v] = k
2711 copy[v] = k
2712
2712
2713 for state, char, files in changestates:
2713 for state, char, files in changestates:
2714 if state in show:
2714 if state in show:
2715 format = "%s %%s%s" % (char, end)
2715 format = "%s %%s%s" % (char, end)
2716 if opts.get('no_status'):
2716 if opts.get('no_status'):
2717 format = "%%s%s" % end
2717 format = "%%s%s" % end
2718
2718
2719 for f in files:
2719 for f in files:
2720 ui.write(format % repo.pathto(f, cwd))
2720 ui.write(format % repo.pathto(f, cwd))
2721 if f in copy:
2721 if f in copy:
2722 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2722 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2723
2723
2724 def tag(ui, repo, name1, *names, **opts):
2724 def tag(ui, repo, name1, *names, **opts):
2725 """add one or more tags for the current or given revision
2725 """add one or more tags for the current or given revision
2726
2726
2727 Name a particular revision using <name>.
2727 Name a particular revision using <name>.
2728
2728
2729 Tags are used to name particular revisions of the repository and are
2729 Tags are used to name particular revisions of the repository and are
2730 very useful to compare different revisions, to go back to significant
2730 very useful to compare different revisions, to go back to significant
2731 earlier versions or to mark branch points as releases, etc.
2731 earlier versions or to mark branch points as releases, etc.
2732
2732
2733 If no revision is given, the parent of the working directory is used,
2733 If no revision is given, the parent of the working directory is used,
2734 or tip if no revision is checked out.
2734 or tip if no revision is checked out.
2735
2735
2736 To facilitate version control, distribution, and merging of tags,
2736 To facilitate version control, distribution, and merging of tags,
2737 they are stored as a file named ".hgtags" which is managed
2737 they are stored as a file named ".hgtags" which is managed
2738 similarly to other project files and can be hand-edited if
2738 similarly to other project files and can be hand-edited if
2739 necessary. The file '.hg/localtags' is used for local tags (not
2739 necessary. The file '.hg/localtags' is used for local tags (not
2740 shared among repositories).
2740 shared among repositories).
2741
2741
2742 See 'hg help dates' for a list of formats valid for -d/--date.
2742 See 'hg help dates' for a list of formats valid for -d/--date.
2743 """
2743 """
2744
2744
2745 rev_ = "."
2745 rev_ = "."
2746 names = (name1,) + names
2746 names = (name1,) + names
2747 if len(names) != len(dict.fromkeys(names)):
2747 if len(names) != len(dict.fromkeys(names)):
2748 raise util.Abort(_('tag names must be unique'))
2748 raise util.Abort(_('tag names must be unique'))
2749 for n in names:
2749 for n in names:
2750 if n in ['tip', '.', 'null']:
2750 if n in ['tip', '.', 'null']:
2751 raise util.Abort(_('the name \'%s\' is reserved') % n)
2751 raise util.Abort(_('the name \'%s\' is reserved') % n)
2752 if opts.get('rev') and opts.get('remove'):
2752 if opts.get('rev') and opts.get('remove'):
2753 raise util.Abort(_("--rev and --remove are incompatible"))
2753 raise util.Abort(_("--rev and --remove are incompatible"))
2754 if opts.get('rev'):
2754 if opts.get('rev'):
2755 rev_ = opts['rev']
2755 rev_ = opts['rev']
2756 message = opts.get('message')
2756 message = opts.get('message')
2757 if opts.get('remove'):
2757 if opts.get('remove'):
2758 expectedtype = opts.get('local') and 'local' or 'global'
2758 expectedtype = opts.get('local') and 'local' or 'global'
2759 for n in names:
2759 for n in names:
2760 if not repo.tagtype(n):
2760 if not repo.tagtype(n):
2761 raise util.Abort(_('tag \'%s\' does not exist') % n)
2761 raise util.Abort(_('tag \'%s\' does not exist') % n)
2762 if repo.tagtype(n) != expectedtype:
2762 if repo.tagtype(n) != expectedtype:
2763 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2763 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2764 (n, expectedtype))
2764 (n, expectedtype))
2765 rev_ = nullid
2765 rev_ = nullid
2766 if not message:
2766 if not message:
2767 message = _('Removed tag %s') % ', '.join(names)
2767 message = _('Removed tag %s') % ', '.join(names)
2768 elif not opts.get('force'):
2768 elif not opts.get('force'):
2769 for n in names:
2769 for n in names:
2770 if n in repo.tags():
2770 if n in repo.tags():
2771 raise util.Abort(_('tag \'%s\' already exists '
2771 raise util.Abort(_('tag \'%s\' already exists '
2772 '(use -f to force)') % n)
2772 '(use -f to force)') % n)
2773 if not rev_ and repo.dirstate.parents()[1] != nullid:
2773 if not rev_ and repo.dirstate.parents()[1] != nullid:
2774 raise util.Abort(_('uncommitted merge - please provide a '
2774 raise util.Abort(_('uncommitted merge - please provide a '
2775 'specific revision'))
2775 'specific revision'))
2776 r = repo[rev_].node()
2776 r = repo[rev_].node()
2777
2777
2778 if not message:
2778 if not message:
2779 message = (_('Added tag %s for changeset %s') %
2779 message = (_('Added tag %s for changeset %s') %
2780 (', '.join(names), short(r)))
2780 (', '.join(names), short(r)))
2781
2781
2782 date = opts.get('date')
2782 date = opts.get('date')
2783 if date:
2783 if date:
2784 date = util.parsedate(date)
2784 date = util.parsedate(date)
2785
2785
2786 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2786 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2787
2787
2788 def tags(ui, repo):
2788 def tags(ui, repo):
2789 """list repository tags
2789 """list repository tags
2790
2790
2791 List the repository tags.
2791 List the repository tags.
2792
2792
2793 This lists both regular and local tags. When the -v/--verbose switch
2793 This lists both regular and local tags. When the -v/--verbose switch
2794 is used, a third column "local" is printed for local tags.
2794 is used, a third column "local" is printed for local tags.
2795 """
2795 """
2796
2796
2797 l = repo.tagslist()
2797 l = repo.tagslist()
2798 l.reverse()
2798 l.reverse()
2799 hexfunc = ui.debugflag and hex or short
2799 hexfunc = ui.debugflag and hex or short
2800 tagtype = ""
2800 tagtype = ""
2801
2801
2802 for t, n in l:
2802 for t, n in l:
2803 if ui.quiet:
2803 if ui.quiet:
2804 ui.write("%s\n" % t)
2804 ui.write("%s\n" % t)
2805 continue
2805 continue
2806
2806
2807 try:
2807 try:
2808 hn = hexfunc(n)
2808 hn = hexfunc(n)
2809 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2809 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2810 except revlog.LookupError:
2810 except revlog.LookupError:
2811 r = " ?:%s" % hn
2811 r = " ?:%s" % hn
2812 else:
2812 else:
2813 spaces = " " * (30 - util.locallen(t))
2813 spaces = " " * (30 - util.locallen(t))
2814 if ui.verbose:
2814 if ui.verbose:
2815 if repo.tagtype(t) == 'local':
2815 if repo.tagtype(t) == 'local':
2816 tagtype = " local"
2816 tagtype = " local"
2817 else:
2817 else:
2818 tagtype = ""
2818 tagtype = ""
2819 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2819 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2820
2820
2821 def tip(ui, repo, **opts):
2821 def tip(ui, repo, **opts):
2822 """show the tip revision
2822 """show the tip revision
2823
2823
2824 The tip revision (usually just called the tip) is the most
2824 The tip revision (usually just called the tip) is the most
2825 recently added changeset in the repository, the most recently
2825 recently added changeset in the repository, the most recently
2826 changed head.
2826 changed head.
2827
2827
2828 If you have just made a commit, that commit will be the tip. If
2828 If you have just made a commit, that commit will be the tip. If
2829 you have just pulled changes from another repository, the tip of
2829 you have just pulled changes from another repository, the tip of
2830 that repository becomes the current tip. The "tip" tag is special
2830 that repository becomes the current tip. The "tip" tag is special
2831 and cannot be renamed or assigned to a different changeset.
2831 and cannot be renamed or assigned to a different changeset.
2832 """
2832 """
2833 cmdutil.show_changeset(ui, repo, opts).show(len(repo) - 1)
2833 cmdutil.show_changeset(ui, repo, opts).show(len(repo) - 1)
2834
2834
2835 def unbundle(ui, repo, fname1, *fnames, **opts):
2835 def unbundle(ui, repo, fname1, *fnames, **opts):
2836 """apply one or more changegroup files
2836 """apply one or more changegroup files
2837
2837
2838 Apply one or more compressed changegroup files generated by the
2838 Apply one or more compressed changegroup files generated by the
2839 bundle command.
2839 bundle command.
2840 """
2840 """
2841 fnames = (fname1,) + fnames
2841 fnames = (fname1,) + fnames
2842
2842
2843 lock = None
2843 lock = None
2844 try:
2844 try:
2845 lock = repo.lock()
2845 lock = repo.lock()
2846 for fname in fnames:
2846 for fname in fnames:
2847 if os.path.exists(fname):
2847 if os.path.exists(fname):
2848 f = open(fname, "rb")
2848 f = open(fname, "rb")
2849 else:
2849 else:
2850 f = urllib.urlopen(fname)
2850 f = urllib.urlopen(fname)
2851 gen = changegroup.readbundle(f, fname)
2851 gen = changegroup.readbundle(f, fname)
2852 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2852 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2853 finally:
2853 finally:
2854 del lock
2854 del lock
2855
2855
2856 return postincoming(ui, repo, modheads, opts.get('update'), None)
2856 return postincoming(ui, repo, modheads, opts.get('update'), None)
2857
2857
2858 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2858 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2859 """update working directory
2859 """update working directory
2860
2860
2861 Update the repository's working directory to the specified revision,
2861 Update the repository's working directory to the specified revision,
2862 or the tip of the current branch if none is specified. Use null as
2862 or the tip of the current branch if none is specified. Use null as
2863 the revision to remove the working copy (like 'hg clone -U').
2863 the revision to remove the working copy (like 'hg clone -U').
2864
2864
2865 If the requested revision is a descendant of the working
2865 If the requested revision is a descendant of the working
2866 directory, any outstanding changes in the working directory will
2866 directory, any outstanding changes in the working directory will
2867 be merged into the result. If it is not directly descended but is
2867 be merged into the result. If it is not directly descended but is
2868 on the same named branch, update aborts with a suggestion to use
2868 on the same named branch, update aborts with a suggestion to use
2869 merge or update -C instead.
2869 merge or update -C instead.
2870
2870
2871 If the requested revision is on a different named branch and the
2871 If the requested revision is on a different named branch and the
2872 working directory is clean, update quietly switches branches.
2872 working directory is clean, update quietly switches branches.
2873
2873
2874 If you want to update just one file to an older revision, use revert.
2874 If you want to update just one file to an older revision, use revert.
2875
2875
2876 See 'hg help dates' for a list of formats valid for --date.
2876 See 'hg help dates' for a list of formats valid for --date.
2877 """
2877 """
2878 if rev and node:
2878 if rev and node:
2879 raise util.Abort(_("please specify just one revision"))
2879 raise util.Abort(_("please specify just one revision"))
2880
2880
2881 if not rev:
2881 if not rev:
2882 rev = node
2882 rev = node
2883
2883
2884 if date:
2884 if date:
2885 if rev:
2885 if rev:
2886 raise util.Abort(_("you can't specify a revision and a date"))
2886 raise util.Abort(_("you can't specify a revision and a date"))
2887 rev = cmdutil.finddate(ui, repo, date)
2887 rev = cmdutil.finddate(ui, repo, date)
2888
2888
2889 if clean:
2889 if clean:
2890 return hg.clean(repo, rev)
2890 return hg.clean(repo, rev)
2891 else:
2891 else:
2892 return hg.update(repo, rev)
2892 return hg.update(repo, rev)
2893
2893
2894 def verify(ui, repo):
2894 def verify(ui, repo):
2895 """verify the integrity of the repository
2895 """verify the integrity of the repository
2896
2896
2897 Verify the integrity of the current repository.
2897 Verify the integrity of the current repository.
2898
2898
2899 This will perform an extensive check of the repository's
2899 This will perform an extensive check of the repository's
2900 integrity, validating the hashes and checksums of each entry in
2900 integrity, validating the hashes and checksums of each entry in
2901 the changelog, manifest, and tracked files, as well as the
2901 the changelog, manifest, and tracked files, as well as the
2902 integrity of their crosslinks and indices.
2902 integrity of their crosslinks and indices.
2903 """
2903 """
2904 return hg.verify(repo)
2904 return hg.verify(repo)
2905
2905
2906 def version_(ui):
2906 def version_(ui):
2907 """output version and copyright information"""
2907 """output version and copyright information"""
2908 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2908 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2909 % version.get_version())
2909 % version.get_version())
2910 ui.status(_(
2910 ui.status(_(
2911 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2911 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2912 "This is free software; see the source for copying conditions. "
2912 "This is free software; see the source for copying conditions. "
2913 "There is NO\nwarranty; "
2913 "There is NO\nwarranty; "
2914 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2914 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2915 ))
2915 ))
2916
2916
2917 # Command options and aliases are listed here, alphabetically
2917 # Command options and aliases are listed here, alphabetically
2918
2918
2919 globalopts = [
2919 globalopts = [
2920 ('R', 'repository', '',
2920 ('R', 'repository', '',
2921 _('repository root directory or symbolic path name')),
2921 _('repository root directory or symbolic path name')),
2922 ('', 'cwd', '', _('change working directory')),
2922 ('', 'cwd', '', _('change working directory')),
2923 ('y', 'noninteractive', None,
2923 ('y', 'noninteractive', None,
2924 _('do not prompt, assume \'yes\' for any required answers')),
2924 _('do not prompt, assume \'yes\' for any required answers')),
2925 ('q', 'quiet', None, _('suppress output')),
2925 ('q', 'quiet', None, _('suppress output')),
2926 ('v', 'verbose', None, _('enable additional output')),
2926 ('v', 'verbose', None, _('enable additional output')),
2927 ('', 'config', [], _('set/override config option')),
2927 ('', 'config', [], _('set/override config option')),
2928 ('', 'debug', None, _('enable debugging output')),
2928 ('', 'debug', None, _('enable debugging output')),
2929 ('', 'debugger', None, _('start debugger')),
2929 ('', 'debugger', None, _('start debugger')),
2930 ('', 'encoding', util._encoding, _('set the charset encoding')),
2930 ('', 'encoding', util._encoding, _('set the charset encoding')),
2931 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2931 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2932 ('', 'lsprof', None, _('print improved command execution profile')),
2932 ('', 'lsprof', None, _('print improved command execution profile')),
2933 ('', 'traceback', None, _('print traceback on exception')),
2933 ('', 'traceback', None, _('print traceback on exception')),
2934 ('', 'time', None, _('time how long the command takes')),
2934 ('', 'time', None, _('time how long the command takes')),
2935 ('', 'profile', None, _('print command execution profile')),
2935 ('', 'profile', None, _('print command execution profile')),
2936 ('', 'version', None, _('output version information and exit')),
2936 ('', 'version', None, _('output version information and exit')),
2937 ('h', 'help', None, _('display help and exit')),
2937 ('h', 'help', None, _('display help and exit')),
2938 ]
2938 ]
2939
2939
2940 dryrunopts = [('n', 'dry-run', None,
2940 dryrunopts = [('n', 'dry-run', None,
2941 _('do not perform actions, just print output'))]
2941 _('do not perform actions, just print output'))]
2942
2942
2943 remoteopts = [
2943 remoteopts = [
2944 ('e', 'ssh', '', _('specify ssh command to use')),
2944 ('e', 'ssh', '', _('specify ssh command to use')),
2945 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2945 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2946 ]
2946 ]
2947
2947
2948 walkopts = [
2948 walkopts = [
2949 ('I', 'include', [], _('include names matching the given patterns')),
2949 ('I', 'include', [], _('include names matching the given patterns')),
2950 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2950 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2951 ]
2951 ]
2952
2952
2953 commitopts = [
2953 commitopts = [
2954 ('m', 'message', '', _('use <text> as commit message')),
2954 ('m', 'message', '', _('use <text> as commit message')),
2955 ('l', 'logfile', '', _('read commit message from <file>')),
2955 ('l', 'logfile', '', _('read commit message from <file>')),
2956 ]
2956 ]
2957
2957
2958 commitopts2 = [
2958 commitopts2 = [
2959 ('d', 'date', '', _('record datecode as commit date')),
2959 ('d', 'date', '', _('record datecode as commit date')),
2960 ('u', 'user', '', _('record user as committer')),
2960 ('u', 'user', '', _('record user as committer')),
2961 ]
2961 ]
2962
2962
2963 templateopts = [
2963 templateopts = [
2964 ('', 'style', '', _('display using template map file')),
2964 ('', 'style', '', _('display using template map file')),
2965 ('', 'template', '', _('display with template')),
2965 ('', 'template', '', _('display with template')),
2966 ]
2966 ]
2967
2967
2968 logopts = [
2968 logopts = [
2969 ('p', 'patch', None, _('show patch')),
2969 ('p', 'patch', None, _('show patch')),
2970 ('l', 'limit', '', _('limit number of changes displayed')),
2970 ('l', 'limit', '', _('limit number of changes displayed')),
2971 ('M', 'no-merges', None, _('do not show merges')),
2971 ('M', 'no-merges', None, _('do not show merges')),
2972 ] + templateopts
2972 ] + templateopts
2973
2973
2974 diffopts = [
2974 diffopts = [
2975 ('a', 'text', None, _('treat all files as text')),
2975 ('a', 'text', None, _('treat all files as text')),
2976 ('g', 'git', None, _('use git extended diff format')),
2976 ('g', 'git', None, _('use git extended diff format')),
2977 ('', 'nodates', None, _("don't include dates in diff headers"))
2977 ('', 'nodates', None, _("don't include dates in diff headers"))
2978 ]
2978 ]
2979
2979
2980 diffopts2 = [
2980 diffopts2 = [
2981 ('p', 'show-function', None, _('show which function each change is in')),
2981 ('p', 'show-function', None, _('show which function each change is in')),
2982 ('w', 'ignore-all-space', None,
2982 ('w', 'ignore-all-space', None,
2983 _('ignore white space when comparing lines')),
2983 _('ignore white space when comparing lines')),
2984 ('b', 'ignore-space-change', None,
2984 ('b', 'ignore-space-change', None,
2985 _('ignore changes in the amount of white space')),
2985 _('ignore changes in the amount of white space')),
2986 ('B', 'ignore-blank-lines', None,
2986 ('B', 'ignore-blank-lines', None,
2987 _('ignore changes whose lines are all blank')),
2987 _('ignore changes whose lines are all blank')),
2988 ('U', 'unified', '', _('number of lines of context to show'))
2988 ('U', 'unified', '', _('number of lines of context to show'))
2989 ]
2989 ]
2990
2990
2991 table = {
2991 table = {
2992 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2992 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2993 "addremove":
2993 "addremove":
2994 (addremove,
2994 (addremove,
2995 [('s', 'similarity', '',
2995 [('s', 'similarity', '',
2996 _('guess renamed files by similarity (0<=s<=100)')),
2996 _('guess renamed files by similarity (0<=s<=100)')),
2997 ] + walkopts + dryrunopts,
2997 ] + walkopts + dryrunopts,
2998 _('hg addremove [OPTION]... [FILE]...')),
2998 _('hg addremove [OPTION]... [FILE]...')),
2999 "^annotate|blame":
2999 "^annotate|blame":
3000 (annotate,
3000 (annotate,
3001 [('r', 'rev', '', _('annotate the specified revision')),
3001 [('r', 'rev', '', _('annotate the specified revision')),
3002 ('f', 'follow', None, _('follow file copies and renames')),
3002 ('f', 'follow', None, _('follow file copies and renames')),
3003 ('a', 'text', None, _('treat all files as text')),
3003 ('a', 'text', None, _('treat all files as text')),
3004 ('u', 'user', None, _('list the author (long with -v)')),
3004 ('u', 'user', None, _('list the author (long with -v)')),
3005 ('d', 'date', None, _('list the date (short with -q)')),
3005 ('d', 'date', None, _('list the date (short with -q)')),
3006 ('n', 'number', None, _('list the revision number (default)')),
3006 ('n', 'number', None, _('list the revision number (default)')),
3007 ('c', 'changeset', None, _('list the changeset')),
3007 ('c', 'changeset', None, _('list the changeset')),
3008 ('l', 'line-number', None,
3008 ('l', 'line-number', None,
3009 _('show line number at the first appearance'))
3009 _('show line number at the first appearance'))
3010 ] + walkopts,
3010 ] + walkopts,
3011 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3011 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3012 "archive":
3012 "archive":
3013 (archive,
3013 (archive,
3014 [('', 'no-decode', None, _('do not pass files through decoders')),
3014 [('', 'no-decode', None, _('do not pass files through decoders')),
3015 ('p', 'prefix', '', _('directory prefix for files in archive')),
3015 ('p', 'prefix', '', _('directory prefix for files in archive')),
3016 ('r', 'rev', '', _('revision to distribute')),
3016 ('r', 'rev', '', _('revision to distribute')),
3017 ('t', 'type', '', _('type of distribution to create')),
3017 ('t', 'type', '', _('type of distribution to create')),
3018 ] + walkopts,
3018 ] + walkopts,
3019 _('hg archive [OPTION]... DEST')),
3019 _('hg archive [OPTION]... DEST')),
3020 "backout":
3020 "backout":
3021 (backout,
3021 (backout,
3022 [('', 'merge', None,
3022 [('', 'merge', None,
3023 _('merge with old dirstate parent after backout')),
3023 _('merge with old dirstate parent after backout')),
3024 ('', 'parent', '', _('parent to choose when backing out merge')),
3024 ('', 'parent', '', _('parent to choose when backing out merge')),
3025 ('r', 'rev', '', _('revision to backout')),
3025 ('r', 'rev', '', _('revision to backout')),
3026 ] + walkopts + commitopts + commitopts2,
3026 ] + walkopts + commitopts + commitopts2,
3027 _('hg backout [OPTION]... [-r] REV')),
3027 _('hg backout [OPTION]... [-r] REV')),
3028 "bisect":
3028 "bisect":
3029 (bisect,
3029 (bisect,
3030 [('r', 'reset', False, _('reset bisect state')),
3030 [('r', 'reset', False, _('reset bisect state')),
3031 ('g', 'good', False, _('mark changeset good')),
3031 ('g', 'good', False, _('mark changeset good')),
3032 ('b', 'bad', False, _('mark changeset bad')),
3032 ('b', 'bad', False, _('mark changeset bad')),
3033 ('s', 'skip', False, _('skip testing changeset')),
3033 ('s', 'skip', False, _('skip testing changeset')),
3034 ('c', 'command', '', _('Use command to check changeset state')),
3034 ('c', 'command', '', _('Use command to check changeset state')),
3035 ('U', 'noupdate', False, _('do not update to target'))],
3035 ('U', 'noupdate', False, _('do not update to target'))],
3036 _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
3036 _("hg bisect [-gbsr] [REV] [-c COMMAND]")),
3037 "branch":
3037 "branch":
3038 (branch,
3038 (branch,
3039 [('f', 'force', None,
3039 [('f', 'force', None,
3040 _('set branch name even if it shadows an existing branch')),
3040 _('set branch name even if it shadows an existing branch')),
3041 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3041 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3042 _('hg branch [-fC] [NAME]')),
3042 _('hg branch [-fC] [NAME]')),
3043 "branches":
3043 "branches":
3044 (branches,
3044 (branches,
3045 [('a', 'active', False,
3045 [('a', 'active', False,
3046 _('show only branches that have unmerged heads'))],
3046 _('show only branches that have unmerged heads'))],
3047 _('hg branches [-a]')),
3047 _('hg branches [-a]')),
3048 "bundle":
3048 "bundle":
3049 (bundle,
3049 (bundle,
3050 [('f', 'force', None,
3050 [('f', 'force', None,
3051 _('run even when remote repository is unrelated')),
3051 _('run even when remote repository is unrelated')),
3052 ('r', 'rev', [],
3052 ('r', 'rev', [],
3053 _('a changeset up to which you would like to bundle')),
3053 _('a changeset up to which you would like to bundle')),
3054 ('', 'base', [],
3054 ('', 'base', [],
3055 _('a base changeset to specify instead of a destination')),
3055 _('a base changeset to specify instead of a destination')),
3056 ('a', 'all', None, _('bundle all changesets in the repository')),
3056 ('a', 'all', None, _('bundle all changesets in the repository')),
3057 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3057 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3058 ] + remoteopts,
3058 ] + remoteopts,
3059 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3059 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3060 "cat":
3060 "cat":
3061 (cat,
3061 (cat,
3062 [('o', 'output', '', _('print output to file with formatted name')),
3062 [('o', 'output', '', _('print output to file with formatted name')),
3063 ('r', 'rev', '', _('print the given revision')),
3063 ('r', 'rev', '', _('print the given revision')),
3064 ('', 'decode', None, _('apply any matching decode filter')),
3064 ('', 'decode', None, _('apply any matching decode filter')),
3065 ] + walkopts,
3065 ] + walkopts,
3066 _('hg cat [OPTION]... FILE...')),
3066 _('hg cat [OPTION]... FILE...')),
3067 "^clone":
3067 "^clone":
3068 (clone,
3068 (clone,
3069 [('U', 'noupdate', None,
3069 [('U', 'noupdate', None,
3070 _('the clone will only contain a repository (no working copy)')),
3070 _('the clone will only contain a repository (no working copy)')),
3071 ('r', 'rev', [],
3071 ('r', 'rev', [],
3072 _('a changeset you would like to have after cloning')),
3072 _('a changeset you would like to have after cloning')),
3073 ('', 'pull', None, _('use pull protocol to copy metadata')),
3073 ('', 'pull', None, _('use pull protocol to copy metadata')),
3074 ('', 'uncompressed', None,
3074 ('', 'uncompressed', None,
3075 _('use uncompressed transfer (fast over LAN)')),
3075 _('use uncompressed transfer (fast over LAN)')),
3076 ] + remoteopts,
3076 ] + remoteopts,
3077 _('hg clone [OPTION]... SOURCE [DEST]')),
3077 _('hg clone [OPTION]... SOURCE [DEST]')),
3078 "^commit|ci":
3078 "^commit|ci":
3079 (commit,
3079 (commit,
3080 [('A', 'addremove', None,
3080 [('A', 'addremove', None,
3081 _('mark new/missing files as added/removed before committing')),
3081 _('mark new/missing files as added/removed before committing')),
3082 ] + walkopts + commitopts + commitopts2,
3082 ] + walkopts + commitopts + commitopts2,
3083 _('hg commit [OPTION]... [FILE]...')),
3083 _('hg commit [OPTION]... [FILE]...')),
3084 "copy|cp":
3084 "copy|cp":
3085 (copy,
3085 (copy,
3086 [('A', 'after', None, _('record a copy that has already occurred')),
3086 [('A', 'after', None, _('record a copy that has already occurred')),
3087 ('f', 'force', None,
3087 ('f', 'force', None,
3088 _('forcibly copy over an existing managed file')),
3088 _('forcibly copy over an existing managed file')),
3089 ] + walkopts + dryrunopts,
3089 ] + walkopts + dryrunopts,
3090 _('hg copy [OPTION]... [SOURCE]... DEST')),
3090 _('hg copy [OPTION]... [SOURCE]... DEST')),
3091 "debugancestor": (debugancestor, [],
3091 "debugancestor": (debugancestor, [],
3092 _('hg debugancestor [INDEX] REV1 REV2')),
3092 _('hg debugancestor [INDEX] REV1 REV2')),
3093 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3093 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3094 "debugcomplete":
3094 "debugcomplete":
3095 (debugcomplete,
3095 (debugcomplete,
3096 [('o', 'options', None, _('show the command options'))],
3096 [('o', 'options', None, _('show the command options'))],
3097 _('hg debugcomplete [-o] CMD')),
3097 _('hg debugcomplete [-o] CMD')),
3098 "debugdate":
3098 "debugdate":
3099 (debugdate,
3099 (debugdate,
3100 [('e', 'extended', None, _('try extended date formats'))],
3100 [('e', 'extended', None, _('try extended date formats'))],
3101 _('hg debugdate [-e] DATE [RANGE]')),
3101 _('hg debugdate [-e] DATE [RANGE]')),
3102 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3102 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3103 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3103 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3104 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3104 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3105 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3105 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3106 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3106 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3107 "debugrawcommit|rawcommit":
3107 "debugrawcommit|rawcommit":
3108 (rawcommit,
3108 (rawcommit,
3109 [('p', 'parent', [], _('parent')),
3109 [('p', 'parent', [], _('parent')),
3110 ('F', 'files', '', _('file list'))
3110 ('F', 'files', '', _('file list'))
3111 ] + commitopts + commitopts2,
3111 ] + commitopts + commitopts2,
3112 _('hg debugrawcommit [OPTION]... [FILE]...')),
3112 _('hg debugrawcommit [OPTION]... [FILE]...')),
3113 "debugrebuildstate":
3113 "debugrebuildstate":
3114 (debugrebuildstate,
3114 (debugrebuildstate,
3115 [('r', 'rev', '', _('revision to rebuild to'))],
3115 [('r', 'rev', '', _('revision to rebuild to'))],
3116 _('hg debugrebuildstate [-r REV] [REV]')),
3116 _('hg debugrebuildstate [-r REV] [REV]')),
3117 "debugrename":
3117 "debugrename":
3118 (debugrename,
3118 (debugrename,
3119 [('r', 'rev', '', _('revision to debug'))],
3119 [('r', 'rev', '', _('revision to debug'))],
3120 _('hg debugrename [-r REV] FILE')),
3120 _('hg debugrename [-r REV] FILE')),
3121 "debugsetparents":
3121 "debugsetparents":
3122 (debugsetparents,
3122 (debugsetparents,
3123 [],
3123 [],
3124 _('hg debugsetparents REV1 [REV2]')),
3124 _('hg debugsetparents REV1 [REV2]')),
3125 "debugstate":
3125 "debugstate":
3126 (debugstate,
3126 (debugstate,
3127 [('', 'nodates', None, _('do not display the saved mtime'))],
3127 [('', 'nodates', None, _('do not display the saved mtime'))],
3128 _('hg debugstate [OPTS]')),
3128 _('hg debugstate [OPTS]')),
3129 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3129 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3130 "^diff":
3130 "^diff":
3131 (diff,
3131 (diff,
3132 [('r', 'rev', [], _('revision'))
3132 [('r', 'rev', [], _('revision'))
3133 ] + diffopts + diffopts2 + walkopts,
3133 ] + diffopts + diffopts2 + walkopts,
3134 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3134 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3135 "^export":
3135 "^export":
3136 (export,
3136 (export,
3137 [('o', 'output', '', _('print output to file with formatted name')),
3137 [('o', 'output', '', _('print output to file with formatted name')),
3138 ('', 'switch-parent', None, _('diff against the second parent'))
3138 ('', 'switch-parent', None, _('diff against the second parent'))
3139 ] + diffopts,
3139 ] + diffopts,
3140 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3140 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3141 "grep":
3141 "grep":
3142 (grep,
3142 (grep,
3143 [('0', 'print0', None, _('end fields with NUL')),
3143 [('0', 'print0', None, _('end fields with NUL')),
3144 ('', 'all', None, _('print all revisions that match')),
3144 ('', 'all', None, _('print all revisions that match')),
3145 ('f', 'follow', None,
3145 ('f', 'follow', None,
3146 _('follow changeset history, or file history across copies and renames')),
3146 _('follow changeset history, or file history across copies and renames')),
3147 ('i', 'ignore-case', None, _('ignore case when matching')),
3147 ('i', 'ignore-case', None, _('ignore case when matching')),
3148 ('l', 'files-with-matches', None,
3148 ('l', 'files-with-matches', None,
3149 _('print only filenames and revs that match')),
3149 _('print only filenames and revs that match')),
3150 ('n', 'line-number', None, _('print matching line numbers')),
3150 ('n', 'line-number', None, _('print matching line numbers')),
3151 ('r', 'rev', [], _('search in given revision range')),
3151 ('r', 'rev', [], _('search in given revision range')),
3152 ('u', 'user', None, _('list the author (long with -v)')),
3152 ('u', 'user', None, _('list the author (long with -v)')),
3153 ('d', 'date', None, _('list the date (short with -q)')),
3153 ('d', 'date', None, _('list the date (short with -q)')),
3154 ] + walkopts,
3154 ] + walkopts,
3155 _('hg grep [OPTION]... PATTERN [FILE]...')),
3155 _('hg grep [OPTION]... PATTERN [FILE]...')),
3156 "heads":
3156 "heads":
3157 (heads,
3157 (heads,
3158 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3158 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3159 ] + templateopts,
3159 ] + templateopts,
3160 _('hg heads [-r REV] [REV]...')),
3160 _('hg heads [-r REV] [REV]...')),
3161 "help": (help_, [], _('hg help [TOPIC]')),
3161 "help": (help_, [], _('hg help [TOPIC]')),
3162 "identify|id":
3162 "identify|id":
3163 (identify,
3163 (identify,
3164 [('r', 'rev', '', _('identify the specified rev')),
3164 [('r', 'rev', '', _('identify the specified rev')),
3165 ('n', 'num', None, _('show local revision number')),
3165 ('n', 'num', None, _('show local revision number')),
3166 ('i', 'id', None, _('show global revision id')),
3166 ('i', 'id', None, _('show global revision id')),
3167 ('b', 'branch', None, _('show branch')),
3167 ('b', 'branch', None, _('show branch')),
3168 ('t', 'tags', None, _('show tags'))],
3168 ('t', 'tags', None, _('show tags'))],
3169 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3169 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3170 "import|patch":
3170 "import|patch":
3171 (import_,
3171 (import_,
3172 [('p', 'strip', 1,
3172 [('p', 'strip', 1,
3173 _('directory strip option for patch. This has the same\n'
3173 _('directory strip option for patch. This has the same\n'
3174 'meaning as the corresponding patch option')),
3174 'meaning as the corresponding patch option')),
3175 ('b', 'base', '', _('base path')),
3175 ('b', 'base', '', _('base path')),
3176 ('f', 'force', None,
3176 ('f', 'force', None,
3177 _('skip check for outstanding uncommitted changes')),
3177 _('skip check for outstanding uncommitted changes')),
3178 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3178 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3179 ('', 'exact', None,
3179 ('', 'exact', None,
3180 _('apply patch to the nodes from which it was generated')),
3180 _('apply patch to the nodes from which it was generated')),
3181 ('', 'import-branch', None,
3181 ('', 'import-branch', None,
3182 _('Use any branch information in patch (implied by --exact)'))] +
3182 _('Use any branch information in patch (implied by --exact)'))] +
3183 commitopts + commitopts2,
3183 commitopts + commitopts2,
3184 _('hg import [OPTION]... PATCH...')),
3184 _('hg import [OPTION]... PATCH...')),
3185 "incoming|in":
3185 "incoming|in":
3186 (incoming,
3186 (incoming,
3187 [('f', 'force', None,
3187 [('f', 'force', None,
3188 _('run even when remote repository is unrelated')),
3188 _('run even when remote repository is unrelated')),
3189 ('n', 'newest-first', None, _('show newest record first')),
3189 ('n', 'newest-first', None, _('show newest record first')),
3190 ('', 'bundle', '', _('file to store the bundles into')),
3190 ('', 'bundle', '', _('file to store the bundles into')),
3191 ('r', 'rev', [],
3191 ('r', 'rev', [],
3192 _('a specific revision up to which you would like to pull')),
3192 _('a specific revision up to which you would like to pull')),
3193 ] + logopts + remoteopts,
3193 ] + logopts + remoteopts,
3194 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3194 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3195 ' [--bundle FILENAME] [SOURCE]')),
3195 ' [--bundle FILENAME] [SOURCE]')),
3196 "^init":
3196 "^init":
3197 (init,
3197 (init,
3198 remoteopts,
3198 remoteopts,
3199 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3199 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3200 "locate":
3200 "locate":
3201 (locate,
3201 (locate,
3202 [('r', 'rev', '', _('search the repository as it stood at rev')),
3202 [('r', 'rev', '', _('search the repository as it stood at rev')),
3203 ('0', 'print0', None,
3203 ('0', 'print0', None,
3204 _('end filenames with NUL, for use with xargs')),
3204 _('end filenames with NUL, for use with xargs')),
3205 ('f', 'fullpath', None,
3205 ('f', 'fullpath', None,
3206 _('print complete paths from the filesystem root')),
3206 _('print complete paths from the filesystem root')),
3207 ] + walkopts,
3207 ] + walkopts,
3208 _('hg locate [OPTION]... [PATTERN]...')),
3208 _('hg locate [OPTION]... [PATTERN]...')),
3209 "^log|history":
3209 "^log|history":
3210 (log,
3210 (log,
3211 [('f', 'follow', None,
3211 [('f', 'follow', None,
3212 _('follow changeset history, or file history across copies and renames')),
3212 _('follow changeset history, or file history across copies and renames')),
3213 ('', 'follow-first', None,
3213 ('', 'follow-first', None,
3214 _('only follow the first parent of merge changesets')),
3214 _('only follow the first parent of merge changesets')),
3215 ('d', 'date', '', _('show revs matching date spec')),
3215 ('d', 'date', '', _('show revs matching date spec')),
3216 ('C', 'copies', None, _('show copied files')),
3216 ('C', 'copies', None, _('show copied files')),
3217 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3217 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3218 ('r', 'rev', [], _('show the specified revision or range')),
3218 ('r', 'rev', [], _('show the specified revision or range')),
3219 ('', 'removed', None, _('include revs where files were removed')),
3219 ('', 'removed', None, _('include revs where files were removed')),
3220 ('m', 'only-merges', None, _('show only merges')),
3220 ('m', 'only-merges', None, _('show only merges')),
3221 ('u', 'user', [], _('revs committed by user')),
3221 ('u', 'user', [], _('revs committed by user')),
3222 ('b', 'only-branch', [],
3222 ('b', 'only-branch', [],
3223 _('show only changesets within the given named branch')),
3223 _('show only changesets within the given named branch')),
3224 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3224 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3225 ] + logopts + walkopts,
3225 ] + logopts + walkopts,
3226 _('hg log [OPTION]... [FILE]')),
3226 _('hg log [OPTION]... [FILE]')),
3227 "manifest":
3227 "manifest":
3228 (manifest,
3228 (manifest,
3229 [('r', 'rev', '', _('revision to display'))],
3229 [('r', 'rev', '', _('revision to display'))],
3230 _('hg manifest [-r REV]')),
3230 _('hg manifest [-r REV]')),
3231 "^merge":
3231 "^merge":
3232 (merge,
3232 (merge,
3233 [('f', 'force', None, _('force a merge with outstanding changes')),
3233 [('f', 'force', None, _('force a merge with outstanding changes')),
3234 ('r', 'rev', '', _('revision to merge')),
3234 ('r', 'rev', '', _('revision to merge')),
3235 ],
3235 ],
3236 _('hg merge [-f] [[-r] REV]')),
3236 _('hg merge [-f] [[-r] REV]')),
3237 "outgoing|out":
3237 "outgoing|out":
3238 (outgoing,
3238 (outgoing,
3239 [('f', 'force', None,
3239 [('f', 'force', None,
3240 _('run even when remote repository is unrelated')),
3240 _('run even when remote repository is unrelated')),
3241 ('r', 'rev', [],
3241 ('r', 'rev', [],
3242 _('a specific revision up to which you would like to push')),
3242 _('a specific revision up to which you would like to push')),
3243 ('n', 'newest-first', None, _('show newest record first')),
3243 ('n', 'newest-first', None, _('show newest record first')),
3244 ] + logopts + remoteopts,
3244 ] + logopts + remoteopts,
3245 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3245 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3246 "^parents":
3246 "^parents":
3247 (parents,
3247 (parents,
3248 [('r', 'rev', '', _('show parents from the specified rev')),
3248 [('r', 'rev', '', _('show parents from the specified rev')),
3249 ] + templateopts,
3249 ] + templateopts,
3250 _('hg parents [-r REV] [FILE]')),
3250 _('hg parents [-r REV] [FILE]')),
3251 "paths": (paths, [], _('hg paths [NAME]')),
3251 "paths": (paths, [], _('hg paths [NAME]')),
3252 "^pull":
3252 "^pull":
3253 (pull,
3253 (pull,
3254 [('u', 'update', None,
3254 [('u', 'update', None,
3255 _('update to new tip if changesets were pulled')),
3255 _('update to new tip if changesets were pulled')),
3256 ('f', 'force', None,
3256 ('f', 'force', None,
3257 _('run even when remote repository is unrelated')),
3257 _('run even when remote repository is unrelated')),
3258 ('r', 'rev', [],
3258 ('r', 'rev', [],
3259 _('a specific revision up to which you would like to pull')),
3259 _('a specific revision up to which you would like to pull')),
3260 ] + remoteopts,
3260 ] + remoteopts,
3261 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3261 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3262 "^push":
3262 "^push":
3263 (push,
3263 (push,
3264 [('f', 'force', None, _('force push')),
3264 [('f', 'force', None, _('force push')),
3265 ('r', 'rev', [],
3265 ('r', 'rev', [],
3266 _('a specific revision up to which you would like to push')),
3266 _('a specific revision up to which you would like to push')),
3267 ] + remoteopts,
3267 ] + remoteopts,
3268 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3268 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3269 "recover": (recover, [], _('hg recover')),
3269 "recover": (recover, [], _('hg recover')),
3270 "^remove|rm":
3270 "^remove|rm":
3271 (remove,
3271 (remove,
3272 [('A', 'after', None, _('record delete for missing files')),
3272 [('A', 'after', None, _('record delete for missing files')),
3273 ('f', 'force', None,
3273 ('f', 'force', None,
3274 _('remove (and delete) file even if added or modified')),
3274 _('remove (and delete) file even if added or modified')),
3275 ] + walkopts,
3275 ] + walkopts,
3276 _('hg remove [OPTION]... FILE...')),
3276 _('hg remove [OPTION]... FILE...')),
3277 "rename|mv":
3277 "rename|mv":
3278 (rename,
3278 (rename,
3279 [('A', 'after', None, _('record a rename that has already occurred')),
3279 [('A', 'after', None, _('record a rename that has already occurred')),
3280 ('f', 'force', None,
3280 ('f', 'force', None,
3281 _('forcibly copy over an existing managed file')),
3281 _('forcibly copy over an existing managed file')),
3282 ] + walkopts + dryrunopts,
3282 ] + walkopts + dryrunopts,
3283 _('hg rename [OPTION]... SOURCE... DEST')),
3283 _('hg rename [OPTION]... SOURCE... DEST')),
3284 "resolve":
3284 "resolve":
3285 (resolve,
3285 (resolve,
3286 [('l', 'list', None, _('list state of files needing merge')),
3286 [('l', 'list', None, _('list state of files needing merge')),
3287 ('m', 'mark', None, _('mark files as resolved')),
3287 ('m', 'mark', None, _('mark files as resolved')),
3288 ('u', 'unmark', None, _('unmark files as resolved'))],
3288 ('u', 'unmark', None, _('unmark files as resolved'))],
3289 _('hg resolve [OPTION] [FILES...]')),
3289 _('hg resolve [OPTION] [FILES...]')),
3290 "revert":
3290 "revert":
3291 (revert,
3291 (revert,
3292 [('a', 'all', None, _('revert all changes when no arguments given')),
3292 [('a', 'all', None, _('revert all changes when no arguments given')),
3293 ('d', 'date', '', _('tipmost revision matching date')),
3293 ('d', 'date', '', _('tipmost revision matching date')),
3294 ('r', 'rev', '', _('revision to revert to')),
3294 ('r', 'rev', '', _('revision to revert to')),
3295 ('', 'no-backup', None, _('do not save backup copies of files')),
3295 ('', 'no-backup', None, _('do not save backup copies of files')),
3296 ] + walkopts + dryrunopts,
3296 ] + walkopts + dryrunopts,
3297 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3297 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3298 "rollback": (rollback, [], _('hg rollback')),
3298 "rollback": (rollback, [], _('hg rollback')),
3299 "root": (root, [], _('hg root')),
3299 "root": (root, [], _('hg root')),
3300 "^serve":
3300 "^serve":
3301 (serve,
3301 (serve,
3302 [('A', 'accesslog', '', _('name of access log file to write to')),
3302 [('A', 'accesslog', '', _('name of access log file to write to')),
3303 ('d', 'daemon', None, _('run server in background')),
3303 ('d', 'daemon', None, _('run server in background')),
3304 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3304 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3305 ('E', 'errorlog', '', _('name of error log file to write to')),
3305 ('E', 'errorlog', '', _('name of error log file to write to')),
3306 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3306 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3307 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3307 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3308 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3308 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3309 ('n', 'name', '',
3309 ('n', 'name', '',
3310 _('name to show in web pages (default: working dir)')),
3310 _('name to show in web pages (default: working dir)')),
3311 ('', 'webdir-conf', '', _('name of the webdir config file'
3311 ('', 'webdir-conf', '', _('name of the webdir config file'
3312 ' (serve more than one repo)')),
3312 ' (serve more than one repo)')),
3313 ('', 'pid-file', '', _('name of file to write process ID to')),
3313 ('', 'pid-file', '', _('name of file to write process ID to')),
3314 ('', 'stdio', None, _('for remote clients')),
3314 ('', 'stdio', None, _('for remote clients')),
3315 ('t', 'templates', '', _('web templates to use')),
3315 ('t', 'templates', '', _('web templates to use')),
3316 ('', 'style', '', _('template style to use')),
3316 ('', 'style', '', _('template style to use')),
3317 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3317 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3318 ('', 'certificate', '', _('SSL certificate file'))],
3318 ('', 'certificate', '', _('SSL certificate file'))],
3319 _('hg serve [OPTION]...')),
3319 _('hg serve [OPTION]...')),
3320 "showconfig|debugconfig":
3320 "showconfig|debugconfig":
3321 (showconfig,
3321 (showconfig,
3322 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3322 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3323 _('hg showconfig [-u] [NAME]...')),
3323 _('hg showconfig [-u] [NAME]...')),
3324 "^status|st":
3324 "^status|st":
3325 (status,
3325 (status,
3326 [('A', 'all', None, _('show status of all files')),
3326 [('A', 'all', None, _('show status of all files')),
3327 ('m', 'modified', None, _('show only modified files')),
3327 ('m', 'modified', None, _('show only modified files')),
3328 ('a', 'added', None, _('show only added files')),
3328 ('a', 'added', None, _('show only added files')),
3329 ('r', 'removed', None, _('show only removed files')),
3329 ('r', 'removed', None, _('show only removed files')),
3330 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3330 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3331 ('c', 'clean', None, _('show only files without changes')),
3331 ('c', 'clean', None, _('show only files without changes')),
3332 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3332 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3333 ('i', 'ignored', None, _('show only ignored files')),
3333 ('i', 'ignored', None, _('show only ignored files')),
3334 ('n', 'no-status', None, _('hide status prefix')),
3334 ('n', 'no-status', None, _('hide status prefix')),
3335 ('C', 'copies', None, _('show source of copied files')),
3335 ('C', 'copies', None, _('show source of copied files')),
3336 ('0', 'print0', None,
3336 ('0', 'print0', None,
3337 _('end filenames with NUL, for use with xargs')),
3337 _('end filenames with NUL, for use with xargs')),
3338 ('', 'rev', [], _('show difference from revision')),
3338 ('', 'rev', [], _('show difference from revision')),
3339 ] + walkopts,
3339 ] + walkopts,
3340 _('hg status [OPTION]... [FILE]...')),
3340 _('hg status [OPTION]... [FILE]...')),
3341 "tag":
3341 "tag":
3342 (tag,
3342 (tag,
3343 [('f', 'force', None, _('replace existing tag')),
3343 [('f', 'force', None, _('replace existing tag')),
3344 ('l', 'local', None, _('make the tag local')),
3344 ('l', 'local', None, _('make the tag local')),
3345 ('r', 'rev', '', _('revision to tag')),
3345 ('r', 'rev', '', _('revision to tag')),
3346 ('', 'remove', None, _('remove a tag')),
3346 ('', 'remove', None, _('remove a tag')),
3347 # -l/--local is already there, commitopts cannot be used
3347 # -l/--local is already there, commitopts cannot be used
3348 ('m', 'message', '', _('use <text> as commit message')),
3348 ('m', 'message', '', _('use <text> as commit message')),
3349 ] + commitopts2,
3349 ] + commitopts2,
3350 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3350 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3351 "tags": (tags, [], _('hg tags')),
3351 "tags": (tags, [], _('hg tags')),
3352 "tip":
3352 "tip":
3353 (tip,
3353 (tip,
3354 [('p', 'patch', None, _('show patch')),
3354 [('p', 'patch', None, _('show patch')),
3355 ] + templateopts,
3355 ] + templateopts,
3356 _('hg tip [-p]')),
3356 _('hg tip [-p]')),
3357 "unbundle":
3357 "unbundle":
3358 (unbundle,
3358 (unbundle,
3359 [('u', 'update', None,
3359 [('u', 'update', None,
3360 _('update to new tip if changesets were unbundled'))],
3360 _('update to new tip if changesets were unbundled'))],
3361 _('hg unbundle [-u] FILE...')),
3361 _('hg unbundle [-u] FILE...')),
3362 "^update|up|checkout|co":
3362 "^update|up|checkout|co":
3363 (update,
3363 (update,
3364 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3364 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3365 ('d', 'date', '', _('tipmost revision matching date')),
3365 ('d', 'date', '', _('tipmost revision matching date')),
3366 ('r', 'rev', '', _('revision'))],
3366 ('r', 'rev', '', _('revision'))],
3367 _('hg update [-C] [-d DATE] [[-r] REV]')),
3367 _('hg update [-C] [-d DATE] [[-r] REV]')),
3368 "verify": (verify, [], _('hg verify')),
3368 "verify": (verify, [], _('hg verify')),
3369 "version": (version_, [], _('hg version')),
3369 "version": (version_, [], _('hg version')),
3370 }
3370 }
3371
3371
3372 norepo = ("clone init version help debugcomplete debugdata"
3372 norepo = ("clone init version help debugcomplete debugdata"
3373 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3373 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3374 optionalrepo = ("identify paths serve showconfig debugancestor")
3374 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -1,292 +1,292 b''
1 # store.py - repository store handling for Mercurial
1 # store.py - repository store handling for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import os, stat, osutil, util
9 import os, stat, osutil, util
10
10
11 _sha = util.sha1
11 _sha = util.sha1
12
12
13 def _buildencodefun():
13 def _buildencodefun():
14 e = '_'
14 e = '_'
15 win_reserved = [ord(x) for x in '\\:*?"<>|']
15 win_reserved = [ord(x) for x in '\\:*?"<>|']
16 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
16 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
17 for x in (range(32) + range(126, 256) + win_reserved):
17 for x in (range(32) + range(126, 256) + win_reserved):
18 cmap[chr(x)] = "~%02x" % x
18 cmap[chr(x)] = "~%02x" % x
19 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
19 for x in range(ord("A"), ord("Z")+1) + [ord(e)]:
20 cmap[chr(x)] = e + chr(x).lower()
20 cmap[chr(x)] = e + chr(x).lower()
21 dmap = {}
21 dmap = {}
22 for k, v in cmap.iteritems():
22 for k, v in cmap.iteritems():
23 dmap[v] = k
23 dmap[v] = k
24 def decode(s):
24 def decode(s):
25 i = 0
25 i = 0
26 while i < len(s):
26 while i < len(s):
27 for l in xrange(1, 4):
27 for l in xrange(1, 4):
28 try:
28 try:
29 yield dmap[s[i:i+l]]
29 yield dmap[s[i:i+l]]
30 i += l
30 i += l
31 break
31 break
32 except KeyError:
32 except KeyError:
33 pass
33 pass
34 else:
34 else:
35 raise KeyError
35 raise KeyError
36 return (lambda s: "".join([cmap[c] for c in s]),
36 return (lambda s: "".join([cmap[c] for c in s]),
37 lambda s: "".join(list(decode(s))))
37 lambda s: "".join(list(decode(s))))
38
38
39 encodefilename, decodefilename = _buildencodefun()
39 encodefilename, decodefilename = _buildencodefun()
40
40
41 def _build_lower_encodefun():
41 def _build_lower_encodefun():
42 win_reserved = [ord(x) for x in '\\:*?"<>|']
42 win_reserved = [ord(x) for x in '\\:*?"<>|']
43 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
43 cmap = dict([ (chr(x), chr(x)) for x in xrange(127) ])
44 for x in (range(32) + range(126, 256) + win_reserved):
44 for x in (range(32) + range(126, 256) + win_reserved):
45 cmap[chr(x)] = "~%02x" % x
45 cmap[chr(x)] = "~%02x" % x
46 for x in range(ord("A"), ord("Z")+1):
46 for x in range(ord("A"), ord("Z")+1):
47 cmap[chr(x)] = chr(x).lower()
47 cmap[chr(x)] = chr(x).lower()
48 return lambda s: "".join([cmap[c] for c in s])
48 return lambda s: "".join([cmap[c] for c in s])
49
49
50 lowerencode = _build_lower_encodefun()
50 lowerencode = _build_lower_encodefun()
51
51
52 _windows_reserved_filenames = '''con prn aux nul
52 _windows_reserved_filenames = '''con prn aux nul
53 com1 com2 com3 com4 com5 com6 com7 com8 com9
53 com1 com2 com3 com4 com5 com6 com7 com8 com9
54 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
54 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split()
55 def auxencode(path):
55 def auxencode(path):
56 res = []
56 res = []
57 for n in path.split('/'):
57 for n in path.split('/'):
58 if n:
58 if n:
59 base = n.split('.')[0]
59 base = n.split('.')[0]
60 if base and (base in _windows_reserved_filenames):
60 if base and (base in _windows_reserved_filenames):
61 # encode third letter ('aux' -> 'au~78')
61 # encode third letter ('aux' -> 'au~78')
62 ec = "~%02x" % ord(n[2])
62 ec = "~%02x" % ord(n[2])
63 n = n[0:2] + ec + n[3:]
63 n = n[0:2] + ec + n[3:]
64 res.append(n)
64 res.append(n)
65 return '/'.join(res)
65 return '/'.join(res)
66
66
67 MAX_PATH_LEN_IN_HGSTORE = 120
67 MAX_PATH_LEN_IN_HGSTORE = 120
68 DIR_PREFIX_LEN = 8
68 DIR_PREFIX_LEN = 8
69 _MAX_SHORTENED_DIRS_LEN = 8 * (DIR_PREFIX_LEN + 1) - 4
69 _MAX_SHORTENED_DIRS_LEN = 8 * (DIR_PREFIX_LEN + 1) - 4
70 def hybridencode(path):
70 def hybridencode(path):
71 '''encodes path with a length limit
71 '''encodes path with a length limit
72
72
73 Encodes all paths that begin with 'data/', according to the following.
73 Encodes all paths that begin with 'data/', according to the following.
74
74
75 Default encoding (reversible):
75 Default encoding (reversible):
76
76
77 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
77 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
78 characters are encoded as '~xx', where xx is the two digit hex code
78 characters are encoded as '~xx', where xx is the two digit hex code
79 of the character (see encodefilename).
79 of the character (see encodefilename).
80 Relevant path components consisting of Windows reserved filenames are
80 Relevant path components consisting of Windows reserved filenames are
81 masked by encoding the third character ('aux' -> 'au~78', see auxencode).
81 masked by encoding the third character ('aux' -> 'au~78', see auxencode).
82
82
83 Hashed encoding (not reversible):
83 Hashed encoding (not reversible):
84
84
85 If the default-encoded path is longer than MAX_PATH_LEN_IN_HGSTORE, a
85 If the default-encoded path is longer than MAX_PATH_LEN_IN_HGSTORE, a
86 non-reversible hybrid hashing of the path is done instead.
86 non-reversible hybrid hashing of the path is done instead.
87 This encoding uses up to DIR_PREFIX_LEN characters of all directory
87 This encoding uses up to DIR_PREFIX_LEN characters of all directory
88 levels of the lowerencoded path, but not more levels than can fit into
88 levels of the lowerencoded path, but not more levels than can fit into
89 _MAX_SHORTENED_DIRS_LEN.
89 _MAX_SHORTENED_DIRS_LEN.
90 Then follows the filler followed by the sha digest of the full path.
90 Then follows the filler followed by the sha digest of the full path.
91 The filler is the beginning of the basename of the lowerencoded path
91 The filler is the beginning of the basename of the lowerencoded path
92 (the basename is everything after the last path separator). The filler
92 (the basename is everything after the last path separator). The filler
93 is as long as possible, filling in characters from the basename until
93 is as long as possible, filling in characters from the basename until
94 the encoded path has MAX_PATH_LEN_IN_HGSTORE characters (or all chars
94 the encoded path has MAX_PATH_LEN_IN_HGSTORE characters (or all chars
95 of the basename have been taken).
95 of the basename have been taken).
96 The extension (e.g. '.i' or '.d') is preserved.
96 The extension (e.g. '.i' or '.d') is preserved.
97
97
98 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
98 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
99 encoding was used.
99 encoding was used.
100 '''
100 '''
101 if not path.startswith('data/'):
101 if not path.startswith('data/'):
102 return path
102 return path
103 ndpath = path[len('data/'):]
103 ndpath = path[len('data/'):]
104 res = 'data/' + auxencode(encodefilename(ndpath))
104 res = 'data/' + auxencode(encodefilename(ndpath))
105 if len(res) > MAX_PATH_LEN_IN_HGSTORE:
105 if len(res) > MAX_PATH_LEN_IN_HGSTORE:
106 digest = _sha(path).hexdigest()
106 digest = _sha(path).hexdigest()
107 aep = auxencode(lowerencode(ndpath))
107 aep = auxencode(lowerencode(ndpath))
108 _root, ext = os.path.splitext(aep)
108 _root, ext = os.path.splitext(aep)
109 parts = aep.split('/')
109 parts = aep.split('/')
110 basename = parts[-1]
110 basename = parts[-1]
111 sdirs = []
111 sdirs = []
112 for p in parts[:-1]:
112 for p in parts[:-1]:
113 d = p[:DIR_PREFIX_LEN]
113 d = p[:DIR_PREFIX_LEN]
114 t = '/'.join(sdirs) + '/' + d
114 t = '/'.join(sdirs) + '/' + d
115 if len(t) > _MAX_SHORTENED_DIRS_LEN:
115 if len(t) > _MAX_SHORTENED_DIRS_LEN:
116 break
116 break
117 sdirs.append(d)
117 sdirs.append(d)
118 dirs = '/'.join(sdirs)
118 dirs = '/'.join(sdirs)
119 if len(dirs) > 0:
119 if len(dirs) > 0:
120 dirs += '/'
120 dirs += '/'
121 res = 'dh/' + dirs + digest + ext
121 res = 'dh/' + dirs + digest + ext
122 space_left = MAX_PATH_LEN_IN_HGSTORE - len(res)
122 space_left = MAX_PATH_LEN_IN_HGSTORE - len(res)
123 if space_left > 0:
123 if space_left > 0:
124 filler = basename[:space_left]
124 filler = basename[:space_left]
125 res = 'dh/' + dirs + filler + digest + ext
125 res = 'dh/' + dirs + filler + digest + ext
126 return res
126 return res
127
127
128 def _calcmode(path):
128 def _calcmode(path):
129 try:
129 try:
130 # files in .hg/ will be created using this mode
130 # files in .hg/ will be created using this mode
131 mode = os.stat(path).st_mode
131 mode = os.stat(path).st_mode
132 # avoid some useless chmods
132 # avoid some useless chmods
133 if (0777 & ~util._umask) == (0777 & mode):
133 if (0777 & ~util._umask) == (0777 & mode):
134 mode = None
134 mode = None
135 except OSError:
135 except OSError:
136 mode = None
136 mode = None
137 return mode
137 return mode
138
138
139 _data = 'data 00manifest.d 00manifest.i 00changelog.d 00changelog.i'
139 _data = 'data 00manifest.d 00manifest.i 00changelog.d 00changelog.i'
140
140
141 class basicstore:
141 class basicstore:
142 '''base class for local repository stores'''
142 '''base class for local repository stores'''
143 def __init__(self, path, opener, pathjoiner):
143 def __init__(self, path, opener, pathjoiner):
144 self.pathjoiner = pathjoiner
144 self.pathjoiner = pathjoiner
145 self.path = path
145 self.path = path
146 self.createmode = _calcmode(path)
146 self.createmode = _calcmode(path)
147 self.opener = opener(self.path)
147 self.opener = opener(self.path)
148 self.opener.createmode = self.createmode
148 self.opener.createmode = self.createmode
149
149
150 def join(self, f):
150 def join(self, f):
151 return self.pathjoiner(self.path, f)
151 return self.pathjoiner(self.path, f)
152
152
153 def _walk(self, relpath, recurse):
153 def _walk(self, relpath, recurse):
154 '''yields (unencoded, encoded, size)'''
154 '''yields (unencoded, encoded, size)'''
155 path = self.pathjoiner(self.path, relpath)
155 path = self.pathjoiner(self.path, relpath)
156 striplen = len(self.path) + len(os.sep)
156 striplen = len(self.path) + len(os.sep)
157 prefix = path[striplen:]
157 prefix = path[striplen:]
158 l = []
158 l = []
159 if os.path.isdir(path):
159 if os.path.isdir(path):
160 visit = [path]
160 visit = [path]
161 while visit:
161 while visit:
162 p = visit.pop()
162 p = visit.pop()
163 for f, kind, st in osutil.listdir(p, stat=True):
163 for f, kind, st in osutil.listdir(p, stat=True):
164 fp = self.pathjoiner(p, f)
164 fp = self.pathjoiner(p, f)
165 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
165 if kind == stat.S_IFREG and f[-2:] in ('.d', '.i'):
166 n = util.pconvert(fp[striplen:])
166 n = util.pconvert(fp[striplen:])
167 l.append((n, n, st.st_size))
167 l.append((n, n, st.st_size))
168 elif kind == stat.S_IFDIR and recurse:
168 elif kind == stat.S_IFDIR and recurse:
169 visit.append(fp)
169 visit.append(fp)
170 return util.sort(l)
170 return util.sort(l)
171
171
172 def datafiles(self):
172 def datafiles(self):
173 return self._walk('data', True)
173 return self._walk('data', True)
174
174
175 def walk(self):
175 def walk(self):
176 '''yields (unencoded, encoded, size)'''
176 '''yields (unencoded, encoded, size)'''
177 # yield data files first
177 # yield data files first
178 for x in self.datafiles():
178 for x in self.datafiles():
179 yield x
179 yield x
180 # yield manifest before changelog
180 # yield manifest before changelog
181 meta = self._walk('', False)
181 meta = self._walk('', False)
182 meta.reverse()
182 meta.reverse()
183 for x in meta:
183 for x in meta:
184 yield x
184 yield x
185
185
186 def copylist(self):
186 def copylist(self):
187 return ['requires'] + _data.split()
187 return ['requires'] + _data.split()
188
188
189 class encodedstore(basicstore):
189 class encodedstore(basicstore):
190 def __init__(self, path, opener, pathjoiner):
190 def __init__(self, path, opener, pathjoiner):
191 self.pathjoiner = pathjoiner
191 self.pathjoiner = pathjoiner
192 self.path = self.pathjoiner(path, 'store')
192 self.path = self.pathjoiner(path, 'store')
193 self.createmode = _calcmode(self.path)
193 self.createmode = _calcmode(self.path)
194 op = opener(self.path)
194 op = opener(self.path)
195 op.createmode = self.createmode
195 op.createmode = self.createmode
196 self.opener = lambda f, *args, **kw: op(encodefilename(f), *args, **kw)
196 self.opener = lambda f, *args, **kw: op(encodefilename(f), *args, **kw)
197
197
198 def datafiles(self):
198 def datafiles(self):
199 for a, b, size in self._walk('data', True):
199 for a, b, size in self._walk('data', True):
200 try:
200 try:
201 a = decodefilename(a)
201 a = decodefilename(a)
202 except KeyError:
202 except KeyError:
203 a = None
203 a = None
204 yield a, b, size
204 yield a, b, size
205
205
206 def join(self, f):
206 def join(self, f):
207 return self.pathjoiner(self.path, encodefilename(f))
207 return self.pathjoiner(self.path, encodefilename(f))
208
208
209 def copylist(self):
209 def copylist(self):
210 return (['requires', '00changelog.i'] +
210 return (['requires', '00changelog.i'] +
211 [self.pathjoiner('store', f) for f in _data.split()])
211 [self.pathjoiner('store', f) for f in _data.split()])
212
212
213 def fncache(opener):
213 def fncache(opener):
214 '''yields the entries in the fncache file'''
214 '''yields the entries in the fncache file'''
215 try:
215 try:
216 fp = opener('fncache', mode='rb')
216 fp = opener('fncache', mode='rb')
217 except IOError:
217 except IOError:
218 # skip nonexistent file
218 # skip nonexistent file
219 return
219 return
220 for n, line in enumerate(fp):
220 for n, line in enumerate(fp):
221 if (len(line) < 2) or (line[-1] != '\n'):
221 if (len(line) < 2) or (line[-1] != '\n'):
222 t = _('invalid entry in fncache, line %s') % (n + 1)
222 t = _('invalid entry in fncache, line %s') % (n + 1)
223 raise util.Abort(t)
223 raise util.Abort(t)
224 yield line[:-1]
224 yield line[:-1]
225 fp.close()
225 fp.close()
226
226
227 class fncacheopener(object):
227 class fncacheopener(object):
228 def __init__(self, opener):
228 def __init__(self, opener):
229 self.opener = opener
229 self.opener = opener
230 self.entries = None
230 self.entries = None
231
231
232 def loadfncache(self):
232 def loadfncache(self):
233 self.entries = {}
233 self.entries = {}
234 for f in fncache(self.opener):
234 for f in fncache(self.opener):
235 self.entries[f] = True
235 self.entries[f] = True
236
236
237 def __call__(self, path, mode='r', *args, **kw):
237 def __call__(self, path, mode='r', *args, **kw):
238 if mode not in ('r', 'rb') and path.startswith('data/'):
238 if mode not in ('r', 'rb') and path.startswith('data/'):
239 if self.entries is None:
239 if self.entries is None:
240 self.loadfncache()
240 self.loadfncache()
241 if path not in self.entries:
241 if path not in self.entries:
242 self.opener('fncache', 'ab').write(path + '\n')
242 self.opener('fncache', 'ab').write(path + '\n')
243 # fncache may contain non-existent files after rollback / strip
243 # fncache may contain non-existent files after rollback / strip
244 self.entries[path] = True
244 self.entries[path] = True
245 return self.opener(hybridencode(path), mode, *args, **kw)
245 return self.opener(hybridencode(path), mode, *args, **kw)
246
246
247 class fncachestore(basicstore):
247 class fncachestore(basicstore):
248 def __init__(self, path, opener, pathjoiner):
248 def __init__(self, path, opener, pathjoiner):
249 self.pathjoiner = pathjoiner
249 self.pathjoiner = pathjoiner
250 self.path = self.pathjoiner(path, 'store')
250 self.path = self.pathjoiner(path, 'store')
251 self.createmode = _calcmode(self.path)
251 self.createmode = _calcmode(self.path)
252 self._op = opener(self.path)
252 self._op = opener(self.path)
253 self._op.createmode = self.createmode
253 self._op.createmode = self.createmode
254 self.opener = fncacheopener(self._op)
254 self.opener = fncacheopener(self._op)
255
255
256 def join(self, f):
256 def join(self, f):
257 return self.pathjoiner(self.path, hybridencode(f))
257 return self.pathjoiner(self.path, hybridencode(f))
258
258
259 def datafiles(self):
259 def datafiles(self):
260 rewrite = False
260 rewrite = False
261 existing = []
261 existing = []
262 pjoin = self.pathjoiner
262 pjoin = self.pathjoiner
263 spath = self.path
263 spath = self.path
264 for f in fncache(self._op):
264 for f in fncache(self._op):
265 ef = hybridencode(f)
265 ef = hybridencode(f)
266 try:
266 try:
267 st = os.stat(pjoin(spath, ef))
267 st = os.stat(pjoin(spath, ef))
268 yield f, ef, st.st_size
268 yield f, ef, st.st_size
269 existing.append(f)
269 existing.append(f)
270 except OSError:
270 except OSError:
271 # nonexistent entry
271 # nonexistent entry
272 rewrite = True
272 rewrite = True
273 if rewrite:
273 if rewrite:
274 # rewrite fncache to remove nonexistent entries
274 # rewrite fncache to remove nonexistent entries
275 # (may be caused by rollback / strip)
275 # (may be caused by rollback / strip)
276 fp = self._op('fncache', mode='wb')
276 fp = self._op('fncache', mode='wb')
277 for p in existing:
277 for p in existing:
278 fp.write(p + '\n')
278 fp.write(p + '\n')
279 fp.close()
279 fp.close()
280
280
281 def copylist(self):
281 def copylist(self):
282 d = _data + ' dh fncache'
282 d = _data + ' dh fncache'
283 return (['requires', '00changelog.i'] +
283 return (['requires', '00changelog.i'] +
284 [self.pathjoiner('store', f) for f in d.split()])
284 [self.pathjoiner('store', f) for f in d.split()])
285
285
286 def store(requirements, path, opener, pathjoiner=None):
286 def store(requirements, path, opener, pathjoiner=None):
287 pathjoiner = pathjoiner or os.path.join
287 pathjoiner = pathjoiner or os.path.join
288 if 'store' in requirements:
288 if 'store' in requirements:
289 if 'fncache' in requirements:
289 if 'fncache' in requirements:
290 return fncachestore(path, opener, pathjoiner)
290 return fncachestore(path, opener, pathjoiner)
291 return encodedstore(path, opener, pathjoiner)
291 return encodedstore(path, opener, pathjoiner)
292 return basicstore(path, opener, pathjoiner)
292 return basicstore(path, opener, pathjoiner)
@@ -1,211 +1,211 b''
1 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
1 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
2
2
3 Convert a foreign SCM repository to a Mercurial one.
3 Convert a foreign SCM repository to a Mercurial one.
4
4
5 Accepted source formats [identifiers]:
5 Accepted source formats [identifiers]:
6 - Mercurial [hg]
6 - Mercurial [hg]
7 - CVS [cvs]
7 - CVS [cvs]
8 - Darcs [darcs]
8 - Darcs [darcs]
9 - git [git]
9 - git [git]
10 - Subversion [svn]
10 - Subversion [svn]
11 - Monotone [mtn]
11 - Monotone [mtn]
12 - GNU Arch [gnuarch]
12 - GNU Arch [gnuarch]
13 - Bazaar [bzr]
13 - Bazaar [bzr]
14
14
15 Accepted destination formats [identifiers]:
15 Accepted destination formats [identifiers]:
16 - Mercurial [hg]
16 - Mercurial [hg]
17 - Subversion [svn] (history on branches is not preserved)
17 - Subversion [svn] (history on branches is not preserved)
18
18
19 If no revision is given, all revisions will be converted. Otherwise,
19 If no revision is given, all revisions will be converted. Otherwise,
20 convert will only import up to the named revision (given in a format
20 convert will only import up to the named revision (given in a format
21 understood by the source).
21 understood by the source).
22
22
23 If no destination directory name is specified, it defaults to the
23 If no destination directory name is specified, it defaults to the
24 basename of the source with '-hg' appended. If the destination
24 basename of the source with '-hg' appended. If the destination
25 repository doesn't exist, it will be created.
25 repository doesn't exist, it will be created.
26
26
27 If <REVMAP> isn't given, it will be put in a default location
27 If <REVMAP> isn't given, it will be put in a default location
28 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
28 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
29 file that maps each source commit ID to the destination ID for
29 file that maps each source commit ID to the destination ID for
30 that revision, like so:
30 that revision, like so:
31 <source ID> <destination ID>
31 <source ID> <destination ID>
32
32
33 If the file doesn't exist, it's automatically created. It's updated
33 If the file doesn't exist, it's automatically created. It's updated
34 on each commit copied, so convert-repo can be interrupted and can
34 on each commit copied, so convert-repo can be interrupted and can
35 be run repeatedly to copy new commits.
35 be run repeatedly to copy new commits.
36
36
37 The [username mapping] file is a simple text file that maps each source
37 The [username mapping] file is a simple text file that maps each source
38 commit author to a destination commit author. It is handy for source SCMs
38 commit author to a destination commit author. It is handy for source SCMs
39 that use unix logins to identify authors (eg: CVS). One line per author
39 that use unix logins to identify authors (eg: CVS). One line per author
40 mapping and the line format is:
40 mapping and the line format is:
41 srcauthor=whatever string you want
41 srcauthor=whatever string you want
42
42
43 The filemap is a file that allows filtering and remapping of files
43 The filemap is a file that allows filtering and remapping of files
44 and directories. Comment lines start with '#'. Each line can
44 and directories. Comment lines start with '#'. Each line can
45 contain one of the following directives:
45 contain one of the following directives:
46
46
47 include path/to/file
47 include path/to/file
48
48
49 exclude path/to/file
49 exclude path/to/file
50
50
51 rename from/file to/file
51 rename from/file to/file
52
52
53 The 'include' directive causes a file, or all files under a
53 The 'include' directive causes a file, or all files under a
54 directory, to be included in the destination repository, and the
54 directory, to be included in the destination repository, and the
55 exclusion of all other files and dirs not explicitely included.
55 exclusion of all other files and dirs not explicitely included.
56 The 'exclude' directive causes files or directories to be omitted.
56 The 'exclude' directive causes files or directories to be omitted.
57 The 'rename' directive renames a file or directory. To rename from a
57 The 'rename' directive renames a file or directory. To rename from a
58 subdirectory into the root of the repository, use '.' as the path to
58 subdirectory into the root of the repository, use '.' as the path to
59 rename to.
59 rename to.
60
60
61 The splicemap is a file that allows insertion of synthetic
61 The splicemap is a file that allows insertion of synthetic
62 history, letting you specify the parents of a revision. This is
62 history, letting you specify the parents of a revision. This is
63 useful if you want to e.g. give a Subversion merge two parents, or
63 useful if you want to e.g. give a Subversion merge two parents, or
64 graft two disconnected series of history together. Each entry
64 graft two disconnected series of history together. Each entry
65 contains a key, followed by a space, followed by one or two
65 contains a key, followed by a space, followed by one or two
66 values, separated by spaces. The key is the revision ID in the
66 values, separated by spaces. The key is the revision ID in the
67 source revision control system whose parents should be modified
67 source revision control system whose parents should be modified
68 (same format as a key in .hg/shamap). The values are the revision
68 (same format as a key in .hg/shamap). The values are the revision
69 IDs (in either the source or destination revision control system)
69 IDs (in either the source or destination revision control system)
70 that should be used as the new parents for that node.
70 that should be used as the new parents for that node.
71
71
72 Mercurial Source
72 Mercurial Source
73 -----------------
73 -----------------
74
74
75 --config convert.hg.ignoreerrors=False (boolean)
75 --config convert.hg.ignoreerrors=False (boolean)
76 ignore integrity errors when reading. Use it to fix Mercurial
76 ignore integrity errors when reading. Use it to fix Mercurial
77 repositories with missing revlogs, by converting from and to
77 repositories with missing revlogs, by converting from and to
78 Mercurial.
78 Mercurial.
79 --config convert.hg.saverev=True (boolean)
79 --config convert.hg.saverev=True (boolean)
80 allow target to preserve source revision ID
80 allow target to preserve source revision ID
81 --config convert.hg.startrev=0 (hg revision identifier)
81 --config convert.hg.startrev=0 (hg revision identifier)
82 convert start revision and its descendants
82 convert start revision and its descendants
83
83
84 CVS Source
84 CVS Source
85 ----------
85 ----------
86
86
87 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
87 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
88 to indicate the starting point of what will be converted. Direct
88 to indicate the starting point of what will be converted. Direct
89 access to the repository files is not needed, unless of course
89 access to the repository files is not needed, unless of course
90 the repository is :local:. The conversion uses the top level
90 the repository is :local:. The conversion uses the top level
91 directory in the sandbox to find the CVS repository, and then uses
91 directory in the sandbox to find the CVS repository, and then uses
92 CVS rlog commands to find files to convert. This means that unless
92 CVS rlog commands to find files to convert. This means that unless
93 a filemap is given, all files under the starting directory will be
93 a filemap is given, all files under the starting directory will be
94 converted, and that any directory reorganisation in the CVS
94 converted, and that any directory reorganisation in the CVS
95 sandbox is ignored.
95 sandbox is ignored.
96
96
97 Because CVS does not have changesets, it is necessary to collect
97 Because CVS does not have changesets, it is necessary to collect
98 individual commits to CVS and merge them into changesets. CVS
98 individual commits to CVS and merge them into changesets. CVS
99 source uses its internal changeset merging code by default but can
99 source uses its internal changeset merging code by default but can
100 be configured to call the external 'cvsps' program by setting:
100 be configured to call the external 'cvsps' program by setting:
101 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
101 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
102 This is a legacy option and may be removed in future.
102 This is a legacy option and may be removed in future.
103
103
104 The options shown are the defaults.
104 The options shown are the defaults.
105
105
106 Internal cvsps is selected by setting
106 Internal cvsps is selected by setting
107 --config convert.cvsps=builtin
107 --config convert.cvsps=builtin
108 and has a few more configurable options:
108 and has a few more configurable options:
109 --config convert.cvsps.fuzz=60 (integer)
109 --config convert.cvsps.fuzz=60 (integer)
110 Specify the maximum time (in seconds) that is allowed between
110 Specify the maximum time (in seconds) that is allowed between
111 commits with identical user and log message in a single
111 commits with identical user and log message in a single
112 changeset. When very large files were checked in as part
112 changeset. When very large files were checked in as part
113 of a changeset then the default may not be long enough.
113 of a changeset then the default may not be long enough.
114 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
114 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
115 Specify a regular expression to which commit log messages are
115 Specify a regular expression to which commit log messages are
116 matched. If a match occurs, then the conversion process will
116 matched. If a match occurs, then the conversion process will
117 insert a dummy revision merging the branch on which this log
117 insert a dummy revision merging the branch on which this log
118 message occurs to the branch indicated in the regex.
118 message occurs to the branch indicated in the regex.
119 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
119 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
120 Specify a regular expression to which commit log messages are
120 Specify a regular expression to which commit log messages are
121 matched. If a match occurs, then the conversion process will
121 matched. If a match occurs, then the conversion process will
122 add the most recent revision on the branch indicated in the
122 add the most recent revision on the branch indicated in the
123 regex as the second parent of the changeset.
123 regex as the second parent of the changeset.
124
124
125 The hgext/convert/cvsps wrapper script allows the builtin changeset
125 The hgext/convert/cvsps wrapper script allows the builtin changeset
126 merging code to be run without doing a conversion. Its parameters and
126 merging code to be run without doing a conversion. Its parameters and
127 output are similar to that of cvsps 2.1.
127 output are similar to that of cvsps 2.1.
128
128
129 Subversion Source
129 Subversion Source
130 -----------------
130 -----------------
131
131
132 Subversion source detects classical trunk/branches/tags layouts.
132 Subversion source detects classical trunk/branches/tags layouts.
133 By default, the supplied "svn://repo/path/" source URL is
133 By default, the supplied "svn://repo/path/" source URL is
134 converted as a single branch. If "svn://repo/path/trunk" exists
134 converted as a single branch. If "svn://repo/path/trunk" exists
135 it replaces the default branch. If "svn://repo/path/branches"
135 it replaces the default branch. If "svn://repo/path/branches"
136 exists, its subdirectories are listed as possible branches. If
136 exists, its subdirectories are listed as possible branches. If
137 "svn://repo/path/tags" exists, it is looked for tags referencing
137 "svn://repo/path/tags" exists, it is looked for tags referencing
138 converted branches. Default "trunk", "branches" and "tags" values
138 converted branches. Default "trunk", "branches" and "tags" values
139 can be overriden with following options. Set them to paths
139 can be overriden with following options. Set them to paths
140 relative to the source URL, or leave them blank to disable
140 relative to the source URL, or leave them blank to disable
141 autodetection.
141 autodetection.
142
142
143 --config convert.svn.branches=branches (directory name)
143 --config convert.svn.branches=branches (directory name)
144 specify the directory containing branches
144 specify the directory containing branches
145 --config convert.svn.tags=tags (directory name)
145 --config convert.svn.tags=tags (directory name)
146 specify the directory containing tags
146 specify the directory containing tags
147 --config convert.svn.trunk=trunk (directory name)
147 --config convert.svn.trunk=trunk (directory name)
148 specify the name of the trunk branch
148 specify the name of the trunk branch
149
149
150 Source history can be retrieved starting at a specific revision,
150 Source history can be retrieved starting at a specific revision,
151 instead of being integrally converted. Only single branch
151 instead of being integrally converted. Only single branch
152 conversions are supported.
152 conversions are supported.
153
153
154 --config convert.svn.startrev=0 (svn revision number)
154 --config convert.svn.startrev=0 (svn revision number)
155 specify start Subversion revision.
155 specify start Subversion revision.
156
156
157 Mercurial Destination
157 Mercurial Destination
158 ---------------------
158 ---------------------
159
159
160 --config convert.hg.clonebranches=False (boolean)
160 --config convert.hg.clonebranches=False (boolean)
161 dispatch source branches in separate clones.
161 dispatch source branches in separate clones.
162 --config convert.hg.tagsbranch=default (branch name)
162 --config convert.hg.tagsbranch=default (branch name)
163 tag revisions branch name
163 tag revisions branch name
164 --config convert.hg.usebranchnames=True (boolean)
164 --config convert.hg.usebranchnames=True (boolean)
165 preserve branch names
165 preserve branch names
166
166
167 options:
167 options:
168
168
169 -A --authors username mapping filename
169 -A --authors username mapping filename
170 -d --dest-type destination repository type
170 -d --dest-type destination repository type
171 --filemap remap file names using contents of file
171 --filemap remap file names using contents of file
172 -r --rev import up to target revision REV
172 -r --rev import up to target revision REV
173 -s --source-type source repository type
173 -s --source-type source repository type
174 --splicemap splice synthesized history into place
174 --splicemap splice synthesized history into place
175 --datesort try to sort changesets by date
175 --datesort try to sort changesets by date
176
176
177 use "hg -v help convert" to show global options
177 use "hg -v help convert" to show global options
178 adding a
178 adding a
179 assuming destination a-hg
179 assuming destination a-hg
180 initializing destination a-hg repository
180 initializing destination a-hg repository
181 scanning source...
181 scanning source...
182 sorting...
182 sorting...
183 converting...
183 converting...
184 4 a
184 4 a
185 3 b
185 3 b
186 2 c
186 2 c
187 1 d
187 1 d
188 0 e
188 0 e
189 pulling from ../a
189 pulling from ../a
190 searching for changes
190 searching for changes
191 no changes found
191 no changes found
192 % should fail
192 % should fail
193 initializing destination bogusfile repository
193 initializing destination bogusfile repository
194 abort: cannot create new bundle repository
194 abort: cannot create new bundle repository
195 % should fail
195 % should fail
196 abort: Permission denied: bogusdir
196 abort: Permission denied: bogusdir
197 % should succeed
197 % should succeed
198 initializing destination bogusdir repository
198 initializing destination bogusdir repository
199 scanning source...
199 scanning source...
200 sorting...
200 sorting...
201 converting...
201 converting...
202 4 a
202 4 a
203 3 b
203 3 b
204 2 c
204 2 c
205 1 d
205 1 d
206 0 e
206 0 e
207 % test pre and post conversion actions
207 % test pre and post conversion actions
208 run hg source pre-conversion action
208 run hg source pre-conversion action
209 run hg sink pre-conversion action
209 run hg sink pre-conversion action
210 run hg sink post-conversion action
210 run hg sink post-conversion action
211 run hg source post-conversion action
211 run hg source post-conversion action
General Comments 0
You need to be logged in to leave comments. Login now