##// END OF EJS Templates
lowercase help output...
Martin Geisler -
r7598:26adfacc default
parent child Browse files
Show More
@@ -1,161 +1,161 b''
1 # churn.py - create a graph of revisions count grouped by template
1 # churn.py - create a graph of revisions count grouped by template
2 #
2 #
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
3 # Copyright 2006 Josef "Jeff" Sipek <jeffpc@josefsipek.net>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
4 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8 '''command to show certain statistics about revision history'''
8 '''command to show certain statistics about revision history'''
9
9
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial import patch, cmdutil, util, templater
11 from mercurial import patch, cmdutil, util, templater
12 import os, sys
12 import os, sys
13 import time, datetime
13 import time, datetime
14
14
15 def maketemplater(ui, repo, tmpl):
15 def maketemplater(ui, repo, tmpl):
16 tmpl = templater.parsestring(tmpl, quoted=False)
16 tmpl = templater.parsestring(tmpl, quoted=False)
17 try:
17 try:
18 t = cmdutil.changeset_templater(ui, repo, False, None, False)
18 t = cmdutil.changeset_templater(ui, repo, False, None, False)
19 except SyntaxError, inst:
19 except SyntaxError, inst:
20 raise util.Abort(inst.args[0])
20 raise util.Abort(inst.args[0])
21 t.use_template(tmpl)
21 t.use_template(tmpl)
22 return t
22 return t
23
23
24 def changedlines(ui, repo, ctx1, ctx2):
24 def changedlines(ui, repo, ctx1, ctx2):
25 lines = 0
25 lines = 0
26 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node()))
26 diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node()))
27 for l in diff.split('\n'):
27 for l in diff.split('\n'):
28 if (l.startswith("+") and not l.startswith("+++ ") or
28 if (l.startswith("+") and not l.startswith("+++ ") or
29 l.startswith("-") and not l.startswith("--- ")):
29 l.startswith("-") and not l.startswith("--- ")):
30 lines += 1
30 lines += 1
31 return lines
31 return lines
32
32
33 def countrate(ui, repo, amap, *pats, **opts):
33 def countrate(ui, repo, amap, *pats, **opts):
34 """Calculate stats"""
34 """Calculate stats"""
35 if opts.get('dateformat'):
35 if opts.get('dateformat'):
36 def getkey(ctx):
36 def getkey(ctx):
37 t, tz = ctx.date()
37 t, tz = ctx.date()
38 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
38 date = datetime.datetime(*time.gmtime(float(t) - tz)[:6])
39 return date.strftime(opts['dateformat'])
39 return date.strftime(opts['dateformat'])
40 else:
40 else:
41 tmpl = opts.get('template', '{author|email}')
41 tmpl = opts.get('template', '{author|email}')
42 tmpl = maketemplater(ui, repo, tmpl)
42 tmpl = maketemplater(ui, repo, tmpl)
43 def getkey(ctx):
43 def getkey(ctx):
44 ui.pushbuffer()
44 ui.pushbuffer()
45 tmpl.show(ctx)
45 tmpl.show(ctx)
46 return ui.popbuffer()
46 return ui.popbuffer()
47
47
48 count = pct = 0
48 count = pct = 0
49 rate = {}
49 rate = {}
50 df = False
50 df = False
51 if opts.get('date'):
51 if opts.get('date'):
52 df = util.matchdate(opts['date'])
52 df = util.matchdate(opts['date'])
53
53
54 get = util.cachefunc(lambda r: repo[r].changeset())
54 get = util.cachefunc(lambda r: repo[r].changeset())
55 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
55 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
56 for st, rev, fns in changeiter:
56 for st, rev, fns in changeiter:
57 if not st == 'add':
57 if not st == 'add':
58 continue
58 continue
59 if df and not df(get(rev)[2][0]): # doesn't match date format
59 if df and not df(get(rev)[2][0]): # doesn't match date format
60 continue
60 continue
61
61
62 ctx = repo[rev]
62 ctx = repo[rev]
63 key = getkey(ctx)
63 key = getkey(ctx)
64 key = amap.get(key, key) # alias remap
64 key = amap.get(key, key) # alias remap
65 if opts.get('changesets'):
65 if opts.get('changesets'):
66 rate[key] = rate.get(key, 0) + 1
66 rate[key] = rate.get(key, 0) + 1
67 else:
67 else:
68 parents = ctx.parents()
68 parents = ctx.parents()
69 if len(parents) > 1:
69 if len(parents) > 1:
70 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
70 ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,))
71 continue
71 continue
72
72
73 ctx1 = parents[0]
73 ctx1 = parents[0]
74 lines = changedlines(ui, repo, ctx1, ctx)
74 lines = changedlines(ui, repo, ctx1, ctx)
75 rate[key] = rate.get(key, 0) + lines
75 rate[key] = rate.get(key, 0) + lines
76
76
77 if opts.get('progress'):
77 if opts.get('progress'):
78 count += 1
78 count += 1
79 newpct = int(100.0 * count / max(len(repo), 1))
79 newpct = int(100.0 * count / max(len(repo), 1))
80 if pct < newpct:
80 if pct < newpct:
81 pct = newpct
81 pct = newpct
82 ui.write(_("\rGenerating stats: %d%%") % pct)
82 ui.write(_("\rGenerating stats: %d%%") % pct)
83 sys.stdout.flush()
83 sys.stdout.flush()
84
84
85 if opts.get('progress'):
85 if opts.get('progress'):
86 ui.write("\r")
86 ui.write("\r")
87 sys.stdout.flush()
87 sys.stdout.flush()
88
88
89 return rate
89 return rate
90
90
91
91
92 def churn(ui, repo, *pats, **opts):
92 def churn(ui, repo, *pats, **opts):
93 '''Graph count of revisions grouped by template
93 '''graph count of revisions grouped by template
94
94
95 Will graph count of changed lines or revisions grouped by template or
95 Will graph count of changed lines or revisions grouped by template or
96 alternatively by date, if dateformat is used. In this case it will override
96 alternatively by date, if dateformat is used. In this case it will override
97 template.
97 template.
98
98
99 By default statistics are counted for number of changed lines.
99 By default statistics are counted for number of changed lines.
100
100
101 Examples:
101 Examples:
102
102
103 # display count of changed lines for every committer
103 # display count of changed lines for every committer
104 hg churn -t '{author|email}'
104 hg churn -t '{author|email}'
105
105
106 # display daily activity graph
106 # display daily activity graph
107 hg churn -f '%H' -s -c
107 hg churn -f '%H' -s -c
108
108
109 # display activity of developers by month
109 # display activity of developers by month
110 hg churn -f '%Y-%m' -s -c
110 hg churn -f '%Y-%m' -s -c
111
111
112 # display count of lines changed in every year
112 # display count of lines changed in every year
113 hg churn -f '%Y' -s
113 hg churn -f '%Y' -s
114
114
115 The map file format used to specify aliases is fairly simple:
115 The map file format used to specify aliases is fairly simple:
116
116
117 <alias email> <actual email>'''
117 <alias email> <actual email>'''
118 def pad(s, l):
118 def pad(s, l):
119 return (s + " " * l)[:l]
119 return (s + " " * l)[:l]
120
120
121 amap = {}
121 amap = {}
122 aliases = opts.get('aliases')
122 aliases = opts.get('aliases')
123 if aliases:
123 if aliases:
124 for l in open(aliases, "r"):
124 for l in open(aliases, "r"):
125 l = l.strip()
125 l = l.strip()
126 alias, actual = l.split()
126 alias, actual = l.split()
127 amap[alias] = actual
127 amap[alias] = actual
128
128
129 rate = countrate(ui, repo, amap, *pats, **opts).items()
129 rate = countrate(ui, repo, amap, *pats, **opts).items()
130 if not rate:
130 if not rate:
131 return
131 return
132
132
133 sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None)
133 sortfn = ((not opts.get('sort')) and (lambda a, b: cmp(b[1], a[1])) or None)
134 rate.sort(sortfn)
134 rate.sort(sortfn)
135
135
136 maxcount = float(max([v for k, v in rate]))
136 maxcount = float(max([v for k, v in rate]))
137 maxname = max([len(k) for k, v in rate])
137 maxname = max([len(k) for k, v in rate])
138
138
139 ttywidth = util.termwidth()
139 ttywidth = util.termwidth()
140 ui.debug(_("assuming %i character terminal\n") % ttywidth)
140 ui.debug(_("assuming %i character terminal\n") % ttywidth)
141 width = ttywidth - maxname - 2 - 6 - 2 - 2
141 width = ttywidth - maxname - 2 - 6 - 2 - 2
142
142
143 for date, count in rate:
143 for date, count in rate:
144 print "%s %6d %s" % (pad(date, maxname), count,
144 print "%s %6d %s" % (pad(date, maxname), count,
145 "*" * int(count * width / maxcount))
145 "*" * int(count * width / maxcount))
146
146
147
147
148 cmdtable = {
148 cmdtable = {
149 "churn":
149 "churn":
150 (churn,
150 (churn,
151 [('r', 'rev', [], _('count rate for the specified revision or range')),
151 [('r', 'rev', [], _('count rate for the specified revision or range')),
152 ('d', 'date', '', _('count rate for revs matching date spec')),
152 ('d', 'date', '', _('count rate for revs matching date spec')),
153 ('t', 'template', '{author|email}', _('template to group changesets')),
153 ('t', 'template', '{author|email}', _('template to group changesets')),
154 ('f', 'dateformat', '',
154 ('f', 'dateformat', '',
155 _('strftime-compatible format for grouping by date')),
155 _('strftime-compatible format for grouping by date')),
156 ('c', 'changesets', False, _('count rate by number of changesets')),
156 ('c', 'changesets', False, _('count rate by number of changesets')),
157 ('s', 'sort', False, _('sort by key (default: sort by count)')),
157 ('s', 'sort', False, _('sort by key (default: sort by count)')),
158 ('', 'aliases', '', _('file with email aliases')),
158 ('', 'aliases', '', _('file with email aliases')),
159 ('', 'progress', None, _('show progress'))],
159 ('', 'progress', None, _('show progress'))],
160 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
160 _("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")),
161 }
161 }
@@ -1,233 +1,233 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 import cvsps
10 import cvsps
11 from mercurial import commands
11 from mercurial import commands
12 from mercurial.i18n import _
12 from mercurial.i18n import _
13
13
14 # Commands definition was moved elsewhere to ease demandload job.
14 # Commands definition was moved elsewhere to ease demandload job.
15
15
16 def convert(ui, src, dest=None, revmapfile=None, **opts):
16 def convert(ui, src, dest=None, revmapfile=None, **opts):
17 """Convert a foreign SCM repository to a Mercurial one.
17 """convert a foreign SCM repository to a Mercurial one.
18
18
19 Accepted source formats [identifiers]:
19 Accepted source formats [identifiers]:
20 - Mercurial [hg]
20 - Mercurial [hg]
21 - CVS [cvs]
21 - CVS [cvs]
22 - Darcs [darcs]
22 - Darcs [darcs]
23 - git [git]
23 - git [git]
24 - Subversion [svn]
24 - Subversion [svn]
25 - Monotone [mtn]
25 - Monotone [mtn]
26 - GNU Arch [gnuarch]
26 - GNU Arch [gnuarch]
27 - Bazaar [bzr]
27 - Bazaar [bzr]
28
28
29 Accepted destination formats [identifiers]:
29 Accepted destination formats [identifiers]:
30 - Mercurial [hg]
30 - Mercurial [hg]
31 - Subversion [svn] (history on branches is not preserved)
31 - Subversion [svn] (history on branches is not preserved)
32
32
33 If no revision is given, all revisions will be converted. Otherwise,
33 If no revision is given, all revisions will be converted. Otherwise,
34 convert will only import up to the named revision (given in a format
34 convert will only import up to the named revision (given in a format
35 understood by the source).
35 understood by the source).
36
36
37 If no destination directory name is specified, it defaults to the
37 If no destination directory name is specified, it defaults to the
38 basename of the source with '-hg' appended. If the destination
38 basename of the source with '-hg' appended. If the destination
39 repository doesn't exist, it will be created.
39 repository doesn't exist, it will be created.
40
40
41 If <REVMAP> isn't given, it will be put in a default location
41 If <REVMAP> isn't given, it will be put in a default location
42 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
42 (<dest>/.hg/shamap by default). The <REVMAP> is a simple text
43 file that maps each source commit ID to the destination ID for
43 file that maps each source commit ID to the destination ID for
44 that revision, like so:
44 that revision, like so:
45 <source ID> <destination ID>
45 <source ID> <destination ID>
46
46
47 If the file doesn't exist, it's automatically created. It's updated
47 If the file doesn't exist, it's automatically created. It's updated
48 on each commit copied, so convert-repo can be interrupted and can
48 on each commit copied, so convert-repo can be interrupted and can
49 be run repeatedly to copy new commits.
49 be run repeatedly to copy new commits.
50
50
51 The [username mapping] file is a simple text file that maps each source
51 The [username mapping] file is a simple text file that maps each source
52 commit author to a destination commit author. It is handy for source SCMs
52 commit author to a destination commit author. It is handy for source SCMs
53 that use unix logins to identify authors (eg: CVS). One line per author
53 that use unix logins to identify authors (eg: CVS). One line per author
54 mapping and the line format is:
54 mapping and the line format is:
55 srcauthor=whatever string you want
55 srcauthor=whatever string you want
56
56
57 The filemap is a file that allows filtering and remapping of files
57 The filemap is a file that allows filtering and remapping of files
58 and directories. Comment lines start with '#'. Each line can
58 and directories. Comment lines start with '#'. Each line can
59 contain one of the following directives:
59 contain one of the following directives:
60
60
61 include path/to/file
61 include path/to/file
62
62
63 exclude path/to/file
63 exclude path/to/file
64
64
65 rename from/file to/file
65 rename from/file to/file
66
66
67 The 'include' directive causes a file, or all files under a
67 The 'include' directive causes a file, or all files under a
68 directory, to be included in the destination repository, and the
68 directory, to be included in the destination repository, and the
69 exclusion of all other files and dirs not explicitely included.
69 exclusion of all other files and dirs not explicitely included.
70 The 'exclude' directive causes files or directories to be omitted.
70 The 'exclude' directive causes files or directories to be omitted.
71 The 'rename' directive renames a file or directory. To rename from a
71 The 'rename' directive renames a file or directory. To rename from a
72 subdirectory into the root of the repository, use '.' as the path to
72 subdirectory into the root of the repository, use '.' as the path to
73 rename to.
73 rename to.
74
74
75 The splicemap is a file that allows insertion of synthetic
75 The splicemap is a file that allows insertion of synthetic
76 history, letting you specify the parents of a revision. This is
76 history, letting you specify the parents of a revision. This is
77 useful if you want to e.g. give a Subversion merge two parents, or
77 useful if you want to e.g. give a Subversion merge two parents, or
78 graft two disconnected series of history together. Each entry
78 graft two disconnected series of history together. Each entry
79 contains a key, followed by a space, followed by one or two
79 contains a key, followed by a space, followed by one or two
80 values, separated by spaces. The key is the revision ID in the
80 values, separated by spaces. The key is the revision ID in the
81 source revision control system whose parents should be modified
81 source revision control system whose parents should be modified
82 (same format as a key in .hg/shamap). The values are the revision
82 (same format as a key in .hg/shamap). The values are the revision
83 IDs (in either the source or destination revision control system)
83 IDs (in either the source or destination revision control system)
84 that should be used as the new parents for that node.
84 that should be used as the new parents for that node.
85
85
86 Mercurial Source
86 Mercurial Source
87 -----------------
87 -----------------
88
88
89 --config convert.hg.ignoreerrors=False (boolean)
89 --config convert.hg.ignoreerrors=False (boolean)
90 ignore integrity errors when reading. Use it to fix Mercurial
90 ignore integrity errors when reading. Use it to fix Mercurial
91 repositories with missing revlogs, by converting from and to
91 repositories with missing revlogs, by converting from and to
92 Mercurial.
92 Mercurial.
93 --config convert.hg.saverev=True (boolean)
93 --config convert.hg.saverev=True (boolean)
94 allow target to preserve source revision ID
94 allow target to preserve source revision ID
95 --config convert.hg.startrev=0 (hg revision identifier)
95 --config convert.hg.startrev=0 (hg revision identifier)
96 convert start revision and its descendants
96 convert start revision and its descendants
97
97
98 CVS Source
98 CVS Source
99 ----------
99 ----------
100
100
101 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
101 CVS source will use a sandbox (i.e. a checked-out copy) from CVS
102 to indicate the starting point of what will be converted. Direct
102 to indicate the starting point of what will be converted. Direct
103 access to the repository files is not needed, unless of course
103 access to the repository files is not needed, unless of course
104 the repository is :local:. The conversion uses the top level
104 the repository is :local:. The conversion uses the top level
105 directory in the sandbox to find the CVS repository, and then uses
105 directory in the sandbox to find the CVS repository, and then uses
106 CVS rlog commands to find files to convert. This means that unless
106 CVS rlog commands to find files to convert. This means that unless
107 a filemap is given, all files under the starting directory will be
107 a filemap is given, all files under the starting directory will be
108 converted, and that any directory reorganisation in the CVS
108 converted, and that any directory reorganisation in the CVS
109 sandbox is ignored.
109 sandbox is ignored.
110
110
111 Because CVS does not have changesets, it is necessary to collect
111 Because CVS does not have changesets, it is necessary to collect
112 individual commits to CVS and merge them into changesets. CVS
112 individual commits to CVS and merge them into changesets. CVS
113 source uses its internal changeset merging code by default but can
113 source uses its internal changeset merging code by default but can
114 be configured to call the external 'cvsps' program by setting:
114 be configured to call the external 'cvsps' program by setting:
115 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
115 --config convert.cvsps='cvsps -A -u --cvs-direct -q'
116 This is a legacy option and may be removed in future.
116 This is a legacy option and may be removed in future.
117
117
118 The options shown are the defaults.
118 The options shown are the defaults.
119
119
120 Internal cvsps is selected by setting
120 Internal cvsps is selected by setting
121 --config convert.cvsps=builtin
121 --config convert.cvsps=builtin
122 and has a few more configurable options:
122 and has a few more configurable options:
123 --config convert.cvsps.fuzz=60 (integer)
123 --config convert.cvsps.fuzz=60 (integer)
124 Specify the maximum time (in seconds) that is allowed between
124 Specify the maximum time (in seconds) that is allowed between
125 commits with identical user and log message in a single
125 commits with identical user and log message in a single
126 changeset. When very large files were checked in as part
126 changeset. When very large files were checked in as part
127 of a changeset then the default may not be long enough.
127 of a changeset then the default may not be long enough.
128 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
128 --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
129 Specify a regular expression to which commit log messages are
129 Specify a regular expression to which commit log messages are
130 matched. If a match occurs, then the conversion process will
130 matched. If a match occurs, then the conversion process will
131 insert a dummy revision merging the branch on which this log
131 insert a dummy revision merging the branch on which this log
132 message occurs to the branch indicated in the regex.
132 message occurs to the branch indicated in the regex.
133 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
133 --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
134 Specify a regular expression to which commit log messages are
134 Specify a regular expression to which commit log messages are
135 matched. If a match occurs, then the conversion process will
135 matched. If a match occurs, then the conversion process will
136 add the most recent revision on the branch indicated in the
136 add the most recent revision on the branch indicated in the
137 regex as the second parent of the changeset.
137 regex as the second parent of the changeset.
138
138
139 The hgext/convert/cvsps wrapper script allows the builtin changeset
139 The hgext/convert/cvsps wrapper script allows the builtin changeset
140 merging code to be run without doing a conversion. Its parameters and
140 merging code to be run without doing a conversion. Its parameters and
141 output are similar to that of cvsps 2.1.
141 output are similar to that of cvsps 2.1.
142
142
143 Subversion Source
143 Subversion Source
144 -----------------
144 -----------------
145
145
146 Subversion source detects classical trunk/branches/tags layouts.
146 Subversion source detects classical trunk/branches/tags layouts.
147 By default, the supplied "svn://repo/path/" source URL is
147 By default, the supplied "svn://repo/path/" source URL is
148 converted as a single branch. If "svn://repo/path/trunk" exists
148 converted as a single branch. If "svn://repo/path/trunk" exists
149 it replaces the default branch. If "svn://repo/path/branches"
149 it replaces the default branch. If "svn://repo/path/branches"
150 exists, its subdirectories are listed as possible branches. If
150 exists, its subdirectories are listed as possible branches. If
151 "svn://repo/path/tags" exists, it is looked for tags referencing
151 "svn://repo/path/tags" exists, it is looked for tags referencing
152 converted branches. Default "trunk", "branches" and "tags" values
152 converted branches. Default "trunk", "branches" and "tags" values
153 can be overriden with following options. Set them to paths
153 can be overriden with following options. Set them to paths
154 relative to the source URL, or leave them blank to disable
154 relative to the source URL, or leave them blank to disable
155 autodetection.
155 autodetection.
156
156
157 --config convert.svn.branches=branches (directory name)
157 --config convert.svn.branches=branches (directory name)
158 specify the directory containing branches
158 specify the directory containing branches
159 --config convert.svn.tags=tags (directory name)
159 --config convert.svn.tags=tags (directory name)
160 specify the directory containing tags
160 specify the directory containing tags
161 --config convert.svn.trunk=trunk (directory name)
161 --config convert.svn.trunk=trunk (directory name)
162 specify the name of the trunk branch
162 specify the name of the trunk branch
163
163
164 Source history can be retrieved starting at a specific revision,
164 Source history can be retrieved starting at a specific revision,
165 instead of being integrally converted. Only single branch
165 instead of being integrally converted. Only single branch
166 conversions are supported.
166 conversions are supported.
167
167
168 --config convert.svn.startrev=0 (svn revision number)
168 --config convert.svn.startrev=0 (svn revision number)
169 specify start Subversion revision.
169 specify start Subversion revision.
170
170
171 Mercurial Destination
171 Mercurial Destination
172 ---------------------
172 ---------------------
173
173
174 --config convert.hg.clonebranches=False (boolean)
174 --config convert.hg.clonebranches=False (boolean)
175 dispatch source branches in separate clones.
175 dispatch source branches in separate clones.
176 --config convert.hg.tagsbranch=default (branch name)
176 --config convert.hg.tagsbranch=default (branch name)
177 tag revisions branch name
177 tag revisions branch name
178 --config convert.hg.usebranchnames=True (boolean)
178 --config convert.hg.usebranchnames=True (boolean)
179 preserve branch names
179 preserve branch names
180
180
181 """
181 """
182 return convcmd.convert(ui, src, dest, revmapfile, **opts)
182 return convcmd.convert(ui, src, dest, revmapfile, **opts)
183
183
184 def debugsvnlog(ui, **opts):
184 def debugsvnlog(ui, **opts):
185 return convcmd.debugsvnlog(ui, **opts)
185 return convcmd.debugsvnlog(ui, **opts)
186
186
187 def debugcvsps(ui, *args, **opts):
187 def debugcvsps(ui, *args, **opts):
188 '''Create changeset information from CVS
188 '''create changeset information from CVS
189
189
190 This command is intended as a debugging tool for the CVS to Mercurial
190 This command is intended as a debugging tool for the CVS to Mercurial
191 converter, and can be used as a direct replacement for cvsps.
191 converter, and can be used as a direct replacement for cvsps.
192
192
193 Hg debugcvsps reads the CVS rlog for current directory (or any named
193 Hg debugcvsps reads the CVS rlog for current directory (or any named
194 directory) in the CVS repository, and converts the log to a series of
194 directory) in the CVS repository, and converts the log to a series of
195 changesets based on matching commit log entries and dates.'''
195 changesets based on matching commit log entries and dates.'''
196 return cvsps.debugcvsps(ui, *args, **opts)
196 return cvsps.debugcvsps(ui, *args, **opts)
197
197
198 commands.norepo += " convert debugsvnlog debugcvsps"
198 commands.norepo += " convert debugsvnlog debugcvsps"
199
199
200 cmdtable = {
200 cmdtable = {
201 "convert":
201 "convert":
202 (convert,
202 (convert,
203 [('A', 'authors', '', _('username mapping filename')),
203 [('A', 'authors', '', _('username mapping filename')),
204 ('d', 'dest-type', '', _('destination repository type')),
204 ('d', 'dest-type', '', _('destination repository type')),
205 ('', 'filemap', '', _('remap file names using contents of file')),
205 ('', 'filemap', '', _('remap file names using contents of file')),
206 ('r', 'rev', '', _('import up to target revision REV')),
206 ('r', 'rev', '', _('import up to target revision REV')),
207 ('s', 'source-type', '', _('source repository type')),
207 ('s', 'source-type', '', _('source repository type')),
208 ('', 'splicemap', '', _('splice synthesized history into place')),
208 ('', 'splicemap', '', _('splice synthesized history into place')),
209 ('', 'datesort', None, _('try to sort changesets by date'))],
209 ('', 'datesort', None, _('try to sort changesets by date'))],
210 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')),
210 _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')),
211 "debugsvnlog":
211 "debugsvnlog":
212 (debugsvnlog,
212 (debugsvnlog,
213 [],
213 [],
214 'hg debugsvnlog'),
214 'hg debugsvnlog'),
215 "debugcvsps":
215 "debugcvsps":
216 (debugcvsps,
216 (debugcvsps,
217 [
217 [
218 # Main options shared with cvsps-2.1
218 # Main options shared with cvsps-2.1
219 ('b', 'branches', [], _('Only return changes on specified branches')),
219 ('b', 'branches', [], _('only return changes on specified branches')),
220 ('p', 'prefix', '', _('Prefix to remove from file names')),
220 ('p', 'prefix', '', _('prefix to remove from file names')),
221 ('r', 'revisions', [], _('Only return changes after or between specified tags')),
221 ('r', 'revisions', [], _('only return changes after or between specified tags')),
222 ('u', 'update-cache', None, _("Update cvs log cache")),
222 ('u', 'update-cache', None, _("update cvs log cache")),
223 ('x', 'new-cache', None, _("Create new cvs log cache")),
223 ('x', 'new-cache', None, _("create new cvs log cache")),
224 ('z', 'fuzz', 60, _('Set commit time fuzz in seconds')),
224 ('z', 'fuzz', 60, _('set commit time fuzz in seconds')),
225 ('', 'root', '', _('Specify cvsroot')),
225 ('', 'root', '', _('specify cvsroot')),
226 # Options specific to builtin cvsps
226 # Options specific to builtin cvsps
227 ('', 'parents', '', _('Show parent changesets')),
227 ('', 'parents', '', _('show parent changesets')),
228 ('', 'ancestors', '', _('Show current changeset in ancestor branches')),
228 ('', 'ancestors', '', _('show current changeset in ancestor branches')),
229 # Options that are ignored for compatibility with cvsps-2.1
229 # Options that are ignored for compatibility with cvsps-2.1
230 ('A', 'cvs-direct', None, 'Ignored for compatibility'),
230 ('A', 'cvs-direct', None, 'ignored for compatibility'),
231 ],
231 ],
232 'hg debugcvsps [OPTION]... [PATH]...'),
232 'hg debugcvsps [OPTION]... [PATH]...'),
233 }
233 }
@@ -1,142 +1,142 b''
1 # fetch.py - pull and merge remote changes
1 # fetch.py - pull and merge remote changes
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7 '''pulling, updating and merging in one command'''
7 '''pulling, updating and merging in one command'''
8
8
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial.node import nullid, short
10 from mercurial.node import nullid, short
11 from mercurial import commands, cmdutil, hg, util, url
11 from mercurial import commands, cmdutil, hg, util, url
12
12
13 def fetch(ui, repo, source='default', **opts):
13 def fetch(ui, repo, source='default', **opts):
14 '''Pull changes from a remote repository, merge new changes if needed.
14 '''pull changes from a remote repository, merge new changes if needed.
15
15
16 This finds all changes from the repository at the specified path
16 This finds all changes from the repository at the specified path
17 or URL and adds them to the local repository.
17 or URL and adds them to the local repository.
18
18
19 If the pulled changes add a new branch head, the head is automatically
19 If the pulled changes add a new branch head, the head is automatically
20 merged, and the result of the merge is committed. Otherwise, the
20 merged, and the result of the merge is committed. Otherwise, the
21 working directory is updated to include the new changes.
21 working directory is updated to include the new changes.
22
22
23 When a merge occurs, the newly pulled changes are assumed to be
23 When a merge occurs, the newly pulled changes are assumed to be
24 "authoritative". The head of the new changes is used as the first
24 "authoritative". The head of the new changes is used as the first
25 parent, with local changes as the second. To switch the merge
25 parent, with local changes as the second. To switch the merge
26 order, use --switch-parent.
26 order, use --switch-parent.
27
27
28 See 'hg help dates' for a list of formats valid for -d/--date.
28 See 'hg help dates' for a list of formats valid for -d/--date.
29 '''
29 '''
30
30
31 date = opts.get('date')
31 date = opts.get('date')
32 if date:
32 if date:
33 opts['date'] = util.parsedate(date)
33 opts['date'] = util.parsedate(date)
34
34
35 parent, p2 = repo.dirstate.parents()
35 parent, p2 = repo.dirstate.parents()
36 branch = repo.dirstate.branch()
36 branch = repo.dirstate.branch()
37 branchnode = repo.branchtags().get(branch)
37 branchnode = repo.branchtags().get(branch)
38 if parent != branchnode:
38 if parent != branchnode:
39 raise util.Abort(_('working dir not at branch tip '
39 raise util.Abort(_('working dir not at branch tip '
40 '(use "hg update" to check out branch tip)'))
40 '(use "hg update" to check out branch tip)'))
41
41
42 if p2 != nullid:
42 if p2 != nullid:
43 raise util.Abort(_('outstanding uncommitted merge'))
43 raise util.Abort(_('outstanding uncommitted merge'))
44
44
45 wlock = lock = None
45 wlock = lock = None
46 try:
46 try:
47 wlock = repo.wlock()
47 wlock = repo.wlock()
48 lock = repo.lock()
48 lock = repo.lock()
49 mod, add, rem, del_ = repo.status()[:4]
49 mod, add, rem, del_ = repo.status()[:4]
50
50
51 if mod or add or rem:
51 if mod or add or rem:
52 raise util.Abort(_('outstanding uncommitted changes'))
52 raise util.Abort(_('outstanding uncommitted changes'))
53 if del_:
53 if del_:
54 raise util.Abort(_('working directory is missing some files'))
54 raise util.Abort(_('working directory is missing some files'))
55 if len(repo.branchheads(branch)) > 1:
55 if len(repo.branchheads(branch)) > 1:
56 raise util.Abort(_('multiple heads in this branch '
56 raise util.Abort(_('multiple heads in this branch '
57 '(use "hg heads ." and "hg merge" to merge)'))
57 '(use "hg heads ." and "hg merge" to merge)'))
58
58
59 cmdutil.setremoteconfig(ui, opts)
59 cmdutil.setremoteconfig(ui, opts)
60
60
61 other = hg.repository(ui, ui.expandpath(source))
61 other = hg.repository(ui, ui.expandpath(source))
62 ui.status(_('pulling from %s\n') %
62 ui.status(_('pulling from %s\n') %
63 url.hidepassword(ui.expandpath(source)))
63 url.hidepassword(ui.expandpath(source)))
64 revs = None
64 revs = None
65 if opts['rev']:
65 if opts['rev']:
66 if not other.local():
66 if not other.local():
67 raise util.Abort(_("fetch -r doesn't work for remote "
67 raise util.Abort(_("fetch -r doesn't work for remote "
68 "repositories yet"))
68 "repositories yet"))
69 else:
69 else:
70 revs = [other.lookup(rev) for rev in opts['rev']]
70 revs = [other.lookup(rev) for rev in opts['rev']]
71
71
72 # Are there any changes at all?
72 # Are there any changes at all?
73 modheads = repo.pull(other, heads=revs)
73 modheads = repo.pull(other, heads=revs)
74 if modheads == 0:
74 if modheads == 0:
75 return 0
75 return 0
76
76
77 # Is this a simple fast-forward along the current branch?
77 # Is this a simple fast-forward along the current branch?
78 newheads = repo.branchheads(branch)
78 newheads = repo.branchheads(branch)
79 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
79 newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
80 if len(newheads) == 1:
80 if len(newheads) == 1:
81 if newchildren[0] != parent:
81 if newchildren[0] != parent:
82 return hg.clean(repo, newchildren[0])
82 return hg.clean(repo, newchildren[0])
83 else:
83 else:
84 return
84 return
85
85
86 # Are there more than one additional branch heads?
86 # Are there more than one additional branch heads?
87 newchildren = [n for n in newchildren if n != parent]
87 newchildren = [n for n in newchildren if n != parent]
88 newparent = parent
88 newparent = parent
89 if newchildren:
89 if newchildren:
90 newparent = newchildren[0]
90 newparent = newchildren[0]
91 hg.clean(repo, newparent)
91 hg.clean(repo, newparent)
92 newheads = [n for n in newheads if n != newparent]
92 newheads = [n for n in newheads if n != newparent]
93 if len(newheads) > 1:
93 if len(newheads) > 1:
94 ui.status(_('not merging with %d other new branch heads '
94 ui.status(_('not merging with %d other new branch heads '
95 '(use "hg heads ." and "hg merge" to merge them)\n') %
95 '(use "hg heads ." and "hg merge" to merge them)\n') %
96 (len(newheads) - 1))
96 (len(newheads) - 1))
97 return
97 return
98
98
99 # Otherwise, let's merge.
99 # Otherwise, let's merge.
100 err = False
100 err = False
101 if newheads:
101 if newheads:
102 # By default, we consider the repository we're pulling
102 # By default, we consider the repository we're pulling
103 # *from* as authoritative, so we merge our changes into
103 # *from* as authoritative, so we merge our changes into
104 # theirs.
104 # theirs.
105 if opts['switch_parent']:
105 if opts['switch_parent']:
106 firstparent, secondparent = newparent, newheads[0]
106 firstparent, secondparent = newparent, newheads[0]
107 else:
107 else:
108 firstparent, secondparent = newheads[0], newparent
108 firstparent, secondparent = newheads[0], newparent
109 ui.status(_('updating to %d:%s\n') %
109 ui.status(_('updating to %d:%s\n') %
110 (repo.changelog.rev(firstparent),
110 (repo.changelog.rev(firstparent),
111 short(firstparent)))
111 short(firstparent)))
112 hg.clean(repo, firstparent)
112 hg.clean(repo, firstparent)
113 ui.status(_('merging with %d:%s\n') %
113 ui.status(_('merging with %d:%s\n') %
114 (repo.changelog.rev(secondparent), short(secondparent)))
114 (repo.changelog.rev(secondparent), short(secondparent)))
115 err = hg.merge(repo, secondparent, remind=False)
115 err = hg.merge(repo, secondparent, remind=False)
116
116
117 if not err:
117 if not err:
118 mod, add, rem = repo.status()[:3]
118 mod, add, rem = repo.status()[:3]
119 message = (cmdutil.logmessage(opts) or
119 message = (cmdutil.logmessage(opts) or
120 (_('Automated merge with %s') %
120 (_('Automated merge with %s') %
121 url.removeauth(other.url())))
121 url.removeauth(other.url())))
122 force_editor = opts.get('force_editor') or opts.get('edit')
122 force_editor = opts.get('force_editor') or opts.get('edit')
123 n = repo.commit(mod + add + rem, message,
123 n = repo.commit(mod + add + rem, message,
124 opts['user'], opts['date'], force=True,
124 opts['user'], opts['date'], force=True,
125 force_editor=force_editor)
125 force_editor=force_editor)
126 ui.status(_('new changeset %d:%s merges remote changes '
126 ui.status(_('new changeset %d:%s merges remote changes '
127 'with local\n') % (repo.changelog.rev(n),
127 'with local\n') % (repo.changelog.rev(n),
128 short(n)))
128 short(n)))
129
129
130 finally:
130 finally:
131 del lock, wlock
131 del lock, wlock
132
132
133 cmdtable = {
133 cmdtable = {
134 'fetch':
134 'fetch':
135 (fetch,
135 (fetch,
136 [('r', 'rev', [], _('a specific revision you would like to pull')),
136 [('r', 'rev', [], _('a specific revision you would like to pull')),
137 ('e', 'edit', None, _('edit commit message')),
137 ('e', 'edit', None, _('edit commit message')),
138 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
138 ('', 'force-editor', None, _('edit commit message (DEPRECATED)')),
139 ('', 'switch-parent', None, _('switch parents when merging')),
139 ('', 'switch-parent', None, _('switch parents when merging')),
140 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
140 ] + commands.commitopts + commands.commitopts2 + commands.remoteopts,
141 _('hg fetch [SOURCE]')),
141 _('hg fetch [SOURCE]')),
142 }
142 }
@@ -1,358 +1,358 b''
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.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 '''browsing the repository in a graphical way
7 '''browsing the repository in a graphical way
8
8
9 The hgk extension allows browsing the history of a repository in a
9 The hgk extension allows browsing the history of a repository in a
10 graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is
10 graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is
11 not distributed with Mercurial.)
11 not distributed with Mercurial.)
12
12
13 hgk consists of two parts: a Tcl script that does the displaying and
13 hgk consists of two parts: a Tcl script that does the displaying and
14 querying of information, and an extension to mercurial named hgk.py,
14 querying of information, and an extension to mercurial named hgk.py,
15 which provides hooks for hgk to get information. hgk can be found in
15 which provides hooks for hgk to get information. hgk can be found in
16 the contrib directory, and hgk.py can be found in the hgext directory.
16 the contrib directory, and hgk.py can be found in the hgext directory.
17
17
18 To load the hgext.py extension, add it to your .hgrc file (you have
18 To load the hgext.py extension, add it to your .hgrc file (you have
19 to use your global $HOME/.hgrc file, not one in a repository). You
19 to use your global $HOME/.hgrc file, not one in a repository). You
20 can specify an absolute path:
20 can specify an absolute path:
21
21
22 [extensions]
22 [extensions]
23 hgk=/usr/local/lib/hgk.py
23 hgk=/usr/local/lib/hgk.py
24
24
25 Mercurial can also scan the default python library path for a file
25 Mercurial can also scan the default python library path for a file
26 named 'hgk.py' if you set hgk empty:
26 named 'hgk.py' if you set hgk empty:
27
27
28 [extensions]
28 [extensions]
29 hgk=
29 hgk=
30
30
31 The hg view command will launch the hgk Tcl script. For this command
31 The hg view command will launch the hgk Tcl script. For this command
32 to work, hgk must be in your search path. Alternately, you can
32 to work, hgk must be in your search path. Alternately, you can
33 specify the path to hgk in your .hgrc file:
33 specify the path to hgk in your .hgrc file:
34
34
35 [hgk]
35 [hgk]
36 path=/location/of/hgk
36 path=/location/of/hgk
37
37
38 hgk can make use of the extdiff extension to visualize revisions.
38 hgk can make use of the extdiff extension to visualize revisions.
39 Assuming you had already configured extdiff vdiff command, just add:
39 Assuming you had already configured extdiff vdiff command, just add:
40
40
41 [hgk]
41 [hgk]
42 vdiff=vdiff
42 vdiff=vdiff
43
43
44 Revisions context menu will now display additional entries to fire
44 Revisions context menu will now display additional entries to fire
45 vdiff on hovered and selected revisions.'''
45 vdiff on hovered and selected revisions.'''
46
46
47 import os
47 import os
48 from mercurial import commands, util, patch, revlog, cmdutil
48 from mercurial import commands, util, patch, revlog, cmdutil
49 from mercurial.node import nullid, nullrev, short
49 from mercurial.node import nullid, nullrev, short
50 from mercurial.i18n import _
50 from mercurial.i18n import _
51
51
52 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
52 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
53 """diff trees from two commits"""
53 """diff trees from two commits"""
54 def __difftree(repo, node1, node2, files=[]):
54 def __difftree(repo, node1, node2, files=[]):
55 assert node2 is not None
55 assert node2 is not None
56 mmap = repo[node1].manifest()
56 mmap = repo[node1].manifest()
57 mmap2 = repo[node2].manifest()
57 mmap2 = repo[node2].manifest()
58 m = cmdutil.match(repo, files)
58 m = cmdutil.match(repo, files)
59 modified, added, removed = repo.status(node1, node2, m)[:3]
59 modified, added, removed = repo.status(node1, node2, m)[:3]
60 empty = short(nullid)
60 empty = short(nullid)
61
61
62 for f in modified:
62 for f in modified:
63 # TODO get file permissions
63 # TODO get file permissions
64 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
64 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
65 (short(mmap[f]), short(mmap2[f]), f, f))
65 (short(mmap[f]), short(mmap2[f]), f, f))
66 for f in added:
66 for f in added:
67 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
67 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
68 (empty, short(mmap2[f]), f, f))
68 (empty, short(mmap2[f]), f, f))
69 for f in removed:
69 for f in removed:
70 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
70 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
71 (short(mmap[f]), empty, f, f))
71 (short(mmap[f]), empty, f, f))
72 ##
72 ##
73
73
74 while True:
74 while True:
75 if opts['stdin']:
75 if opts['stdin']:
76 try:
76 try:
77 line = raw_input().split(' ')
77 line = raw_input().split(' ')
78 node1 = line[0]
78 node1 = line[0]
79 if len(line) > 1:
79 if len(line) > 1:
80 node2 = line[1]
80 node2 = line[1]
81 else:
81 else:
82 node2 = None
82 node2 = None
83 except EOFError:
83 except EOFError:
84 break
84 break
85 node1 = repo.lookup(node1)
85 node1 = repo.lookup(node1)
86 if node2:
86 if node2:
87 node2 = repo.lookup(node2)
87 node2 = repo.lookup(node2)
88 else:
88 else:
89 node2 = node1
89 node2 = node1
90 node1 = repo.changelog.parents(node1)[0]
90 node1 = repo.changelog.parents(node1)[0]
91 if opts['patch']:
91 if opts['patch']:
92 if opts['pretty']:
92 if opts['pretty']:
93 catcommit(ui, repo, node2, "")
93 catcommit(ui, repo, node2, "")
94 m = cmdutil.match(repo, files)
94 m = cmdutil.match(repo, files)
95 chunks = patch.diff(repo, node1, node2, match=m,
95 chunks = patch.diff(repo, node1, node2, match=m,
96 opts=patch.diffopts(ui, {'git': True}))
96 opts=patch.diffopts(ui, {'git': True}))
97 for chunk in chunks:
97 for chunk in chunks:
98 repo.ui.write(chunk)
98 repo.ui.write(chunk)
99 else:
99 else:
100 __difftree(repo, node1, node2, files=files)
100 __difftree(repo, node1, node2, files=files)
101 if not opts['stdin']:
101 if not opts['stdin']:
102 break
102 break
103
103
104 def catcommit(ui, repo, n, prefix, ctx=None):
104 def catcommit(ui, repo, n, prefix, ctx=None):
105 nlprefix = '\n' + prefix;
105 nlprefix = '\n' + prefix;
106 if ctx is None:
106 if ctx is None:
107 ctx = repo[n]
107 ctx = repo[n]
108 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
108 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
109 for p in ctx.parents():
109 for p in ctx.parents():
110 ui.write("parent %s\n" % p)
110 ui.write("parent %s\n" % p)
111
111
112 date = ctx.date()
112 date = ctx.date()
113 description = ctx.description().replace("\0", "")
113 description = ctx.description().replace("\0", "")
114 lines = description.splitlines()
114 lines = description.splitlines()
115 if lines and lines[-1].startswith('committer:'):
115 if lines and lines[-1].startswith('committer:'):
116 committer = lines[-1].split(': ')[1].rstrip()
116 committer = lines[-1].split(': ')[1].rstrip()
117 else:
117 else:
118 committer = ctx.user()
118 committer = ctx.user()
119
119
120 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
120 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
121 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
121 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
122 ui.write("revision %d\n" % ctx.rev())
122 ui.write("revision %d\n" % ctx.rev())
123 ui.write("branch %s\n\n" % ctx.branch())
123 ui.write("branch %s\n\n" % ctx.branch())
124
124
125 if prefix != "":
125 if prefix != "":
126 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
126 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
127 else:
127 else:
128 ui.write(description + "\n")
128 ui.write(description + "\n")
129 if prefix:
129 if prefix:
130 ui.write('\0')
130 ui.write('\0')
131
131
132 def base(ui, repo, node1, node2):
132 def base(ui, repo, node1, node2):
133 """Output common ancestor information"""
133 """output common ancestor information"""
134 node1 = repo.lookup(node1)
134 node1 = repo.lookup(node1)
135 node2 = repo.lookup(node2)
135 node2 = repo.lookup(node2)
136 n = repo.changelog.ancestor(node1, node2)
136 n = repo.changelog.ancestor(node1, node2)
137 ui.write(short(n) + "\n")
137 ui.write(short(n) + "\n")
138
138
139 def catfile(ui, repo, type=None, r=None, **opts):
139 def catfile(ui, repo, type=None, r=None, **opts):
140 """cat a specific revision"""
140 """cat a specific revision"""
141 # in stdin mode, every line except the commit is prefixed with two
141 # in stdin mode, every line except the commit is prefixed with two
142 # spaces. This way the our caller can find the commit without magic
142 # spaces. This way the our caller can find the commit without magic
143 # strings
143 # strings
144 #
144 #
145 prefix = ""
145 prefix = ""
146 if opts['stdin']:
146 if opts['stdin']:
147 try:
147 try:
148 (type, r) = raw_input().split(' ');
148 (type, r) = raw_input().split(' ');
149 prefix = " "
149 prefix = " "
150 except EOFError:
150 except EOFError:
151 return
151 return
152
152
153 else:
153 else:
154 if not type or not r:
154 if not type or not r:
155 ui.warn(_("cat-file: type or revision not supplied\n"))
155 ui.warn(_("cat-file: type or revision not supplied\n"))
156 commands.help_(ui, 'cat-file')
156 commands.help_(ui, 'cat-file')
157
157
158 while r:
158 while r:
159 if type != "commit":
159 if type != "commit":
160 ui.warn(_("aborting hg cat-file only understands commits\n"))
160 ui.warn(_("aborting hg cat-file only understands commits\n"))
161 return 1;
161 return 1;
162 n = repo.lookup(r)
162 n = repo.lookup(r)
163 catcommit(ui, repo, n, prefix)
163 catcommit(ui, repo, n, prefix)
164 if opts['stdin']:
164 if opts['stdin']:
165 try:
165 try:
166 (type, r) = raw_input().split(' ');
166 (type, r) = raw_input().split(' ');
167 except EOFError:
167 except EOFError:
168 break
168 break
169 else:
169 else:
170 break
170 break
171
171
172 # git rev-tree is a confusing thing. You can supply a number of
172 # git rev-tree is a confusing thing. You can supply a number of
173 # commit sha1s on the command line, and it walks the commit history
173 # commit sha1s on the command line, and it walks the commit history
174 # telling you which commits are reachable from the supplied ones via
174 # telling you which commits are reachable from the supplied ones via
175 # a bitmask based on arg position.
175 # a bitmask based on arg position.
176 # you can specify a commit to stop at by starting the sha1 with ^
176 # you can specify a commit to stop at by starting the sha1 with ^
177 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
177 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
178 def chlogwalk():
178 def chlogwalk():
179 count = len(repo)
179 count = len(repo)
180 i = count
180 i = count
181 l = [0] * 100
181 l = [0] * 100
182 chunk = 100
182 chunk = 100
183 while True:
183 while True:
184 if chunk > i:
184 if chunk > i:
185 chunk = i
185 chunk = i
186 i = 0
186 i = 0
187 else:
187 else:
188 i -= chunk
188 i -= chunk
189
189
190 for x in xrange(0, chunk):
190 for x in xrange(0, chunk):
191 if i + x >= count:
191 if i + x >= count:
192 l[chunk - x:] = [0] * (chunk - x)
192 l[chunk - x:] = [0] * (chunk - x)
193 break
193 break
194 if full != None:
194 if full != None:
195 l[x] = repo[i + x]
195 l[x] = repo[i + x]
196 l[x].changeset() # force reading
196 l[x].changeset() # force reading
197 else:
197 else:
198 l[x] = 1
198 l[x] = 1
199 for x in xrange(chunk-1, -1, -1):
199 for x in xrange(chunk-1, -1, -1):
200 if l[x] != 0:
200 if l[x] != 0:
201 yield (i + x, full != None and l[x] or None)
201 yield (i + x, full != None and l[x] or None)
202 if i == 0:
202 if i == 0:
203 break
203 break
204
204
205 # calculate and return the reachability bitmask for sha
205 # calculate and return the reachability bitmask for sha
206 def is_reachable(ar, reachable, sha):
206 def is_reachable(ar, reachable, sha):
207 if len(ar) == 0:
207 if len(ar) == 0:
208 return 1
208 return 1
209 mask = 0
209 mask = 0
210 for i in xrange(len(ar)):
210 for i in xrange(len(ar)):
211 if sha in reachable[i]:
211 if sha in reachable[i]:
212 mask |= 1 << i
212 mask |= 1 << i
213
213
214 return mask
214 return mask
215
215
216 reachable = []
216 reachable = []
217 stop_sha1 = []
217 stop_sha1 = []
218 want_sha1 = []
218 want_sha1 = []
219 count = 0
219 count = 0
220
220
221 # figure out which commits they are asking for and which ones they
221 # figure out which commits they are asking for and which ones they
222 # want us to stop on
222 # want us to stop on
223 for i in xrange(len(args)):
223 for i in xrange(len(args)):
224 if args[i].startswith('^'):
224 if args[i].startswith('^'):
225 s = repo.lookup(args[i][1:])
225 s = repo.lookup(args[i][1:])
226 stop_sha1.append(s)
226 stop_sha1.append(s)
227 want_sha1.append(s)
227 want_sha1.append(s)
228 elif args[i] != 'HEAD':
228 elif args[i] != 'HEAD':
229 want_sha1.append(repo.lookup(args[i]))
229 want_sha1.append(repo.lookup(args[i]))
230
230
231 # calculate the graph for the supplied commits
231 # calculate the graph for the supplied commits
232 for i in xrange(len(want_sha1)):
232 for i in xrange(len(want_sha1)):
233 reachable.append({});
233 reachable.append({});
234 n = want_sha1[i];
234 n = want_sha1[i];
235 visit = [n];
235 visit = [n];
236 reachable[i][n] = 1
236 reachable[i][n] = 1
237 while visit:
237 while visit:
238 n = visit.pop(0)
238 n = visit.pop(0)
239 if n in stop_sha1:
239 if n in stop_sha1:
240 continue
240 continue
241 for p in repo.changelog.parents(n):
241 for p in repo.changelog.parents(n):
242 if p not in reachable[i]:
242 if p not in reachable[i]:
243 reachable[i][p] = 1
243 reachable[i][p] = 1
244 visit.append(p)
244 visit.append(p)
245 if p in stop_sha1:
245 if p in stop_sha1:
246 continue
246 continue
247
247
248 # walk the repository looking for commits that are in our
248 # walk the repository looking for commits that are in our
249 # reachability graph
249 # reachability graph
250 for i, ctx in chlogwalk():
250 for i, ctx in chlogwalk():
251 n = repo.changelog.node(i)
251 n = repo.changelog.node(i)
252 mask = is_reachable(want_sha1, reachable, n)
252 mask = is_reachable(want_sha1, reachable, n)
253 if mask:
253 if mask:
254 parentstr = ""
254 parentstr = ""
255 if parents:
255 if parents:
256 pp = repo.changelog.parents(n)
256 pp = repo.changelog.parents(n)
257 if pp[0] != nullid:
257 if pp[0] != nullid:
258 parentstr += " " + short(pp[0])
258 parentstr += " " + short(pp[0])
259 if pp[1] != nullid:
259 if pp[1] != nullid:
260 parentstr += " " + short(pp[1])
260 parentstr += " " + short(pp[1])
261 if not full:
261 if not full:
262 ui.write("%s%s\n" % (short(n), parentstr))
262 ui.write("%s%s\n" % (short(n), parentstr))
263 elif full == "commit":
263 elif full == "commit":
264 ui.write("%s%s\n" % (short(n), parentstr))
264 ui.write("%s%s\n" % (short(n), parentstr))
265 catcommit(ui, repo, n, ' ', ctx)
265 catcommit(ui, repo, n, ' ', ctx)
266 else:
266 else:
267 (p1, p2) = repo.changelog.parents(n)
267 (p1, p2) = repo.changelog.parents(n)
268 (h, h1, h2) = map(short, (n, p1, p2))
268 (h, h1, h2) = map(short, (n, p1, p2))
269 (i1, i2) = map(repo.changelog.rev, (p1, p2))
269 (i1, i2) = map(repo.changelog.rev, (p1, p2))
270
270
271 date = ctx.date()[0]
271 date = ctx.date()[0]
272 ui.write("%s %s:%s" % (date, h, mask))
272 ui.write("%s %s:%s" % (date, h, mask))
273 mask = is_reachable(want_sha1, reachable, p1)
273 mask = is_reachable(want_sha1, reachable, p1)
274 if i1 != nullrev and mask > 0:
274 if i1 != nullrev and mask > 0:
275 ui.write("%s:%s " % (h1, mask)),
275 ui.write("%s:%s " % (h1, mask)),
276 mask = is_reachable(want_sha1, reachable, p2)
276 mask = is_reachable(want_sha1, reachable, p2)
277 if i2 != nullrev and mask > 0:
277 if i2 != nullrev and mask > 0:
278 ui.write("%s:%s " % (h2, mask))
278 ui.write("%s:%s " % (h2, mask))
279 ui.write("\n")
279 ui.write("\n")
280 if maxnr and count >= maxnr:
280 if maxnr and count >= maxnr:
281 break
281 break
282 count += 1
282 count += 1
283
283
284 def revparse(ui, repo, *revs, **opts):
284 def revparse(ui, repo, *revs, **opts):
285 """Parse given revisions"""
285 """parse given revisions"""
286 def revstr(rev):
286 def revstr(rev):
287 if rev == 'HEAD':
287 if rev == 'HEAD':
288 rev = 'tip'
288 rev = 'tip'
289 return revlog.hex(repo.lookup(rev))
289 return revlog.hex(repo.lookup(rev))
290
290
291 for r in revs:
291 for r in revs:
292 revrange = r.split(':', 1)
292 revrange = r.split(':', 1)
293 ui.write('%s\n' % revstr(revrange[0]))
293 ui.write('%s\n' % revstr(revrange[0]))
294 if len(revrange) == 2:
294 if len(revrange) == 2:
295 ui.write('^%s\n' % revstr(revrange[1]))
295 ui.write('^%s\n' % revstr(revrange[1]))
296
296
297 # git rev-list tries to order things by date, and has the ability to stop
297 # git rev-list tries to order things by date, and has the ability to stop
298 # at a given commit without walking the whole repo. TODO add the stop
298 # at a given commit without walking the whole repo. TODO add the stop
299 # parameter
299 # parameter
300 def revlist(ui, repo, *revs, **opts):
300 def revlist(ui, repo, *revs, **opts):
301 """print revisions"""
301 """print revisions"""
302 if opts['header']:
302 if opts['header']:
303 full = "commit"
303 full = "commit"
304 else:
304 else:
305 full = None
305 full = None
306 copy = [x for x in revs]
306 copy = [x for x in revs]
307 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
307 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
308
308
309 def config(ui, repo, **opts):
309 def config(ui, repo, **opts):
310 """print extension options"""
310 """print extension options"""
311 def writeopt(name, value):
311 def writeopt(name, value):
312 ui.write('k=%s\nv=%s\n' % (name, value))
312 ui.write('k=%s\nv=%s\n' % (name, value))
313
313
314 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
314 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
315
315
316
316
317 def view(ui, repo, *etc, **opts):
317 def view(ui, repo, *etc, **opts):
318 "start interactive history viewer"
318 "start interactive history viewer"
319 os.chdir(repo.root)
319 os.chdir(repo.root)
320 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
320 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
321 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
321 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
322 ui.debug(_("running %s\n") % cmd)
322 ui.debug(_("running %s\n") % cmd)
323 util.system(cmd)
323 util.system(cmd)
324
324
325 cmdtable = {
325 cmdtable = {
326 "^view":
326 "^view":
327 (view,
327 (view,
328 [('l', 'limit', '', _('limit number of changes displayed'))],
328 [('l', 'limit', '', _('limit number of changes displayed'))],
329 _('hg view [-l LIMIT] [REVRANGE]')),
329 _('hg view [-l LIMIT] [REVRANGE]')),
330 "debug-diff-tree":
330 "debug-diff-tree":
331 (difftree,
331 (difftree,
332 [('p', 'patch', None, _('generate patch')),
332 [('p', 'patch', None, _('generate patch')),
333 ('r', 'recursive', None, _('recursive')),
333 ('r', 'recursive', None, _('recursive')),
334 ('P', 'pretty', None, _('pretty')),
334 ('P', 'pretty', None, _('pretty')),
335 ('s', 'stdin', None, _('stdin')),
335 ('s', 'stdin', None, _('stdin')),
336 ('C', 'copy', None, _('detect copies')),
336 ('C', 'copy', None, _('detect copies')),
337 ('S', 'search', "", _('search'))],
337 ('S', 'search', "", _('search'))],
338 _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')),
338 _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')),
339 "debug-cat-file":
339 "debug-cat-file":
340 (catfile,
340 (catfile,
341 [('s', 'stdin', None, _('stdin'))],
341 [('s', 'stdin', None, _('stdin'))],
342 _('hg debug-cat-file [OPTION]... TYPE FILE')),
342 _('hg debug-cat-file [OPTION]... TYPE FILE')),
343 "debug-config":
343 "debug-config":
344 (config, [], _('hg debug-config')),
344 (config, [], _('hg debug-config')),
345 "debug-merge-base":
345 "debug-merge-base":
346 (base, [], _('hg debug-merge-base node node')),
346 (base, [], _('hg debug-merge-base node node')),
347 "debug-rev-parse":
347 "debug-rev-parse":
348 (revparse,
348 (revparse,
349 [('', 'default', '', _('ignored'))],
349 [('', 'default', '', _('ignored'))],
350 _('hg debug-rev-parse REV')),
350 _('hg debug-rev-parse REV')),
351 "debug-rev-list":
351 "debug-rev-list":
352 (revlist,
352 (revlist,
353 [('H', 'header', None, _('header')),
353 [('H', 'header', None, _('header')),
354 ('t', 'topo-order', None, _('topo-order')),
354 ('t', 'topo-order', None, _('topo-order')),
355 ('p', 'parents', None, _('parents')),
355 ('p', 'parents', None, _('parents')),
356 ('n', 'max-count', 0, _('max-count'))],
356 ('n', 'max-count', 0, _('max-count'))],
357 _('hg debug-rev-list [options] revs')),
357 _('hg debug-rev-list [options] revs')),
358 }
358 }
@@ -1,2576 +1,2576 b''
1 # mq.py - patch queues for mercurial
1 # mq.py - patch queues for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.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 '''patch management and development
8 '''patch management and development
9
9
10 This extension lets you work with a stack of patches in a Mercurial
10 This extension lets you work with a stack of patches in a Mercurial
11 repository. It manages two stacks of patches - all known patches, and
11 repository. It manages two stacks of patches - all known patches, and
12 applied patches (subset of known patches).
12 applied patches (subset of known patches).
13
13
14 Known patches are represented as patch files in the .hg/patches
14 Known patches are represented as patch files in the .hg/patches
15 directory. Applied patches are both patch files and changesets.
15 directory. Applied patches are both patch files and changesets.
16
16
17 Common tasks (use "hg help command" for more details):
17 Common tasks (use "hg help command" for more details):
18
18
19 prepare repository to work with patches qinit
19 prepare repository to work with patches qinit
20 create new patch qnew
20 create new patch qnew
21 import existing patch qimport
21 import existing patch qimport
22
22
23 print patch series qseries
23 print patch series qseries
24 print applied patches qapplied
24 print applied patches qapplied
25 print name of top applied patch qtop
25 print name of top applied patch qtop
26
26
27 add known patch to applied stack qpush
27 add known patch to applied stack qpush
28 remove patch from applied stack qpop
28 remove patch from applied stack qpop
29 refresh contents of top applied patch qrefresh
29 refresh contents of top applied patch qrefresh
30 '''
30 '''
31
31
32 from mercurial.i18n import _
32 from mercurial.i18n import _
33 from mercurial.node import bin, hex, short
33 from mercurial.node import bin, hex, short
34 from mercurial.repo import RepoError
34 from mercurial.repo import RepoError
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
35 from mercurial import commands, cmdutil, hg, patch, revlog, util
36 from mercurial import repair, extensions, url
36 from mercurial import repair, extensions, url
37 import os, sys, re, errno
37 import os, sys, re, errno
38
38
39 commands.norepo += " qclone"
39 commands.norepo += " qclone"
40
40
41 # Patch names looks like unix-file names.
41 # Patch names looks like unix-file names.
42 # They must be joinable with queue directory and result in the patch path.
42 # They must be joinable with queue directory and result in the patch path.
43 normname = util.normpath
43 normname = util.normpath
44
44
45 class statusentry:
45 class statusentry:
46 def __init__(self, rev, name=None):
46 def __init__(self, rev, name=None):
47 if not name:
47 if not name:
48 fields = rev.split(':', 1)
48 fields = rev.split(':', 1)
49 if len(fields) == 2:
49 if len(fields) == 2:
50 self.rev, self.name = fields
50 self.rev, self.name = fields
51 else:
51 else:
52 self.rev, self.name = None, None
52 self.rev, self.name = None, None
53 else:
53 else:
54 self.rev, self.name = rev, name
54 self.rev, self.name = rev, name
55
55
56 def __str__(self):
56 def __str__(self):
57 return self.rev + ':' + self.name
57 return self.rev + ':' + self.name
58
58
59 class patchheader(object):
59 class patchheader(object):
60 def __init__(self, message, comments, user, date, haspatch):
60 def __init__(self, message, comments, user, date, haspatch):
61 self.message = message
61 self.message = message
62 self.comments = comments
62 self.comments = comments
63 self.user = user
63 self.user = user
64 self.date = date
64 self.date = date
65 self.haspatch = haspatch
65 self.haspatch = haspatch
66
66
67 def setuser(self, user):
67 def setuser(self, user):
68 if not self.setheader(['From: ', '# User '], user):
68 if not self.setheader(['From: ', '# User '], user):
69 try:
69 try:
70 patchheaderat = self.comments.index('# HG changeset patch')
70 patchheaderat = self.comments.index('# HG changeset patch')
71 self.comments.insert(patchheaderat + 1,'# User ' + user)
71 self.comments.insert(patchheaderat + 1,'# User ' + user)
72 except ValueError:
72 except ValueError:
73 self.comments = ['From: ' + user, ''] + self.comments
73 self.comments = ['From: ' + user, ''] + self.comments
74 self.user = user
74 self.user = user
75
75
76 def setdate(self, date):
76 def setdate(self, date):
77 if self.setheader(['# Date '], date):
77 if self.setheader(['# Date '], date):
78 self.date = date
78 self.date = date
79
79
80 def setmessage(self, message):
80 def setmessage(self, message):
81 if self.comments:
81 if self.comments:
82 self._delmsg()
82 self._delmsg()
83 self.message = [message]
83 self.message = [message]
84 self.comments += self.message
84 self.comments += self.message
85
85
86 def setheader(self, prefixes, new):
86 def setheader(self, prefixes, new):
87 '''Update all references to a field in the patch header.
87 '''Update all references to a field in the patch header.
88 If none found, add it email style.'''
88 If none found, add it email style.'''
89 res = False
89 res = False
90 for prefix in prefixes:
90 for prefix in prefixes:
91 for i in xrange(len(self.comments)):
91 for i in xrange(len(self.comments)):
92 if self.comments[i].startswith(prefix):
92 if self.comments[i].startswith(prefix):
93 self.comments[i] = prefix + new
93 self.comments[i] = prefix + new
94 res = True
94 res = True
95 break
95 break
96 return res
96 return res
97
97
98 def __str__(self):
98 def __str__(self):
99 if not self.comments:
99 if not self.comments:
100 return ''
100 return ''
101 return '\n'.join(self.comments) + '\n\n'
101 return '\n'.join(self.comments) + '\n\n'
102
102
103 def _delmsg(self):
103 def _delmsg(self):
104 '''Remove existing message, keeping the rest of the comments fields.
104 '''Remove existing message, keeping the rest of the comments fields.
105 If comments contains 'subject: ', message will prepend
105 If comments contains 'subject: ', message will prepend
106 the field and a blank line.'''
106 the field and a blank line.'''
107 if self.message:
107 if self.message:
108 subj = 'subject: ' + self.message[0].lower()
108 subj = 'subject: ' + self.message[0].lower()
109 for i in xrange(len(self.comments)):
109 for i in xrange(len(self.comments)):
110 if subj == self.comments[i].lower():
110 if subj == self.comments[i].lower():
111 del self.comments[i]
111 del self.comments[i]
112 self.message = self.message[2:]
112 self.message = self.message[2:]
113 break
113 break
114 ci = 0
114 ci = 0
115 for mi in xrange(len(self.message)):
115 for mi in xrange(len(self.message)):
116 while self.message[mi] != self.comments[ci]:
116 while self.message[mi] != self.comments[ci]:
117 ci += 1
117 ci += 1
118 del self.comments[ci]
118 del self.comments[ci]
119
119
120 class queue:
120 class queue:
121 def __init__(self, ui, path, patchdir=None):
121 def __init__(self, ui, path, patchdir=None):
122 self.basepath = path
122 self.basepath = path
123 self.path = patchdir or os.path.join(path, "patches")
123 self.path = patchdir or os.path.join(path, "patches")
124 self.opener = util.opener(self.path)
124 self.opener = util.opener(self.path)
125 self.ui = ui
125 self.ui = ui
126 self.applied = []
126 self.applied = []
127 self.full_series = []
127 self.full_series = []
128 self.applied_dirty = 0
128 self.applied_dirty = 0
129 self.series_dirty = 0
129 self.series_dirty = 0
130 self.series_path = "series"
130 self.series_path = "series"
131 self.status_path = "status"
131 self.status_path = "status"
132 self.guards_path = "guards"
132 self.guards_path = "guards"
133 self.active_guards = None
133 self.active_guards = None
134 self.guards_dirty = False
134 self.guards_dirty = False
135 self._diffopts = None
135 self._diffopts = None
136
136
137 if os.path.exists(self.join(self.series_path)):
137 if os.path.exists(self.join(self.series_path)):
138 self.full_series = self.opener(self.series_path).read().splitlines()
138 self.full_series = self.opener(self.series_path).read().splitlines()
139 self.parse_series()
139 self.parse_series()
140
140
141 if os.path.exists(self.join(self.status_path)):
141 if os.path.exists(self.join(self.status_path)):
142 lines = self.opener(self.status_path).read().splitlines()
142 lines = self.opener(self.status_path).read().splitlines()
143 self.applied = [statusentry(l) for l in lines]
143 self.applied = [statusentry(l) for l in lines]
144
144
145 def diffopts(self):
145 def diffopts(self):
146 if self._diffopts is None:
146 if self._diffopts is None:
147 self._diffopts = patch.diffopts(self.ui)
147 self._diffopts = patch.diffopts(self.ui)
148 return self._diffopts
148 return self._diffopts
149
149
150 def join(self, *p):
150 def join(self, *p):
151 return os.path.join(self.path, *p)
151 return os.path.join(self.path, *p)
152
152
153 def find_series(self, patch):
153 def find_series(self, patch):
154 pre = re.compile("(\s*)([^#]+)")
154 pre = re.compile("(\s*)([^#]+)")
155 index = 0
155 index = 0
156 for l in self.full_series:
156 for l in self.full_series:
157 m = pre.match(l)
157 m = pre.match(l)
158 if m:
158 if m:
159 s = m.group(2)
159 s = m.group(2)
160 s = s.rstrip()
160 s = s.rstrip()
161 if s == patch:
161 if s == patch:
162 return index
162 return index
163 index += 1
163 index += 1
164 return None
164 return None
165
165
166 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
166 guard_re = re.compile(r'\s?#([-+][^-+# \t\r\n\f][^# \t\r\n\f]*)')
167
167
168 def parse_series(self):
168 def parse_series(self):
169 self.series = []
169 self.series = []
170 self.series_guards = []
170 self.series_guards = []
171 for l in self.full_series:
171 for l in self.full_series:
172 h = l.find('#')
172 h = l.find('#')
173 if h == -1:
173 if h == -1:
174 patch = l
174 patch = l
175 comment = ''
175 comment = ''
176 elif h == 0:
176 elif h == 0:
177 continue
177 continue
178 else:
178 else:
179 patch = l[:h]
179 patch = l[:h]
180 comment = l[h:]
180 comment = l[h:]
181 patch = patch.strip()
181 patch = patch.strip()
182 if patch:
182 if patch:
183 if patch in self.series:
183 if patch in self.series:
184 raise util.Abort(_('%s appears more than once in %s') %
184 raise util.Abort(_('%s appears more than once in %s') %
185 (patch, self.join(self.series_path)))
185 (patch, self.join(self.series_path)))
186 self.series.append(patch)
186 self.series.append(patch)
187 self.series_guards.append(self.guard_re.findall(comment))
187 self.series_guards.append(self.guard_re.findall(comment))
188
188
189 def check_guard(self, guard):
189 def check_guard(self, guard):
190 if not guard:
190 if not guard:
191 return _('guard cannot be an empty string')
191 return _('guard cannot be an empty string')
192 bad_chars = '# \t\r\n\f'
192 bad_chars = '# \t\r\n\f'
193 first = guard[0]
193 first = guard[0]
194 for c in '-+':
194 for c in '-+':
195 if first == c:
195 if first == c:
196 return (_('guard %r starts with invalid character: %r') %
196 return (_('guard %r starts with invalid character: %r') %
197 (guard, c))
197 (guard, c))
198 for c in bad_chars:
198 for c in bad_chars:
199 if c in guard:
199 if c in guard:
200 return _('invalid character in guard %r: %r') % (guard, c)
200 return _('invalid character in guard %r: %r') % (guard, c)
201
201
202 def set_active(self, guards):
202 def set_active(self, guards):
203 for guard in guards:
203 for guard in guards:
204 bad = self.check_guard(guard)
204 bad = self.check_guard(guard)
205 if bad:
205 if bad:
206 raise util.Abort(bad)
206 raise util.Abort(bad)
207 guards = util.sort(util.unique(guards))
207 guards = util.sort(util.unique(guards))
208 self.ui.debug(_('active guards: %s\n') % ' '.join(guards))
208 self.ui.debug(_('active guards: %s\n') % ' '.join(guards))
209 self.active_guards = guards
209 self.active_guards = guards
210 self.guards_dirty = True
210 self.guards_dirty = True
211
211
212 def active(self):
212 def active(self):
213 if self.active_guards is None:
213 if self.active_guards is None:
214 self.active_guards = []
214 self.active_guards = []
215 try:
215 try:
216 guards = self.opener(self.guards_path).read().split()
216 guards = self.opener(self.guards_path).read().split()
217 except IOError, err:
217 except IOError, err:
218 if err.errno != errno.ENOENT: raise
218 if err.errno != errno.ENOENT: raise
219 guards = []
219 guards = []
220 for i, guard in enumerate(guards):
220 for i, guard in enumerate(guards):
221 bad = self.check_guard(guard)
221 bad = self.check_guard(guard)
222 if bad:
222 if bad:
223 self.ui.warn('%s:%d: %s\n' %
223 self.ui.warn('%s:%d: %s\n' %
224 (self.join(self.guards_path), i + 1, bad))
224 (self.join(self.guards_path), i + 1, bad))
225 else:
225 else:
226 self.active_guards.append(guard)
226 self.active_guards.append(guard)
227 return self.active_guards
227 return self.active_guards
228
228
229 def set_guards(self, idx, guards):
229 def set_guards(self, idx, guards):
230 for g in guards:
230 for g in guards:
231 if len(g) < 2:
231 if len(g) < 2:
232 raise util.Abort(_('guard %r too short') % g)
232 raise util.Abort(_('guard %r too short') % g)
233 if g[0] not in '-+':
233 if g[0] not in '-+':
234 raise util.Abort(_('guard %r starts with invalid char') % g)
234 raise util.Abort(_('guard %r starts with invalid char') % g)
235 bad = self.check_guard(g[1:])
235 bad = self.check_guard(g[1:])
236 if bad:
236 if bad:
237 raise util.Abort(bad)
237 raise util.Abort(bad)
238 drop = self.guard_re.sub('', self.full_series[idx])
238 drop = self.guard_re.sub('', self.full_series[idx])
239 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
239 self.full_series[idx] = drop + ''.join([' #' + g for g in guards])
240 self.parse_series()
240 self.parse_series()
241 self.series_dirty = True
241 self.series_dirty = True
242
242
243 def pushable(self, idx):
243 def pushable(self, idx):
244 if isinstance(idx, str):
244 if isinstance(idx, str):
245 idx = self.series.index(idx)
245 idx = self.series.index(idx)
246 patchguards = self.series_guards[idx]
246 patchguards = self.series_guards[idx]
247 if not patchguards:
247 if not patchguards:
248 return True, None
248 return True, None
249 guards = self.active()
249 guards = self.active()
250 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
250 exactneg = [g for g in patchguards if g[0] == '-' and g[1:] in guards]
251 if exactneg:
251 if exactneg:
252 return False, exactneg[0]
252 return False, exactneg[0]
253 pos = [g for g in patchguards if g[0] == '+']
253 pos = [g for g in patchguards if g[0] == '+']
254 exactpos = [g for g in pos if g[1:] in guards]
254 exactpos = [g for g in pos if g[1:] in guards]
255 if pos:
255 if pos:
256 if exactpos:
256 if exactpos:
257 return True, exactpos[0]
257 return True, exactpos[0]
258 return False, pos
258 return False, pos
259 return True, ''
259 return True, ''
260
260
261 def explain_pushable(self, idx, all_patches=False):
261 def explain_pushable(self, idx, all_patches=False):
262 write = all_patches and self.ui.write or self.ui.warn
262 write = all_patches and self.ui.write or self.ui.warn
263 if all_patches or self.ui.verbose:
263 if all_patches or self.ui.verbose:
264 if isinstance(idx, str):
264 if isinstance(idx, str):
265 idx = self.series.index(idx)
265 idx = self.series.index(idx)
266 pushable, why = self.pushable(idx)
266 pushable, why = self.pushable(idx)
267 if all_patches and pushable:
267 if all_patches and pushable:
268 if why is None:
268 if why is None:
269 write(_('allowing %s - no guards in effect\n') %
269 write(_('allowing %s - no guards in effect\n') %
270 self.series[idx])
270 self.series[idx])
271 else:
271 else:
272 if not why:
272 if not why:
273 write(_('allowing %s - no matching negative guards\n') %
273 write(_('allowing %s - no matching negative guards\n') %
274 self.series[idx])
274 self.series[idx])
275 else:
275 else:
276 write(_('allowing %s - guarded by %r\n') %
276 write(_('allowing %s - guarded by %r\n') %
277 (self.series[idx], why))
277 (self.series[idx], why))
278 if not pushable:
278 if not pushable:
279 if why:
279 if why:
280 write(_('skipping %s - guarded by %r\n') %
280 write(_('skipping %s - guarded by %r\n') %
281 (self.series[idx], why))
281 (self.series[idx], why))
282 else:
282 else:
283 write(_('skipping %s - no matching guards\n') %
283 write(_('skipping %s - no matching guards\n') %
284 self.series[idx])
284 self.series[idx])
285
285
286 def save_dirty(self):
286 def save_dirty(self):
287 def write_list(items, path):
287 def write_list(items, path):
288 fp = self.opener(path, 'w')
288 fp = self.opener(path, 'w')
289 for i in items:
289 for i in items:
290 fp.write("%s\n" % i)
290 fp.write("%s\n" % i)
291 fp.close()
291 fp.close()
292 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
292 if self.applied_dirty: write_list(map(str, self.applied), self.status_path)
293 if self.series_dirty: write_list(self.full_series, self.series_path)
293 if self.series_dirty: write_list(self.full_series, self.series_path)
294 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
294 if self.guards_dirty: write_list(self.active_guards, self.guards_path)
295
295
296 def readheaders(self, patch):
296 def readheaders(self, patch):
297 def eatdiff(lines):
297 def eatdiff(lines):
298 while lines:
298 while lines:
299 l = lines[-1]
299 l = lines[-1]
300 if (l.startswith("diff -") or
300 if (l.startswith("diff -") or
301 l.startswith("Index:") or
301 l.startswith("Index:") or
302 l.startswith("===========")):
302 l.startswith("===========")):
303 del lines[-1]
303 del lines[-1]
304 else:
304 else:
305 break
305 break
306 def eatempty(lines):
306 def eatempty(lines):
307 while lines:
307 while lines:
308 l = lines[-1]
308 l = lines[-1]
309 if re.match('\s*$', l):
309 if re.match('\s*$', l):
310 del lines[-1]
310 del lines[-1]
311 else:
311 else:
312 break
312 break
313
313
314 pf = self.join(patch)
314 pf = self.join(patch)
315 message = []
315 message = []
316 comments = []
316 comments = []
317 user = None
317 user = None
318 date = None
318 date = None
319 format = None
319 format = None
320 subject = None
320 subject = None
321 diffstart = 0
321 diffstart = 0
322
322
323 for line in file(pf):
323 for line in file(pf):
324 line = line.rstrip()
324 line = line.rstrip()
325 if line.startswith('diff --git'):
325 if line.startswith('diff --git'):
326 diffstart = 2
326 diffstart = 2
327 break
327 break
328 if diffstart:
328 if diffstart:
329 if line.startswith('+++ '):
329 if line.startswith('+++ '):
330 diffstart = 2
330 diffstart = 2
331 break
331 break
332 if line.startswith("--- "):
332 if line.startswith("--- "):
333 diffstart = 1
333 diffstart = 1
334 continue
334 continue
335 elif format == "hgpatch":
335 elif format == "hgpatch":
336 # parse values when importing the result of an hg export
336 # parse values when importing the result of an hg export
337 if line.startswith("# User "):
337 if line.startswith("# User "):
338 user = line[7:]
338 user = line[7:]
339 elif line.startswith("# Date "):
339 elif line.startswith("# Date "):
340 date = line[7:]
340 date = line[7:]
341 elif not line.startswith("# ") and line:
341 elif not line.startswith("# ") and line:
342 message.append(line)
342 message.append(line)
343 format = None
343 format = None
344 elif line == '# HG changeset patch':
344 elif line == '# HG changeset patch':
345 format = "hgpatch"
345 format = "hgpatch"
346 elif (format != "tagdone" and (line.startswith("Subject: ") or
346 elif (format != "tagdone" and (line.startswith("Subject: ") or
347 line.startswith("subject: "))):
347 line.startswith("subject: "))):
348 subject = line[9:]
348 subject = line[9:]
349 format = "tag"
349 format = "tag"
350 elif (format != "tagdone" and (line.startswith("From: ") or
350 elif (format != "tagdone" and (line.startswith("From: ") or
351 line.startswith("from: "))):
351 line.startswith("from: "))):
352 user = line[6:]
352 user = line[6:]
353 format = "tag"
353 format = "tag"
354 elif format == "tag" and line == "":
354 elif format == "tag" and line == "":
355 # when looking for tags (subject: from: etc) they
355 # when looking for tags (subject: from: etc) they
356 # end once you find a blank line in the source
356 # end once you find a blank line in the source
357 format = "tagdone"
357 format = "tagdone"
358 elif message or line:
358 elif message or line:
359 message.append(line)
359 message.append(line)
360 comments.append(line)
360 comments.append(line)
361
361
362 eatdiff(message)
362 eatdiff(message)
363 eatdiff(comments)
363 eatdiff(comments)
364 eatempty(message)
364 eatempty(message)
365 eatempty(comments)
365 eatempty(comments)
366
366
367 # make sure message isn't empty
367 # make sure message isn't empty
368 if format and format.startswith("tag") and subject:
368 if format and format.startswith("tag") and subject:
369 message.insert(0, "")
369 message.insert(0, "")
370 message.insert(0, subject)
370 message.insert(0, subject)
371 return patchheader(message, comments, user, date, diffstart > 1)
371 return patchheader(message, comments, user, date, diffstart > 1)
372
372
373 def removeundo(self, repo):
373 def removeundo(self, repo):
374 undo = repo.sjoin('undo')
374 undo = repo.sjoin('undo')
375 if not os.path.exists(undo):
375 if not os.path.exists(undo):
376 return
376 return
377 try:
377 try:
378 os.unlink(undo)
378 os.unlink(undo)
379 except OSError, inst:
379 except OSError, inst:
380 self.ui.warn(_('error removing undo: %s\n') % str(inst))
380 self.ui.warn(_('error removing undo: %s\n') % str(inst))
381
381
382 def printdiff(self, repo, node1, node2=None, files=None,
382 def printdiff(self, repo, node1, node2=None, files=None,
383 fp=None, changes=None, opts={}):
383 fp=None, changes=None, opts={}):
384 m = cmdutil.match(repo, files, opts)
384 m = cmdutil.match(repo, files, opts)
385 chunks = patch.diff(repo, node1, node2, m, changes, self.diffopts())
385 chunks = patch.diff(repo, node1, node2, m, changes, self.diffopts())
386 write = fp is None and repo.ui.write or fp.write
386 write = fp is None and repo.ui.write or fp.write
387 for chunk in chunks:
387 for chunk in chunks:
388 write(chunk)
388 write(chunk)
389
389
390 def mergeone(self, repo, mergeq, head, patch, rev):
390 def mergeone(self, repo, mergeq, head, patch, rev):
391 # first try just applying the patch
391 # first try just applying the patch
392 (err, n) = self.apply(repo, [ patch ], update_status=False,
392 (err, n) = self.apply(repo, [ patch ], update_status=False,
393 strict=True, merge=rev)
393 strict=True, merge=rev)
394
394
395 if err == 0:
395 if err == 0:
396 return (err, n)
396 return (err, n)
397
397
398 if n is None:
398 if n is None:
399 raise util.Abort(_("apply failed for patch %s") % patch)
399 raise util.Abort(_("apply failed for patch %s") % patch)
400
400
401 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
401 self.ui.warn(_("patch didn't work out, merging %s\n") % patch)
402
402
403 # apply failed, strip away that rev and merge.
403 # apply failed, strip away that rev and merge.
404 hg.clean(repo, head)
404 hg.clean(repo, head)
405 self.strip(repo, n, update=False, backup='strip')
405 self.strip(repo, n, update=False, backup='strip')
406
406
407 ctx = repo[rev]
407 ctx = repo[rev]
408 ret = hg.merge(repo, rev)
408 ret = hg.merge(repo, rev)
409 if ret:
409 if ret:
410 raise util.Abort(_("update returned %d") % ret)
410 raise util.Abort(_("update returned %d") % ret)
411 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
411 n = repo.commit(None, ctx.description(), ctx.user(), force=1)
412 if n == None:
412 if n == None:
413 raise util.Abort(_("repo commit failed"))
413 raise util.Abort(_("repo commit failed"))
414 try:
414 try:
415 ph = mergeq.readheaders(patch)
415 ph = mergeq.readheaders(patch)
416 except:
416 except:
417 raise util.Abort(_("unable to read %s") % patch)
417 raise util.Abort(_("unable to read %s") % patch)
418
418
419 patchf = self.opener(patch, "w")
419 patchf = self.opener(patch, "w")
420 comments = str(ph)
420 comments = str(ph)
421 if comments:
421 if comments:
422 patchf.write(comments)
422 patchf.write(comments)
423 self.printdiff(repo, head, n, fp=patchf)
423 self.printdiff(repo, head, n, fp=patchf)
424 patchf.close()
424 patchf.close()
425 self.removeundo(repo)
425 self.removeundo(repo)
426 return (0, n)
426 return (0, n)
427
427
428 def qparents(self, repo, rev=None):
428 def qparents(self, repo, rev=None):
429 if rev is None:
429 if rev is None:
430 (p1, p2) = repo.dirstate.parents()
430 (p1, p2) = repo.dirstate.parents()
431 if p2 == revlog.nullid:
431 if p2 == revlog.nullid:
432 return p1
432 return p1
433 if len(self.applied) == 0:
433 if len(self.applied) == 0:
434 return None
434 return None
435 return revlog.bin(self.applied[-1].rev)
435 return revlog.bin(self.applied[-1].rev)
436 pp = repo.changelog.parents(rev)
436 pp = repo.changelog.parents(rev)
437 if pp[1] != revlog.nullid:
437 if pp[1] != revlog.nullid:
438 arevs = [ x.rev for x in self.applied ]
438 arevs = [ x.rev for x in self.applied ]
439 p0 = revlog.hex(pp[0])
439 p0 = revlog.hex(pp[0])
440 p1 = revlog.hex(pp[1])
440 p1 = revlog.hex(pp[1])
441 if p0 in arevs:
441 if p0 in arevs:
442 return pp[0]
442 return pp[0]
443 if p1 in arevs:
443 if p1 in arevs:
444 return pp[1]
444 return pp[1]
445 return pp[0]
445 return pp[0]
446
446
447 def mergepatch(self, repo, mergeq, series):
447 def mergepatch(self, repo, mergeq, series):
448 if len(self.applied) == 0:
448 if len(self.applied) == 0:
449 # each of the patches merged in will have two parents. This
449 # each of the patches merged in will have two parents. This
450 # can confuse the qrefresh, qdiff, and strip code because it
450 # can confuse the qrefresh, qdiff, and strip code because it
451 # needs to know which parent is actually in the patch queue.
451 # needs to know which parent is actually in the patch queue.
452 # so, we insert a merge marker with only one parent. This way
452 # so, we insert a merge marker with only one parent. This way
453 # the first patch in the queue is never a merge patch
453 # the first patch in the queue is never a merge patch
454 #
454 #
455 pname = ".hg.patches.merge.marker"
455 pname = ".hg.patches.merge.marker"
456 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
456 n = repo.commit(None, '[mq]: merge marker', user=None, force=1)
457 self.removeundo(repo)
457 self.removeundo(repo)
458 self.applied.append(statusentry(revlog.hex(n), pname))
458 self.applied.append(statusentry(revlog.hex(n), pname))
459 self.applied_dirty = 1
459 self.applied_dirty = 1
460
460
461 head = self.qparents(repo)
461 head = self.qparents(repo)
462
462
463 for patch in series:
463 for patch in series:
464 patch = mergeq.lookup(patch, strict=True)
464 patch = mergeq.lookup(patch, strict=True)
465 if not patch:
465 if not patch:
466 self.ui.warn(_("patch %s does not exist\n") % patch)
466 self.ui.warn(_("patch %s does not exist\n") % patch)
467 return (1, None)
467 return (1, None)
468 pushable, reason = self.pushable(patch)
468 pushable, reason = self.pushable(patch)
469 if not pushable:
469 if not pushable:
470 self.explain_pushable(patch, all_patches=True)
470 self.explain_pushable(patch, all_patches=True)
471 continue
471 continue
472 info = mergeq.isapplied(patch)
472 info = mergeq.isapplied(patch)
473 if not info:
473 if not info:
474 self.ui.warn(_("patch %s is not applied\n") % patch)
474 self.ui.warn(_("patch %s is not applied\n") % patch)
475 return (1, None)
475 return (1, None)
476 rev = revlog.bin(info[1])
476 rev = revlog.bin(info[1])
477 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
477 (err, head) = self.mergeone(repo, mergeq, head, patch, rev)
478 if head:
478 if head:
479 self.applied.append(statusentry(revlog.hex(head), patch))
479 self.applied.append(statusentry(revlog.hex(head), patch))
480 self.applied_dirty = 1
480 self.applied_dirty = 1
481 if err:
481 if err:
482 return (err, head)
482 return (err, head)
483 self.save_dirty()
483 self.save_dirty()
484 return (0, head)
484 return (0, head)
485
485
486 def patch(self, repo, patchfile):
486 def patch(self, repo, patchfile):
487 '''Apply patchfile to the working directory.
487 '''Apply patchfile to the working directory.
488 patchfile: file name of patch'''
488 patchfile: file name of patch'''
489 files = {}
489 files = {}
490 try:
490 try:
491 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
491 fuzz = patch.patch(patchfile, self.ui, strip=1, cwd=repo.root,
492 files=files)
492 files=files)
493 except Exception, inst:
493 except Exception, inst:
494 self.ui.note(str(inst) + '\n')
494 self.ui.note(str(inst) + '\n')
495 if not self.ui.verbose:
495 if not self.ui.verbose:
496 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
496 self.ui.warn(_("patch failed, unable to continue (try -v)\n"))
497 return (False, files, False)
497 return (False, files, False)
498
498
499 return (True, files, fuzz)
499 return (True, files, fuzz)
500
500
501 def apply(self, repo, series, list=False, update_status=True,
501 def apply(self, repo, series, list=False, update_status=True,
502 strict=False, patchdir=None, merge=None, all_files={}):
502 strict=False, patchdir=None, merge=None, all_files={}):
503 wlock = lock = tr = None
503 wlock = lock = tr = None
504 try:
504 try:
505 wlock = repo.wlock()
505 wlock = repo.wlock()
506 lock = repo.lock()
506 lock = repo.lock()
507 tr = repo.transaction()
507 tr = repo.transaction()
508 try:
508 try:
509 ret = self._apply(repo, series, list, update_status,
509 ret = self._apply(repo, series, list, update_status,
510 strict, patchdir, merge, all_files=all_files)
510 strict, patchdir, merge, all_files=all_files)
511 tr.close()
511 tr.close()
512 self.save_dirty()
512 self.save_dirty()
513 return ret
513 return ret
514 except:
514 except:
515 try:
515 try:
516 tr.abort()
516 tr.abort()
517 finally:
517 finally:
518 repo.invalidate()
518 repo.invalidate()
519 repo.dirstate.invalidate()
519 repo.dirstate.invalidate()
520 raise
520 raise
521 finally:
521 finally:
522 del tr, lock, wlock
522 del tr, lock, wlock
523 self.removeundo(repo)
523 self.removeundo(repo)
524
524
525 def _apply(self, repo, series, list=False, update_status=True,
525 def _apply(self, repo, series, list=False, update_status=True,
526 strict=False, patchdir=None, merge=None, all_files={}):
526 strict=False, patchdir=None, merge=None, all_files={}):
527 # TODO unify with commands.py
527 # TODO unify with commands.py
528 if not patchdir:
528 if not patchdir:
529 patchdir = self.path
529 patchdir = self.path
530 err = 0
530 err = 0
531 n = None
531 n = None
532 for patchname in series:
532 for patchname in series:
533 pushable, reason = self.pushable(patchname)
533 pushable, reason = self.pushable(patchname)
534 if not pushable:
534 if not pushable:
535 self.explain_pushable(patchname, all_patches=True)
535 self.explain_pushable(patchname, all_patches=True)
536 continue
536 continue
537 self.ui.warn(_("applying %s\n") % patchname)
537 self.ui.warn(_("applying %s\n") % patchname)
538 pf = os.path.join(patchdir, patchname)
538 pf = os.path.join(patchdir, patchname)
539
539
540 try:
540 try:
541 ph = self.readheaders(patchname)
541 ph = self.readheaders(patchname)
542 except:
542 except:
543 self.ui.warn(_("Unable to read %s\n") % patchname)
543 self.ui.warn(_("Unable to read %s\n") % patchname)
544 err = 1
544 err = 1
545 break
545 break
546
546
547 message = ph.message
547 message = ph.message
548 if not message:
548 if not message:
549 message = _("imported patch %s\n") % patchname
549 message = _("imported patch %s\n") % patchname
550 else:
550 else:
551 if list:
551 if list:
552 message.append(_("\nimported patch %s") % patchname)
552 message.append(_("\nimported patch %s") % patchname)
553 message = '\n'.join(message)
553 message = '\n'.join(message)
554
554
555 (patcherr, files, fuzz) = self.patch(repo, pf)
555 (patcherr, files, fuzz) = self.patch(repo, pf)
556 all_files.update(files)
556 all_files.update(files)
557 patcherr = not patcherr
557 patcherr = not patcherr
558
558
559 if merge and files:
559 if merge and files:
560 # Mark as removed/merged and update dirstate parent info
560 # Mark as removed/merged and update dirstate parent info
561 removed = []
561 removed = []
562 merged = []
562 merged = []
563 for f in files:
563 for f in files:
564 if os.path.exists(repo.wjoin(f)):
564 if os.path.exists(repo.wjoin(f)):
565 merged.append(f)
565 merged.append(f)
566 else:
566 else:
567 removed.append(f)
567 removed.append(f)
568 for f in removed:
568 for f in removed:
569 repo.dirstate.remove(f)
569 repo.dirstate.remove(f)
570 for f in merged:
570 for f in merged:
571 repo.dirstate.merge(f)
571 repo.dirstate.merge(f)
572 p1, p2 = repo.dirstate.parents()
572 p1, p2 = repo.dirstate.parents()
573 repo.dirstate.setparents(p1, merge)
573 repo.dirstate.setparents(p1, merge)
574
574
575 files = patch.updatedir(self.ui, repo, files)
575 files = patch.updatedir(self.ui, repo, files)
576 match = cmdutil.matchfiles(repo, files or [])
576 match = cmdutil.matchfiles(repo, files or [])
577 n = repo.commit(files, message, ph.user, ph.date, match=match,
577 n = repo.commit(files, message, ph.user, ph.date, match=match,
578 force=True)
578 force=True)
579
579
580 if n == None:
580 if n == None:
581 raise util.Abort(_("repo commit failed"))
581 raise util.Abort(_("repo commit failed"))
582
582
583 if update_status:
583 if update_status:
584 self.applied.append(statusentry(revlog.hex(n), patchname))
584 self.applied.append(statusentry(revlog.hex(n), patchname))
585
585
586 if patcherr:
586 if patcherr:
587 if not ph.haspatch:
587 if not ph.haspatch:
588 self.ui.warn(_("patch %s is empty\n") % patchname)
588 self.ui.warn(_("patch %s is empty\n") % patchname)
589 err = 0
589 err = 0
590 else:
590 else:
591 self.ui.warn(_("patch failed, rejects left in working dir\n"))
591 self.ui.warn(_("patch failed, rejects left in working dir\n"))
592 err = 1
592 err = 1
593 break
593 break
594
594
595 if fuzz and strict:
595 if fuzz and strict:
596 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
596 self.ui.warn(_("fuzz found when applying patch, stopping\n"))
597 err = 1
597 err = 1
598 break
598 break
599 return (err, n)
599 return (err, n)
600
600
601 def _clean_series(self, patches):
601 def _clean_series(self, patches):
602 indices = util.sort([self.find_series(p) for p in patches])
602 indices = util.sort([self.find_series(p) for p in patches])
603 for i in indices[-1::-1]:
603 for i in indices[-1::-1]:
604 del self.full_series[i]
604 del self.full_series[i]
605 self.parse_series()
605 self.parse_series()
606 self.series_dirty = 1
606 self.series_dirty = 1
607
607
608 def finish(self, repo, revs):
608 def finish(self, repo, revs):
609 revs.sort()
609 revs.sort()
610 firstrev = repo[self.applied[0].rev].rev()
610 firstrev = repo[self.applied[0].rev].rev()
611 appliedbase = 0
611 appliedbase = 0
612 patches = []
612 patches = []
613 for rev in util.sort(revs):
613 for rev in util.sort(revs):
614 if rev < firstrev:
614 if rev < firstrev:
615 raise util.Abort(_('revision %d is not managed') % rev)
615 raise util.Abort(_('revision %d is not managed') % rev)
616 base = revlog.bin(self.applied[appliedbase].rev)
616 base = revlog.bin(self.applied[appliedbase].rev)
617 node = repo.changelog.node(rev)
617 node = repo.changelog.node(rev)
618 if node != base:
618 if node != base:
619 raise util.Abort(_('cannot delete revision %d above '
619 raise util.Abort(_('cannot delete revision %d above '
620 'applied patches') % rev)
620 'applied patches') % rev)
621 patches.append(self.applied[appliedbase].name)
621 patches.append(self.applied[appliedbase].name)
622 appliedbase += 1
622 appliedbase += 1
623
623
624 r = self.qrepo()
624 r = self.qrepo()
625 if r:
625 if r:
626 r.remove(patches, True)
626 r.remove(patches, True)
627 else:
627 else:
628 for p in patches:
628 for p in patches:
629 os.unlink(self.join(p))
629 os.unlink(self.join(p))
630
630
631 del self.applied[:appliedbase]
631 del self.applied[:appliedbase]
632 self.applied_dirty = 1
632 self.applied_dirty = 1
633 self._clean_series(patches)
633 self._clean_series(patches)
634
634
635 def delete(self, repo, patches, opts):
635 def delete(self, repo, patches, opts):
636 if not patches and not opts.get('rev'):
636 if not patches and not opts.get('rev'):
637 raise util.Abort(_('qdelete requires at least one revision or '
637 raise util.Abort(_('qdelete requires at least one revision or '
638 'patch name'))
638 'patch name'))
639
639
640 realpatches = []
640 realpatches = []
641 for patch in patches:
641 for patch in patches:
642 patch = self.lookup(patch, strict=True)
642 patch = self.lookup(patch, strict=True)
643 info = self.isapplied(patch)
643 info = self.isapplied(patch)
644 if info:
644 if info:
645 raise util.Abort(_("cannot delete applied patch %s") % patch)
645 raise util.Abort(_("cannot delete applied patch %s") % patch)
646 if patch not in self.series:
646 if patch not in self.series:
647 raise util.Abort(_("patch %s not in series file") % patch)
647 raise util.Abort(_("patch %s not in series file") % patch)
648 realpatches.append(patch)
648 realpatches.append(patch)
649
649
650 appliedbase = 0
650 appliedbase = 0
651 if opts.get('rev'):
651 if opts.get('rev'):
652 if not self.applied:
652 if not self.applied:
653 raise util.Abort(_('no patches applied'))
653 raise util.Abort(_('no patches applied'))
654 revs = cmdutil.revrange(repo, opts['rev'])
654 revs = cmdutil.revrange(repo, opts['rev'])
655 if len(revs) > 1 and revs[0] > revs[1]:
655 if len(revs) > 1 and revs[0] > revs[1]:
656 revs.reverse()
656 revs.reverse()
657 for rev in revs:
657 for rev in revs:
658 if appliedbase >= len(self.applied):
658 if appliedbase >= len(self.applied):
659 raise util.Abort(_("revision %d is not managed") % rev)
659 raise util.Abort(_("revision %d is not managed") % rev)
660
660
661 base = revlog.bin(self.applied[appliedbase].rev)
661 base = revlog.bin(self.applied[appliedbase].rev)
662 node = repo.changelog.node(rev)
662 node = repo.changelog.node(rev)
663 if node != base:
663 if node != base:
664 raise util.Abort(_("cannot delete revision %d above "
664 raise util.Abort(_("cannot delete revision %d above "
665 "applied patches") % rev)
665 "applied patches") % rev)
666 realpatches.append(self.applied[appliedbase].name)
666 realpatches.append(self.applied[appliedbase].name)
667 appliedbase += 1
667 appliedbase += 1
668
668
669 if not opts.get('keep'):
669 if not opts.get('keep'):
670 r = self.qrepo()
670 r = self.qrepo()
671 if r:
671 if r:
672 r.remove(realpatches, True)
672 r.remove(realpatches, True)
673 else:
673 else:
674 for p in realpatches:
674 for p in realpatches:
675 os.unlink(self.join(p))
675 os.unlink(self.join(p))
676
676
677 if appliedbase:
677 if appliedbase:
678 del self.applied[:appliedbase]
678 del self.applied[:appliedbase]
679 self.applied_dirty = 1
679 self.applied_dirty = 1
680 self._clean_series(realpatches)
680 self._clean_series(realpatches)
681
681
682 def check_toppatch(self, repo):
682 def check_toppatch(self, repo):
683 if len(self.applied) > 0:
683 if len(self.applied) > 0:
684 top = revlog.bin(self.applied[-1].rev)
684 top = revlog.bin(self.applied[-1].rev)
685 pp = repo.dirstate.parents()
685 pp = repo.dirstate.parents()
686 if top not in pp:
686 if top not in pp:
687 raise util.Abort(_("working directory revision is not qtip"))
687 raise util.Abort(_("working directory revision is not qtip"))
688 return top
688 return top
689 return None
689 return None
690 def check_localchanges(self, repo, force=False, refresh=True):
690 def check_localchanges(self, repo, force=False, refresh=True):
691 m, a, r, d = repo.status()[:4]
691 m, a, r, d = repo.status()[:4]
692 if m or a or r or d:
692 if m or a or r or d:
693 if not force:
693 if not force:
694 if refresh:
694 if refresh:
695 raise util.Abort(_("local changes found, refresh first"))
695 raise util.Abort(_("local changes found, refresh first"))
696 else:
696 else:
697 raise util.Abort(_("local changes found"))
697 raise util.Abort(_("local changes found"))
698 return m, a, r, d
698 return m, a, r, d
699
699
700 _reserved = ('series', 'status', 'guards')
700 _reserved = ('series', 'status', 'guards')
701 def check_reserved_name(self, name):
701 def check_reserved_name(self, name):
702 if (name in self._reserved or name.startswith('.hg')
702 if (name in self._reserved or name.startswith('.hg')
703 or name.startswith('.mq')):
703 or name.startswith('.mq')):
704 raise util.Abort(_('"%s" cannot be used as the name of a patch')
704 raise util.Abort(_('"%s" cannot be used as the name of a patch')
705 % name)
705 % name)
706
706
707 def new(self, repo, patchfn, *pats, **opts):
707 def new(self, repo, patchfn, *pats, **opts):
708 """options:
708 """options:
709 msg: a string or a no-argument function returning a string
709 msg: a string or a no-argument function returning a string
710 """
710 """
711 msg = opts.get('msg')
711 msg = opts.get('msg')
712 force = opts.get('force')
712 force = opts.get('force')
713 user = opts.get('user')
713 user = opts.get('user')
714 date = opts.get('date')
714 date = opts.get('date')
715 if date:
715 if date:
716 date = util.parsedate(date)
716 date = util.parsedate(date)
717 self.check_reserved_name(patchfn)
717 self.check_reserved_name(patchfn)
718 if os.path.exists(self.join(patchfn)):
718 if os.path.exists(self.join(patchfn)):
719 raise util.Abort(_('patch "%s" already exists') % patchfn)
719 raise util.Abort(_('patch "%s" already exists') % patchfn)
720 if opts.get('include') or opts.get('exclude') or pats:
720 if opts.get('include') or opts.get('exclude') or pats:
721 match = cmdutil.match(repo, pats, opts)
721 match = cmdutil.match(repo, pats, opts)
722 # detect missing files in pats
722 # detect missing files in pats
723 def badfn(f, msg):
723 def badfn(f, msg):
724 raise util.Abort('%s: %s' % (f, msg))
724 raise util.Abort('%s: %s' % (f, msg))
725 match.bad = badfn
725 match.bad = badfn
726 m, a, r, d = repo.status(match=match)[:4]
726 m, a, r, d = repo.status(match=match)[:4]
727 else:
727 else:
728 m, a, r, d = self.check_localchanges(repo, force)
728 m, a, r, d = self.check_localchanges(repo, force)
729 match = cmdutil.matchfiles(repo, m + a + r)
729 match = cmdutil.matchfiles(repo, m + a + r)
730 commitfiles = m + a + r
730 commitfiles = m + a + r
731 self.check_toppatch(repo)
731 self.check_toppatch(repo)
732 insert = self.full_series_end()
732 insert = self.full_series_end()
733 wlock = repo.wlock()
733 wlock = repo.wlock()
734 try:
734 try:
735 # if patch file write fails, abort early
735 # if patch file write fails, abort early
736 p = self.opener(patchfn, "w")
736 p = self.opener(patchfn, "w")
737 try:
737 try:
738 if date:
738 if date:
739 p.write("# HG changeset patch\n")
739 p.write("# HG changeset patch\n")
740 if user:
740 if user:
741 p.write("# User " + user + "\n")
741 p.write("# User " + user + "\n")
742 p.write("# Date %d %d\n\n" % date)
742 p.write("# Date %d %d\n\n" % date)
743 elif user:
743 elif user:
744 p.write("From: " + user + "\n\n")
744 p.write("From: " + user + "\n\n")
745
745
746 if callable(msg):
746 if callable(msg):
747 msg = msg()
747 msg = msg()
748 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
748 commitmsg = msg and msg or ("[mq]: %s" % patchfn)
749 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
749 n = repo.commit(commitfiles, commitmsg, user, date, match=match, force=True)
750 if n == None:
750 if n == None:
751 raise util.Abort(_("repo commit failed"))
751 raise util.Abort(_("repo commit failed"))
752 try:
752 try:
753 self.full_series[insert:insert] = [patchfn]
753 self.full_series[insert:insert] = [patchfn]
754 self.applied.append(statusentry(revlog.hex(n), patchfn))
754 self.applied.append(statusentry(revlog.hex(n), patchfn))
755 self.parse_series()
755 self.parse_series()
756 self.series_dirty = 1
756 self.series_dirty = 1
757 self.applied_dirty = 1
757 self.applied_dirty = 1
758 if msg:
758 if msg:
759 msg = msg + "\n"
759 msg = msg + "\n"
760 p.write(msg)
760 p.write(msg)
761 if commitfiles:
761 if commitfiles:
762 diffopts = self.diffopts()
762 diffopts = self.diffopts()
763 if opts.get('git'): diffopts.git = True
763 if opts.get('git'): diffopts.git = True
764 parent = self.qparents(repo, n)
764 parent = self.qparents(repo, n)
765 chunks = patch.diff(repo, node1=parent, node2=n,
765 chunks = patch.diff(repo, node1=parent, node2=n,
766 match=match, opts=diffopts)
766 match=match, opts=diffopts)
767 for chunk in chunks:
767 for chunk in chunks:
768 p.write(chunk)
768 p.write(chunk)
769 p.close()
769 p.close()
770 wlock = None
770 wlock = None
771 r = self.qrepo()
771 r = self.qrepo()
772 if r: r.add([patchfn])
772 if r: r.add([patchfn])
773 except:
773 except:
774 repo.rollback()
774 repo.rollback()
775 raise
775 raise
776 except Exception:
776 except Exception:
777 patchpath = self.join(patchfn)
777 patchpath = self.join(patchfn)
778 try:
778 try:
779 os.unlink(patchpath)
779 os.unlink(patchpath)
780 except:
780 except:
781 self.ui.warn(_('error unlinking %s\n') % patchpath)
781 self.ui.warn(_('error unlinking %s\n') % patchpath)
782 raise
782 raise
783 self.removeundo(repo)
783 self.removeundo(repo)
784 finally:
784 finally:
785 del wlock
785 del wlock
786
786
787 def strip(self, repo, rev, update=True, backup="all", force=None):
787 def strip(self, repo, rev, update=True, backup="all", force=None):
788 wlock = lock = None
788 wlock = lock = None
789 try:
789 try:
790 wlock = repo.wlock()
790 wlock = repo.wlock()
791 lock = repo.lock()
791 lock = repo.lock()
792
792
793 if update:
793 if update:
794 self.check_localchanges(repo, force=force, refresh=False)
794 self.check_localchanges(repo, force=force, refresh=False)
795 urev = self.qparents(repo, rev)
795 urev = self.qparents(repo, rev)
796 hg.clean(repo, urev)
796 hg.clean(repo, urev)
797 repo.dirstate.write()
797 repo.dirstate.write()
798
798
799 self.removeundo(repo)
799 self.removeundo(repo)
800 repair.strip(self.ui, repo, rev, backup)
800 repair.strip(self.ui, repo, rev, backup)
801 # strip may have unbundled a set of backed up revisions after
801 # strip may have unbundled a set of backed up revisions after
802 # the actual strip
802 # the actual strip
803 self.removeundo(repo)
803 self.removeundo(repo)
804 finally:
804 finally:
805 del lock, wlock
805 del lock, wlock
806
806
807 def isapplied(self, patch):
807 def isapplied(self, patch):
808 """returns (index, rev, patch)"""
808 """returns (index, rev, patch)"""
809 for i in xrange(len(self.applied)):
809 for i in xrange(len(self.applied)):
810 a = self.applied[i]
810 a = self.applied[i]
811 if a.name == patch:
811 if a.name == patch:
812 return (i, a.rev, a.name)
812 return (i, a.rev, a.name)
813 return None
813 return None
814
814
815 # if the exact patch name does not exist, we try a few
815 # if the exact patch name does not exist, we try a few
816 # variations. If strict is passed, we try only #1
816 # variations. If strict is passed, we try only #1
817 #
817 #
818 # 1) a number to indicate an offset in the series file
818 # 1) a number to indicate an offset in the series file
819 # 2) a unique substring of the patch name was given
819 # 2) a unique substring of the patch name was given
820 # 3) patchname[-+]num to indicate an offset in the series file
820 # 3) patchname[-+]num to indicate an offset in the series file
821 def lookup(self, patch, strict=False):
821 def lookup(self, patch, strict=False):
822 patch = patch and str(patch)
822 patch = patch and str(patch)
823
823
824 def partial_name(s):
824 def partial_name(s):
825 if s in self.series:
825 if s in self.series:
826 return s
826 return s
827 matches = [x for x in self.series if s in x]
827 matches = [x for x in self.series if s in x]
828 if len(matches) > 1:
828 if len(matches) > 1:
829 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
829 self.ui.warn(_('patch name "%s" is ambiguous:\n') % s)
830 for m in matches:
830 for m in matches:
831 self.ui.warn(' %s\n' % m)
831 self.ui.warn(' %s\n' % m)
832 return None
832 return None
833 if matches:
833 if matches:
834 return matches[0]
834 return matches[0]
835 if len(self.series) > 0 and len(self.applied) > 0:
835 if len(self.series) > 0 and len(self.applied) > 0:
836 if s == 'qtip':
836 if s == 'qtip':
837 return self.series[self.series_end(True)-1]
837 return self.series[self.series_end(True)-1]
838 if s == 'qbase':
838 if s == 'qbase':
839 return self.series[0]
839 return self.series[0]
840 return None
840 return None
841 if patch == None:
841 if patch == None:
842 return None
842 return None
843
843
844 # we don't want to return a partial match until we make
844 # we don't want to return a partial match until we make
845 # sure the file name passed in does not exist (checked below)
845 # sure the file name passed in does not exist (checked below)
846 res = partial_name(patch)
846 res = partial_name(patch)
847 if res and res == patch:
847 if res and res == patch:
848 return res
848 return res
849
849
850 if not os.path.isfile(self.join(patch)):
850 if not os.path.isfile(self.join(patch)):
851 try:
851 try:
852 sno = int(patch)
852 sno = int(patch)
853 except(ValueError, OverflowError):
853 except(ValueError, OverflowError):
854 pass
854 pass
855 else:
855 else:
856 if sno < len(self.series):
856 if sno < len(self.series):
857 return self.series[sno]
857 return self.series[sno]
858 if not strict:
858 if not strict:
859 # return any partial match made above
859 # return any partial match made above
860 if res:
860 if res:
861 return res
861 return res
862 minus = patch.rfind('-')
862 minus = patch.rfind('-')
863 if minus >= 0:
863 if minus >= 0:
864 res = partial_name(patch[:minus])
864 res = partial_name(patch[:minus])
865 if res:
865 if res:
866 i = self.series.index(res)
866 i = self.series.index(res)
867 try:
867 try:
868 off = int(patch[minus+1:] or 1)
868 off = int(patch[minus+1:] or 1)
869 except(ValueError, OverflowError):
869 except(ValueError, OverflowError):
870 pass
870 pass
871 else:
871 else:
872 if i - off >= 0:
872 if i - off >= 0:
873 return self.series[i - off]
873 return self.series[i - off]
874 plus = patch.rfind('+')
874 plus = patch.rfind('+')
875 if plus >= 0:
875 if plus >= 0:
876 res = partial_name(patch[:plus])
876 res = partial_name(patch[:plus])
877 if res:
877 if res:
878 i = self.series.index(res)
878 i = self.series.index(res)
879 try:
879 try:
880 off = int(patch[plus+1:] or 1)
880 off = int(patch[plus+1:] or 1)
881 except(ValueError, OverflowError):
881 except(ValueError, OverflowError):
882 pass
882 pass
883 else:
883 else:
884 if i + off < len(self.series):
884 if i + off < len(self.series):
885 return self.series[i + off]
885 return self.series[i + off]
886 raise util.Abort(_("patch %s not in series") % patch)
886 raise util.Abort(_("patch %s not in series") % patch)
887
887
888 def push(self, repo, patch=None, force=False, list=False,
888 def push(self, repo, patch=None, force=False, list=False,
889 mergeq=None, all=False):
889 mergeq=None, all=False):
890 wlock = repo.wlock()
890 wlock = repo.wlock()
891 if repo.dirstate.parents()[0] != repo.changelog.tip():
891 if repo.dirstate.parents()[0] != repo.changelog.tip():
892 self.ui.status(_("(working directory not at tip)\n"))
892 self.ui.status(_("(working directory not at tip)\n"))
893
893
894 if not self.series:
894 if not self.series:
895 self.ui.warn(_('no patches in series\n'))
895 self.ui.warn(_('no patches in series\n'))
896 return 0
896 return 0
897
897
898 try:
898 try:
899 patch = self.lookup(patch)
899 patch = self.lookup(patch)
900 # Suppose our series file is: A B C and the current 'top'
900 # Suppose our series file is: A B C and the current 'top'
901 # patch is B. qpush C should be performed (moving forward)
901 # patch is B. qpush C should be performed (moving forward)
902 # qpush B is a NOP (no change) qpush A is an error (can't
902 # qpush B is a NOP (no change) qpush A is an error (can't
903 # go backwards with qpush)
903 # go backwards with qpush)
904 if patch:
904 if patch:
905 info = self.isapplied(patch)
905 info = self.isapplied(patch)
906 if info:
906 if info:
907 if info[0] < len(self.applied) - 1:
907 if info[0] < len(self.applied) - 1:
908 raise util.Abort(
908 raise util.Abort(
909 _("cannot push to a previous patch: %s") % patch)
909 _("cannot push to a previous patch: %s") % patch)
910 self.ui.warn(
910 self.ui.warn(
911 _('qpush: %s is already at the top\n') % patch)
911 _('qpush: %s is already at the top\n') % patch)
912 return
912 return
913 pushable, reason = self.pushable(patch)
913 pushable, reason = self.pushable(patch)
914 if not pushable:
914 if not pushable:
915 if reason:
915 if reason:
916 reason = _('guarded by %r') % reason
916 reason = _('guarded by %r') % reason
917 else:
917 else:
918 reason = _('no matching guards')
918 reason = _('no matching guards')
919 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
919 self.ui.warn(_("cannot push '%s' - %s\n") % (patch, reason))
920 return 1
920 return 1
921 elif all:
921 elif all:
922 patch = self.series[-1]
922 patch = self.series[-1]
923 if self.isapplied(patch):
923 if self.isapplied(patch):
924 self.ui.warn(_('all patches are currently applied\n'))
924 self.ui.warn(_('all patches are currently applied\n'))
925 return 0
925 return 0
926
926
927 # Following the above example, starting at 'top' of B:
927 # Following the above example, starting at 'top' of B:
928 # qpush should be performed (pushes C), but a subsequent
928 # qpush should be performed (pushes C), but a subsequent
929 # qpush without an argument is an error (nothing to
929 # qpush without an argument is an error (nothing to
930 # apply). This allows a loop of "...while hg qpush..." to
930 # apply). This allows a loop of "...while hg qpush..." to
931 # work as it detects an error when done
931 # work as it detects an error when done
932 start = self.series_end()
932 start = self.series_end()
933 if start == len(self.series):
933 if start == len(self.series):
934 self.ui.warn(_('patch series already fully applied\n'))
934 self.ui.warn(_('patch series already fully applied\n'))
935 return 1
935 return 1
936 if not force:
936 if not force:
937 self.check_localchanges(repo)
937 self.check_localchanges(repo)
938
938
939 self.applied_dirty = 1
939 self.applied_dirty = 1
940 if start > 0:
940 if start > 0:
941 self.check_toppatch(repo)
941 self.check_toppatch(repo)
942 if not patch:
942 if not patch:
943 patch = self.series[start]
943 patch = self.series[start]
944 end = start + 1
944 end = start + 1
945 else:
945 else:
946 end = self.series.index(patch, start) + 1
946 end = self.series.index(patch, start) + 1
947 s = self.series[start:end]
947 s = self.series[start:end]
948 all_files = {}
948 all_files = {}
949 try:
949 try:
950 if mergeq:
950 if mergeq:
951 ret = self.mergepatch(repo, mergeq, s)
951 ret = self.mergepatch(repo, mergeq, s)
952 else:
952 else:
953 ret = self.apply(repo, s, list, all_files=all_files)
953 ret = self.apply(repo, s, list, all_files=all_files)
954 except:
954 except:
955 self.ui.warn(_('cleaning up working directory...'))
955 self.ui.warn(_('cleaning up working directory...'))
956 node = repo.dirstate.parents()[0]
956 node = repo.dirstate.parents()[0]
957 hg.revert(repo, node, None)
957 hg.revert(repo, node, None)
958 unknown = repo.status(unknown=True)[4]
958 unknown = repo.status(unknown=True)[4]
959 # only remove unknown files that we know we touched or
959 # only remove unknown files that we know we touched or
960 # created while patching
960 # created while patching
961 for f in unknown:
961 for f in unknown:
962 if f in all_files:
962 if f in all_files:
963 util.unlink(repo.wjoin(f))
963 util.unlink(repo.wjoin(f))
964 self.ui.warn(_('done\n'))
964 self.ui.warn(_('done\n'))
965 raise
965 raise
966 top = self.applied[-1].name
966 top = self.applied[-1].name
967 if ret[0]:
967 if ret[0]:
968 self.ui.write(_("Errors during apply, please fix and "
968 self.ui.write(_("Errors during apply, please fix and "
969 "refresh %s\n") % top)
969 "refresh %s\n") % top)
970 else:
970 else:
971 self.ui.write(_("Now at: %s\n") % top)
971 self.ui.write(_("Now at: %s\n") % top)
972 return ret[0]
972 return ret[0]
973 finally:
973 finally:
974 del wlock
974 del wlock
975
975
976 def pop(self, repo, patch=None, force=False, update=True, all=False):
976 def pop(self, repo, patch=None, force=False, update=True, all=False):
977 def getfile(f, rev, flags):
977 def getfile(f, rev, flags):
978 t = repo.file(f).read(rev)
978 t = repo.file(f).read(rev)
979 repo.wwrite(f, t, flags)
979 repo.wwrite(f, t, flags)
980
980
981 wlock = repo.wlock()
981 wlock = repo.wlock()
982 try:
982 try:
983 if patch:
983 if patch:
984 # index, rev, patch
984 # index, rev, patch
985 info = self.isapplied(patch)
985 info = self.isapplied(patch)
986 if not info:
986 if not info:
987 patch = self.lookup(patch)
987 patch = self.lookup(patch)
988 info = self.isapplied(patch)
988 info = self.isapplied(patch)
989 if not info:
989 if not info:
990 raise util.Abort(_("patch %s is not applied") % patch)
990 raise util.Abort(_("patch %s is not applied") % patch)
991
991
992 if len(self.applied) == 0:
992 if len(self.applied) == 0:
993 # Allow qpop -a to work repeatedly,
993 # Allow qpop -a to work repeatedly,
994 # but not qpop without an argument
994 # but not qpop without an argument
995 self.ui.warn(_("no patches applied\n"))
995 self.ui.warn(_("no patches applied\n"))
996 return not all
996 return not all
997
997
998 if not update:
998 if not update:
999 parents = repo.dirstate.parents()
999 parents = repo.dirstate.parents()
1000 rr = [ revlog.bin(x.rev) for x in self.applied ]
1000 rr = [ revlog.bin(x.rev) for x in self.applied ]
1001 for p in parents:
1001 for p in parents:
1002 if p in rr:
1002 if p in rr:
1003 self.ui.warn(_("qpop: forcing dirstate update\n"))
1003 self.ui.warn(_("qpop: forcing dirstate update\n"))
1004 update = True
1004 update = True
1005
1005
1006 if not force and update:
1006 if not force and update:
1007 self.check_localchanges(repo)
1007 self.check_localchanges(repo)
1008
1008
1009 self.applied_dirty = 1;
1009 self.applied_dirty = 1;
1010 end = len(self.applied)
1010 end = len(self.applied)
1011 if not patch:
1011 if not patch:
1012 if all:
1012 if all:
1013 popi = 0
1013 popi = 0
1014 else:
1014 else:
1015 popi = len(self.applied) - 1
1015 popi = len(self.applied) - 1
1016 else:
1016 else:
1017 popi = info[0] + 1
1017 popi = info[0] + 1
1018 if popi >= end:
1018 if popi >= end:
1019 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1019 self.ui.warn(_("qpop: %s is already at the top\n") % patch)
1020 return
1020 return
1021 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
1021 info = [ popi ] + [self.applied[popi].rev, self.applied[popi].name]
1022
1022
1023 start = info[0]
1023 start = info[0]
1024 rev = revlog.bin(info[1])
1024 rev = revlog.bin(info[1])
1025
1025
1026 if update:
1026 if update:
1027 top = self.check_toppatch(repo)
1027 top = self.check_toppatch(repo)
1028
1028
1029 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
1029 if repo.changelog.heads(rev) != [revlog.bin(self.applied[-1].rev)]:
1030 raise util.Abort(_("popping would remove a revision not "
1030 raise util.Abort(_("popping would remove a revision not "
1031 "managed by this patch queue"))
1031 "managed by this patch queue"))
1032
1032
1033 # we know there are no local changes, so we can make a simplified
1033 # we know there are no local changes, so we can make a simplified
1034 # form of hg.update.
1034 # form of hg.update.
1035 if update:
1035 if update:
1036 qp = self.qparents(repo, rev)
1036 qp = self.qparents(repo, rev)
1037 changes = repo.changelog.read(qp)
1037 changes = repo.changelog.read(qp)
1038 mmap = repo.manifest.read(changes[0])
1038 mmap = repo.manifest.read(changes[0])
1039 m, a, r, d = repo.status(qp, top)[:4]
1039 m, a, r, d = repo.status(qp, top)[:4]
1040 if d:
1040 if d:
1041 raise util.Abort(_("deletions found between repo revs"))
1041 raise util.Abort(_("deletions found between repo revs"))
1042 for f in m:
1042 for f in m:
1043 getfile(f, mmap[f], mmap.flags(f))
1043 getfile(f, mmap[f], mmap.flags(f))
1044 for f in r:
1044 for f in r:
1045 getfile(f, mmap[f], mmap.flags(f))
1045 getfile(f, mmap[f], mmap.flags(f))
1046 for f in m + r:
1046 for f in m + r:
1047 repo.dirstate.normal(f)
1047 repo.dirstate.normal(f)
1048 for f in a:
1048 for f in a:
1049 try:
1049 try:
1050 os.unlink(repo.wjoin(f))
1050 os.unlink(repo.wjoin(f))
1051 except OSError, e:
1051 except OSError, e:
1052 if e.errno != errno.ENOENT:
1052 if e.errno != errno.ENOENT:
1053 raise
1053 raise
1054 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
1054 try: os.removedirs(os.path.dirname(repo.wjoin(f)))
1055 except: pass
1055 except: pass
1056 repo.dirstate.forget(f)
1056 repo.dirstate.forget(f)
1057 repo.dirstate.setparents(qp, revlog.nullid)
1057 repo.dirstate.setparents(qp, revlog.nullid)
1058 del self.applied[start:end]
1058 del self.applied[start:end]
1059 self.strip(repo, rev, update=False, backup='strip')
1059 self.strip(repo, rev, update=False, backup='strip')
1060 if len(self.applied):
1060 if len(self.applied):
1061 self.ui.write(_("Now at: %s\n") % self.applied[-1].name)
1061 self.ui.write(_("Now at: %s\n") % self.applied[-1].name)
1062 else:
1062 else:
1063 self.ui.write(_("Patch queue now empty\n"))
1063 self.ui.write(_("Patch queue now empty\n"))
1064 finally:
1064 finally:
1065 del wlock
1065 del wlock
1066
1066
1067 def diff(self, repo, pats, opts):
1067 def diff(self, repo, pats, opts):
1068 top = self.check_toppatch(repo)
1068 top = self.check_toppatch(repo)
1069 if not top:
1069 if not top:
1070 self.ui.write(_("No patches applied\n"))
1070 self.ui.write(_("No patches applied\n"))
1071 return
1071 return
1072 qp = self.qparents(repo, top)
1072 qp = self.qparents(repo, top)
1073 self._diffopts = patch.diffopts(self.ui, opts)
1073 self._diffopts = patch.diffopts(self.ui, opts)
1074 self.printdiff(repo, qp, files=pats, opts=opts)
1074 self.printdiff(repo, qp, files=pats, opts=opts)
1075
1075
1076 def refresh(self, repo, pats=None, **opts):
1076 def refresh(self, repo, pats=None, **opts):
1077 if len(self.applied) == 0:
1077 if len(self.applied) == 0:
1078 self.ui.write(_("No patches applied\n"))
1078 self.ui.write(_("No patches applied\n"))
1079 return 1
1079 return 1
1080 msg = opts.get('msg', '').rstrip()
1080 msg = opts.get('msg', '').rstrip()
1081 newuser = opts.get('user')
1081 newuser = opts.get('user')
1082 newdate = opts.get('date')
1082 newdate = opts.get('date')
1083 if newdate:
1083 if newdate:
1084 newdate = '%d %d' % util.parsedate(newdate)
1084 newdate = '%d %d' % util.parsedate(newdate)
1085 wlock = repo.wlock()
1085 wlock = repo.wlock()
1086 try:
1086 try:
1087 self.check_toppatch(repo)
1087 self.check_toppatch(repo)
1088 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1088 (top, patchfn) = (self.applied[-1].rev, self.applied[-1].name)
1089 top = revlog.bin(top)
1089 top = revlog.bin(top)
1090 if repo.changelog.heads(top) != [top]:
1090 if repo.changelog.heads(top) != [top]:
1091 raise util.Abort(_("cannot refresh a revision with children"))
1091 raise util.Abort(_("cannot refresh a revision with children"))
1092 cparents = repo.changelog.parents(top)
1092 cparents = repo.changelog.parents(top)
1093 patchparent = self.qparents(repo, top)
1093 patchparent = self.qparents(repo, top)
1094 ph = self.readheaders(patchfn)
1094 ph = self.readheaders(patchfn)
1095
1095
1096 patchf = self.opener(patchfn, 'r')
1096 patchf = self.opener(patchfn, 'r')
1097
1097
1098 # if the patch was a git patch, refresh it as a git patch
1098 # if the patch was a git patch, refresh it as a git patch
1099 for line in patchf:
1099 for line in patchf:
1100 if line.startswith('diff --git'):
1100 if line.startswith('diff --git'):
1101 self.diffopts().git = True
1101 self.diffopts().git = True
1102 break
1102 break
1103
1103
1104 if msg:
1104 if msg:
1105 ph.setmessage(msg)
1105 ph.setmessage(msg)
1106 if newuser:
1106 if newuser:
1107 ph.setuser(newuser)
1107 ph.setuser(newuser)
1108 if newdate:
1108 if newdate:
1109 ph.setdate(newdate)
1109 ph.setdate(newdate)
1110
1110
1111 # only commit new patch when write is complete
1111 # only commit new patch when write is complete
1112 patchf = self.opener(patchfn, 'w', atomictemp=True)
1112 patchf = self.opener(patchfn, 'w', atomictemp=True)
1113
1113
1114 patchf.seek(0)
1114 patchf.seek(0)
1115 patchf.truncate()
1115 patchf.truncate()
1116
1116
1117 comments = str(ph)
1117 comments = str(ph)
1118 if comments:
1118 if comments:
1119 patchf.write(comments)
1119 patchf.write(comments)
1120
1120
1121 if opts.get('git'):
1121 if opts.get('git'):
1122 self.diffopts().git = True
1122 self.diffopts().git = True
1123 tip = repo.changelog.tip()
1123 tip = repo.changelog.tip()
1124 if top == tip:
1124 if top == tip:
1125 # if the top of our patch queue is also the tip, there is an
1125 # if the top of our patch queue is also the tip, there is an
1126 # optimization here. We update the dirstate in place and strip
1126 # optimization here. We update the dirstate in place and strip
1127 # off the tip commit. Then just commit the current directory
1127 # off the tip commit. Then just commit the current directory
1128 # tree. We can also send repo.commit the list of files
1128 # tree. We can also send repo.commit the list of files
1129 # changed to speed up the diff
1129 # changed to speed up the diff
1130 #
1130 #
1131 # in short mode, we only diff the files included in the
1131 # in short mode, we only diff the files included in the
1132 # patch already plus specified files
1132 # patch already plus specified files
1133 #
1133 #
1134 # this should really read:
1134 # this should really read:
1135 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1135 # mm, dd, aa, aa2 = repo.status(tip, patchparent)[:4]
1136 # but we do it backwards to take advantage of manifest/chlog
1136 # but we do it backwards to take advantage of manifest/chlog
1137 # caching against the next repo.status call
1137 # caching against the next repo.status call
1138 #
1138 #
1139 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1139 mm, aa, dd, aa2 = repo.status(patchparent, tip)[:4]
1140 changes = repo.changelog.read(tip)
1140 changes = repo.changelog.read(tip)
1141 man = repo.manifest.read(changes[0])
1141 man = repo.manifest.read(changes[0])
1142 aaa = aa[:]
1142 aaa = aa[:]
1143 matchfn = cmdutil.match(repo, pats, opts)
1143 matchfn = cmdutil.match(repo, pats, opts)
1144 if opts.get('short'):
1144 if opts.get('short'):
1145 # if amending a patch, we start with existing
1145 # if amending a patch, we start with existing
1146 # files plus specified files - unfiltered
1146 # files plus specified files - unfiltered
1147 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1147 match = cmdutil.matchfiles(repo, mm + aa + dd + matchfn.files())
1148 # filter with inc/exl options
1148 # filter with inc/exl options
1149 matchfn = cmdutil.match(repo, opts=opts)
1149 matchfn = cmdutil.match(repo, opts=opts)
1150 else:
1150 else:
1151 match = cmdutil.matchall(repo)
1151 match = cmdutil.matchall(repo)
1152 m, a, r, d = repo.status(match=match)[:4]
1152 m, a, r, d = repo.status(match=match)[:4]
1153
1153
1154 # we might end up with files that were added between
1154 # we might end up with files that were added between
1155 # tip and the dirstate parent, but then changed in the
1155 # tip and the dirstate parent, but then changed in the
1156 # local dirstate. in this case, we want them to only
1156 # local dirstate. in this case, we want them to only
1157 # show up in the added section
1157 # show up in the added section
1158 for x in m:
1158 for x in m:
1159 if x not in aa:
1159 if x not in aa:
1160 mm.append(x)
1160 mm.append(x)
1161 # we might end up with files added by the local dirstate that
1161 # we might end up with files added by the local dirstate that
1162 # were deleted by the patch. In this case, they should only
1162 # were deleted by the patch. In this case, they should only
1163 # show up in the changed section.
1163 # show up in the changed section.
1164 for x in a:
1164 for x in a:
1165 if x in dd:
1165 if x in dd:
1166 del dd[dd.index(x)]
1166 del dd[dd.index(x)]
1167 mm.append(x)
1167 mm.append(x)
1168 else:
1168 else:
1169 aa.append(x)
1169 aa.append(x)
1170 # make sure any files deleted in the local dirstate
1170 # make sure any files deleted in the local dirstate
1171 # are not in the add or change column of the patch
1171 # are not in the add or change column of the patch
1172 forget = []
1172 forget = []
1173 for x in d + r:
1173 for x in d + r:
1174 if x in aa:
1174 if x in aa:
1175 del aa[aa.index(x)]
1175 del aa[aa.index(x)]
1176 forget.append(x)
1176 forget.append(x)
1177 continue
1177 continue
1178 elif x in mm:
1178 elif x in mm:
1179 del mm[mm.index(x)]
1179 del mm[mm.index(x)]
1180 dd.append(x)
1180 dd.append(x)
1181
1181
1182 m = util.unique(mm)
1182 m = util.unique(mm)
1183 r = util.unique(dd)
1183 r = util.unique(dd)
1184 a = util.unique(aa)
1184 a = util.unique(aa)
1185 c = [filter(matchfn, l) for l in (m, a, r)]
1185 c = [filter(matchfn, l) for l in (m, a, r)]
1186 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1186 match = cmdutil.matchfiles(repo, util.unique(c[0] + c[1] + c[2]))
1187 chunks = patch.diff(repo, patchparent, match=match,
1187 chunks = patch.diff(repo, patchparent, match=match,
1188 changes=c, opts=self.diffopts())
1188 changes=c, opts=self.diffopts())
1189 for chunk in chunks:
1189 for chunk in chunks:
1190 patchf.write(chunk)
1190 patchf.write(chunk)
1191
1191
1192 try:
1192 try:
1193 copies = {}
1193 copies = {}
1194 for dst in a:
1194 for dst in a:
1195 src = repo.dirstate.copied(dst)
1195 src = repo.dirstate.copied(dst)
1196 # during qfold, the source file for copies may
1196 # during qfold, the source file for copies may
1197 # be removed. Treat this as a simple add.
1197 # be removed. Treat this as a simple add.
1198 if src is not None and src in repo.dirstate:
1198 if src is not None and src in repo.dirstate:
1199 copies.setdefault(src, []).append(dst)
1199 copies.setdefault(src, []).append(dst)
1200 repo.dirstate.add(dst)
1200 repo.dirstate.add(dst)
1201 # remember the copies between patchparent and tip
1201 # remember the copies between patchparent and tip
1202 # this may be slow, so don't do it if we're not tracking copies
1202 # this may be slow, so don't do it if we're not tracking copies
1203 if self.diffopts().git:
1203 if self.diffopts().git:
1204 for dst in aaa:
1204 for dst in aaa:
1205 f = repo.file(dst)
1205 f = repo.file(dst)
1206 src = f.renamed(man[dst])
1206 src = f.renamed(man[dst])
1207 if src:
1207 if src:
1208 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1208 copies.setdefault(src[0], []).extend(copies.get(dst, []))
1209 if dst in a:
1209 if dst in a:
1210 copies[src[0]].append(dst)
1210 copies[src[0]].append(dst)
1211 # we can't copy a file created by the patch itself
1211 # we can't copy a file created by the patch itself
1212 if dst in copies:
1212 if dst in copies:
1213 del copies[dst]
1213 del copies[dst]
1214 for src, dsts in copies.iteritems():
1214 for src, dsts in copies.iteritems():
1215 for dst in dsts:
1215 for dst in dsts:
1216 repo.dirstate.copy(src, dst)
1216 repo.dirstate.copy(src, dst)
1217 for f in r:
1217 for f in r:
1218 repo.dirstate.remove(f)
1218 repo.dirstate.remove(f)
1219 # if the patch excludes a modified file, mark that
1219 # if the patch excludes a modified file, mark that
1220 # file with mtime=0 so status can see it.
1220 # file with mtime=0 so status can see it.
1221 mm = []
1221 mm = []
1222 for i in xrange(len(m)-1, -1, -1):
1222 for i in xrange(len(m)-1, -1, -1):
1223 if not matchfn(m[i]):
1223 if not matchfn(m[i]):
1224 mm.append(m[i])
1224 mm.append(m[i])
1225 del m[i]
1225 del m[i]
1226 for f in m:
1226 for f in m:
1227 repo.dirstate.normal(f)
1227 repo.dirstate.normal(f)
1228 for f in mm:
1228 for f in mm:
1229 repo.dirstate.normallookup(f)
1229 repo.dirstate.normallookup(f)
1230 for f in forget:
1230 for f in forget:
1231 repo.dirstate.forget(f)
1231 repo.dirstate.forget(f)
1232
1232
1233 if not msg:
1233 if not msg:
1234 if not ph.message:
1234 if not ph.message:
1235 message = "[mq]: %s\n" % patchfn
1235 message = "[mq]: %s\n" % patchfn
1236 else:
1236 else:
1237 message = "\n".join(ph.message)
1237 message = "\n".join(ph.message)
1238 else:
1238 else:
1239 message = msg
1239 message = msg
1240
1240
1241 user = ph.user or changes[1]
1241 user = ph.user or changes[1]
1242
1242
1243 # assumes strip can roll itself back if interrupted
1243 # assumes strip can roll itself back if interrupted
1244 repo.dirstate.setparents(*cparents)
1244 repo.dirstate.setparents(*cparents)
1245 self.applied.pop()
1245 self.applied.pop()
1246 self.applied_dirty = 1
1246 self.applied_dirty = 1
1247 self.strip(repo, top, update=False,
1247 self.strip(repo, top, update=False,
1248 backup='strip')
1248 backup='strip')
1249 except:
1249 except:
1250 repo.dirstate.invalidate()
1250 repo.dirstate.invalidate()
1251 raise
1251 raise
1252
1252
1253 try:
1253 try:
1254 # might be nice to attempt to roll back strip after this
1254 # might be nice to attempt to roll back strip after this
1255 patchf.rename()
1255 patchf.rename()
1256 n = repo.commit(match.files(), message, user, ph.date,
1256 n = repo.commit(match.files(), message, user, ph.date,
1257 match=match, force=1)
1257 match=match, force=1)
1258 self.applied.append(statusentry(revlog.hex(n), patchfn))
1258 self.applied.append(statusentry(revlog.hex(n), patchfn))
1259 except:
1259 except:
1260 ctx = repo[cparents[0]]
1260 ctx = repo[cparents[0]]
1261 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1261 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1262 self.save_dirty()
1262 self.save_dirty()
1263 self.ui.warn(_('refresh interrupted while patch was popped! '
1263 self.ui.warn(_('refresh interrupted while patch was popped! '
1264 '(revert --all, qpush to recover)\n'))
1264 '(revert --all, qpush to recover)\n'))
1265 raise
1265 raise
1266 else:
1266 else:
1267 self.printdiff(repo, patchparent, fp=patchf)
1267 self.printdiff(repo, patchparent, fp=patchf)
1268 patchf.rename()
1268 patchf.rename()
1269 added = repo.status()[1]
1269 added = repo.status()[1]
1270 for a in added:
1270 for a in added:
1271 f = repo.wjoin(a)
1271 f = repo.wjoin(a)
1272 try:
1272 try:
1273 os.unlink(f)
1273 os.unlink(f)
1274 except OSError, e:
1274 except OSError, e:
1275 if e.errno != errno.ENOENT:
1275 if e.errno != errno.ENOENT:
1276 raise
1276 raise
1277 try: os.removedirs(os.path.dirname(f))
1277 try: os.removedirs(os.path.dirname(f))
1278 except: pass
1278 except: pass
1279 # forget the file copies in the dirstate
1279 # forget the file copies in the dirstate
1280 # push should readd the files later on
1280 # push should readd the files later on
1281 repo.dirstate.forget(a)
1281 repo.dirstate.forget(a)
1282 self.pop(repo, force=True)
1282 self.pop(repo, force=True)
1283 self.push(repo, force=True)
1283 self.push(repo, force=True)
1284 finally:
1284 finally:
1285 del wlock
1285 del wlock
1286 self.removeundo(repo)
1286 self.removeundo(repo)
1287
1287
1288 def init(self, repo, create=False):
1288 def init(self, repo, create=False):
1289 if not create and os.path.isdir(self.path):
1289 if not create and os.path.isdir(self.path):
1290 raise util.Abort(_("patch queue directory already exists"))
1290 raise util.Abort(_("patch queue directory already exists"))
1291 try:
1291 try:
1292 os.mkdir(self.path)
1292 os.mkdir(self.path)
1293 except OSError, inst:
1293 except OSError, inst:
1294 if inst.errno != errno.EEXIST or not create:
1294 if inst.errno != errno.EEXIST or not create:
1295 raise
1295 raise
1296 if create:
1296 if create:
1297 return self.qrepo(create=True)
1297 return self.qrepo(create=True)
1298
1298
1299 def unapplied(self, repo, patch=None):
1299 def unapplied(self, repo, patch=None):
1300 if patch and patch not in self.series:
1300 if patch and patch not in self.series:
1301 raise util.Abort(_("patch %s is not in series file") % patch)
1301 raise util.Abort(_("patch %s is not in series file") % patch)
1302 if not patch:
1302 if not patch:
1303 start = self.series_end()
1303 start = self.series_end()
1304 else:
1304 else:
1305 start = self.series.index(patch) + 1
1305 start = self.series.index(patch) + 1
1306 unapplied = []
1306 unapplied = []
1307 for i in xrange(start, len(self.series)):
1307 for i in xrange(start, len(self.series)):
1308 pushable, reason = self.pushable(i)
1308 pushable, reason = self.pushable(i)
1309 if pushable:
1309 if pushable:
1310 unapplied.append((i, self.series[i]))
1310 unapplied.append((i, self.series[i]))
1311 self.explain_pushable(i)
1311 self.explain_pushable(i)
1312 return unapplied
1312 return unapplied
1313
1313
1314 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1314 def qseries(self, repo, missing=None, start=0, length=None, status=None,
1315 summary=False):
1315 summary=False):
1316 def displayname(patchname):
1316 def displayname(patchname):
1317 if summary:
1317 if summary:
1318 ph = self.readheaders(patchname)
1318 ph = self.readheaders(patchname)
1319 msg = ph.message
1319 msg = ph.message
1320 msg = msg and ': ' + msg[0] or ': '
1320 msg = msg and ': ' + msg[0] or ': '
1321 else:
1321 else:
1322 msg = ''
1322 msg = ''
1323 return '%s%s' % (patchname, msg)
1323 return '%s%s' % (patchname, msg)
1324
1324
1325 applied = dict.fromkeys([p.name for p in self.applied])
1325 applied = dict.fromkeys([p.name for p in self.applied])
1326 if length is None:
1326 if length is None:
1327 length = len(self.series) - start
1327 length = len(self.series) - start
1328 if not missing:
1328 if not missing:
1329 for i in xrange(start, start+length):
1329 for i in xrange(start, start+length):
1330 patch = self.series[i]
1330 patch = self.series[i]
1331 if patch in applied:
1331 if patch in applied:
1332 stat = 'A'
1332 stat = 'A'
1333 elif self.pushable(i)[0]:
1333 elif self.pushable(i)[0]:
1334 stat = 'U'
1334 stat = 'U'
1335 else:
1335 else:
1336 stat = 'G'
1336 stat = 'G'
1337 pfx = ''
1337 pfx = ''
1338 if self.ui.verbose:
1338 if self.ui.verbose:
1339 pfx = '%d %s ' % (i, stat)
1339 pfx = '%d %s ' % (i, stat)
1340 elif status and status != stat:
1340 elif status and status != stat:
1341 continue
1341 continue
1342 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1342 self.ui.write('%s%s\n' % (pfx, displayname(patch)))
1343 else:
1343 else:
1344 msng_list = []
1344 msng_list = []
1345 for root, dirs, files in os.walk(self.path):
1345 for root, dirs, files in os.walk(self.path):
1346 d = root[len(self.path) + 1:]
1346 d = root[len(self.path) + 1:]
1347 for f in files:
1347 for f in files:
1348 fl = os.path.join(d, f)
1348 fl = os.path.join(d, f)
1349 if (fl not in self.series and
1349 if (fl not in self.series and
1350 fl not in (self.status_path, self.series_path,
1350 fl not in (self.status_path, self.series_path,
1351 self.guards_path)
1351 self.guards_path)
1352 and not fl.startswith('.')):
1352 and not fl.startswith('.')):
1353 msng_list.append(fl)
1353 msng_list.append(fl)
1354 for x in util.sort(msng_list):
1354 for x in util.sort(msng_list):
1355 pfx = self.ui.verbose and ('D ') or ''
1355 pfx = self.ui.verbose and ('D ') or ''
1356 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1356 self.ui.write("%s%s\n" % (pfx, displayname(x)))
1357
1357
1358 def issaveline(self, l):
1358 def issaveline(self, l):
1359 if l.name == '.hg.patches.save.line':
1359 if l.name == '.hg.patches.save.line':
1360 return True
1360 return True
1361
1361
1362 def qrepo(self, create=False):
1362 def qrepo(self, create=False):
1363 if create or os.path.isdir(self.join(".hg")):
1363 if create or os.path.isdir(self.join(".hg")):
1364 return hg.repository(self.ui, path=self.path, create=create)
1364 return hg.repository(self.ui, path=self.path, create=create)
1365
1365
1366 def restore(self, repo, rev, delete=None, qupdate=None):
1366 def restore(self, repo, rev, delete=None, qupdate=None):
1367 c = repo.changelog.read(rev)
1367 c = repo.changelog.read(rev)
1368 desc = c[4].strip()
1368 desc = c[4].strip()
1369 lines = desc.splitlines()
1369 lines = desc.splitlines()
1370 i = 0
1370 i = 0
1371 datastart = None
1371 datastart = None
1372 series = []
1372 series = []
1373 applied = []
1373 applied = []
1374 qpp = None
1374 qpp = None
1375 for i in xrange(0, len(lines)):
1375 for i in xrange(0, len(lines)):
1376 if lines[i] == 'Patch Data:':
1376 if lines[i] == 'Patch Data:':
1377 datastart = i + 1
1377 datastart = i + 1
1378 elif lines[i].startswith('Dirstate:'):
1378 elif lines[i].startswith('Dirstate:'):
1379 l = lines[i].rstrip()
1379 l = lines[i].rstrip()
1380 l = l[10:].split(' ')
1380 l = l[10:].split(' ')
1381 qpp = [ bin(x) for x in l ]
1381 qpp = [ bin(x) for x in l ]
1382 elif datastart != None:
1382 elif datastart != None:
1383 l = lines[i].rstrip()
1383 l = lines[i].rstrip()
1384 se = statusentry(l)
1384 se = statusentry(l)
1385 file_ = se.name
1385 file_ = se.name
1386 if se.rev:
1386 if se.rev:
1387 applied.append(se)
1387 applied.append(se)
1388 else:
1388 else:
1389 series.append(file_)
1389 series.append(file_)
1390 if datastart == None:
1390 if datastart == None:
1391 self.ui.warn(_("No saved patch data found\n"))
1391 self.ui.warn(_("No saved patch data found\n"))
1392 return 1
1392 return 1
1393 self.ui.warn(_("restoring status: %s\n") % lines[0])
1393 self.ui.warn(_("restoring status: %s\n") % lines[0])
1394 self.full_series = series
1394 self.full_series = series
1395 self.applied = applied
1395 self.applied = applied
1396 self.parse_series()
1396 self.parse_series()
1397 self.series_dirty = 1
1397 self.series_dirty = 1
1398 self.applied_dirty = 1
1398 self.applied_dirty = 1
1399 heads = repo.changelog.heads()
1399 heads = repo.changelog.heads()
1400 if delete:
1400 if delete:
1401 if rev not in heads:
1401 if rev not in heads:
1402 self.ui.warn(_("save entry has children, leaving it alone\n"))
1402 self.ui.warn(_("save entry has children, leaving it alone\n"))
1403 else:
1403 else:
1404 self.ui.warn(_("removing save entry %s\n") % short(rev))
1404 self.ui.warn(_("removing save entry %s\n") % short(rev))
1405 pp = repo.dirstate.parents()
1405 pp = repo.dirstate.parents()
1406 if rev in pp:
1406 if rev in pp:
1407 update = True
1407 update = True
1408 else:
1408 else:
1409 update = False
1409 update = False
1410 self.strip(repo, rev, update=update, backup='strip')
1410 self.strip(repo, rev, update=update, backup='strip')
1411 if qpp:
1411 if qpp:
1412 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1412 self.ui.warn(_("saved queue repository parents: %s %s\n") %
1413 (short(qpp[0]), short(qpp[1])))
1413 (short(qpp[0]), short(qpp[1])))
1414 if qupdate:
1414 if qupdate:
1415 self.ui.status(_("queue directory updating\n"))
1415 self.ui.status(_("queue directory updating\n"))
1416 r = self.qrepo()
1416 r = self.qrepo()
1417 if not r:
1417 if not r:
1418 self.ui.warn(_("Unable to load queue repository\n"))
1418 self.ui.warn(_("Unable to load queue repository\n"))
1419 return 1
1419 return 1
1420 hg.clean(r, qpp[0])
1420 hg.clean(r, qpp[0])
1421
1421
1422 def save(self, repo, msg=None):
1422 def save(self, repo, msg=None):
1423 if len(self.applied) == 0:
1423 if len(self.applied) == 0:
1424 self.ui.warn(_("save: no patches applied, exiting\n"))
1424 self.ui.warn(_("save: no patches applied, exiting\n"))
1425 return 1
1425 return 1
1426 if self.issaveline(self.applied[-1]):
1426 if self.issaveline(self.applied[-1]):
1427 self.ui.warn(_("status is already saved\n"))
1427 self.ui.warn(_("status is already saved\n"))
1428 return 1
1428 return 1
1429
1429
1430 ar = [ ':' + x for x in self.full_series ]
1430 ar = [ ':' + x for x in self.full_series ]
1431 if not msg:
1431 if not msg:
1432 msg = _("hg patches saved state")
1432 msg = _("hg patches saved state")
1433 else:
1433 else:
1434 msg = "hg patches: " + msg.rstrip('\r\n')
1434 msg = "hg patches: " + msg.rstrip('\r\n')
1435 r = self.qrepo()
1435 r = self.qrepo()
1436 if r:
1436 if r:
1437 pp = r.dirstate.parents()
1437 pp = r.dirstate.parents()
1438 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1438 msg += "\nDirstate: %s %s" % (hex(pp[0]), hex(pp[1]))
1439 msg += "\n\nPatch Data:\n"
1439 msg += "\n\nPatch Data:\n"
1440 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1440 text = msg + "\n".join([str(x) for x in self.applied]) + '\n' + (ar and
1441 "\n".join(ar) + '\n' or "")
1441 "\n".join(ar) + '\n' or "")
1442 n = repo.commit(None, text, user=None, force=1)
1442 n = repo.commit(None, text, user=None, force=1)
1443 if not n:
1443 if not n:
1444 self.ui.warn(_("repo commit failed\n"))
1444 self.ui.warn(_("repo commit failed\n"))
1445 return 1
1445 return 1
1446 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1446 self.applied.append(statusentry(revlog.hex(n),'.hg.patches.save.line'))
1447 self.applied_dirty = 1
1447 self.applied_dirty = 1
1448 self.removeundo(repo)
1448 self.removeundo(repo)
1449
1449
1450 def full_series_end(self):
1450 def full_series_end(self):
1451 if len(self.applied) > 0:
1451 if len(self.applied) > 0:
1452 p = self.applied[-1].name
1452 p = self.applied[-1].name
1453 end = self.find_series(p)
1453 end = self.find_series(p)
1454 if end == None:
1454 if end == None:
1455 return len(self.full_series)
1455 return len(self.full_series)
1456 return end + 1
1456 return end + 1
1457 return 0
1457 return 0
1458
1458
1459 def series_end(self, all_patches=False):
1459 def series_end(self, all_patches=False):
1460 """If all_patches is False, return the index of the next pushable patch
1460 """If all_patches is False, return the index of the next pushable patch
1461 in the series, or the series length. If all_patches is True, return the
1461 in the series, or the series length. If all_patches is True, return the
1462 index of the first patch past the last applied one.
1462 index of the first patch past the last applied one.
1463 """
1463 """
1464 end = 0
1464 end = 0
1465 def next(start):
1465 def next(start):
1466 if all_patches:
1466 if all_patches:
1467 return start
1467 return start
1468 i = start
1468 i = start
1469 while i < len(self.series):
1469 while i < len(self.series):
1470 p, reason = self.pushable(i)
1470 p, reason = self.pushable(i)
1471 if p:
1471 if p:
1472 break
1472 break
1473 self.explain_pushable(i)
1473 self.explain_pushable(i)
1474 i += 1
1474 i += 1
1475 return i
1475 return i
1476 if len(self.applied) > 0:
1476 if len(self.applied) > 0:
1477 p = self.applied[-1].name
1477 p = self.applied[-1].name
1478 try:
1478 try:
1479 end = self.series.index(p)
1479 end = self.series.index(p)
1480 except ValueError:
1480 except ValueError:
1481 return 0
1481 return 0
1482 return next(end + 1)
1482 return next(end + 1)
1483 return next(end)
1483 return next(end)
1484
1484
1485 def appliedname(self, index):
1485 def appliedname(self, index):
1486 pname = self.applied[index].name
1486 pname = self.applied[index].name
1487 if not self.ui.verbose:
1487 if not self.ui.verbose:
1488 p = pname
1488 p = pname
1489 else:
1489 else:
1490 p = str(self.series.index(pname)) + " " + pname
1490 p = str(self.series.index(pname)) + " " + pname
1491 return p
1491 return p
1492
1492
1493 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1493 def qimport(self, repo, files, patchname=None, rev=None, existing=None,
1494 force=None, git=False):
1494 force=None, git=False):
1495 def checkseries(patchname):
1495 def checkseries(patchname):
1496 if patchname in self.series:
1496 if patchname in self.series:
1497 raise util.Abort(_('patch %s is already in the series file')
1497 raise util.Abort(_('patch %s is already in the series file')
1498 % patchname)
1498 % patchname)
1499 def checkfile(patchname):
1499 def checkfile(patchname):
1500 if not force and os.path.exists(self.join(patchname)):
1500 if not force and os.path.exists(self.join(patchname)):
1501 raise util.Abort(_('patch "%s" already exists')
1501 raise util.Abort(_('patch "%s" already exists')
1502 % patchname)
1502 % patchname)
1503
1503
1504 if rev:
1504 if rev:
1505 if files:
1505 if files:
1506 raise util.Abort(_('option "-r" not valid when importing '
1506 raise util.Abort(_('option "-r" not valid when importing '
1507 'files'))
1507 'files'))
1508 rev = cmdutil.revrange(repo, rev)
1508 rev = cmdutil.revrange(repo, rev)
1509 rev.sort(lambda x, y: cmp(y, x))
1509 rev.sort(lambda x, y: cmp(y, x))
1510 if (len(files) > 1 or len(rev) > 1) and patchname:
1510 if (len(files) > 1 or len(rev) > 1) and patchname:
1511 raise util.Abort(_('option "-n" not valid when importing multiple '
1511 raise util.Abort(_('option "-n" not valid when importing multiple '
1512 'patches'))
1512 'patches'))
1513 i = 0
1513 i = 0
1514 added = []
1514 added = []
1515 if rev:
1515 if rev:
1516 # If mq patches are applied, we can only import revisions
1516 # If mq patches are applied, we can only import revisions
1517 # that form a linear path to qbase.
1517 # that form a linear path to qbase.
1518 # Otherwise, they should form a linear path to a head.
1518 # Otherwise, they should form a linear path to a head.
1519 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1519 heads = repo.changelog.heads(repo.changelog.node(rev[-1]))
1520 if len(heads) > 1:
1520 if len(heads) > 1:
1521 raise util.Abort(_('revision %d is the root of more than one '
1521 raise util.Abort(_('revision %d is the root of more than one '
1522 'branch') % rev[-1])
1522 'branch') % rev[-1])
1523 if self.applied:
1523 if self.applied:
1524 base = revlog.hex(repo.changelog.node(rev[0]))
1524 base = revlog.hex(repo.changelog.node(rev[0]))
1525 if base in [n.rev for n in self.applied]:
1525 if base in [n.rev for n in self.applied]:
1526 raise util.Abort(_('revision %d is already managed')
1526 raise util.Abort(_('revision %d is already managed')
1527 % rev[0])
1527 % rev[0])
1528 if heads != [revlog.bin(self.applied[-1].rev)]:
1528 if heads != [revlog.bin(self.applied[-1].rev)]:
1529 raise util.Abort(_('revision %d is not the parent of '
1529 raise util.Abort(_('revision %d is not the parent of '
1530 'the queue') % rev[0])
1530 'the queue') % rev[0])
1531 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1531 base = repo.changelog.rev(revlog.bin(self.applied[0].rev))
1532 lastparent = repo.changelog.parentrevs(base)[0]
1532 lastparent = repo.changelog.parentrevs(base)[0]
1533 else:
1533 else:
1534 if heads != [repo.changelog.node(rev[0])]:
1534 if heads != [repo.changelog.node(rev[0])]:
1535 raise util.Abort(_('revision %d has unmanaged children')
1535 raise util.Abort(_('revision %d has unmanaged children')
1536 % rev[0])
1536 % rev[0])
1537 lastparent = None
1537 lastparent = None
1538
1538
1539 if git:
1539 if git:
1540 self.diffopts().git = True
1540 self.diffopts().git = True
1541
1541
1542 for r in rev:
1542 for r in rev:
1543 p1, p2 = repo.changelog.parentrevs(r)
1543 p1, p2 = repo.changelog.parentrevs(r)
1544 n = repo.changelog.node(r)
1544 n = repo.changelog.node(r)
1545 if p2 != revlog.nullrev:
1545 if p2 != revlog.nullrev:
1546 raise util.Abort(_('cannot import merge revision %d') % r)
1546 raise util.Abort(_('cannot import merge revision %d') % r)
1547 if lastparent and lastparent != r:
1547 if lastparent and lastparent != r:
1548 raise util.Abort(_('revision %d is not the parent of %d')
1548 raise util.Abort(_('revision %d is not the parent of %d')
1549 % (r, lastparent))
1549 % (r, lastparent))
1550 lastparent = p1
1550 lastparent = p1
1551
1551
1552 if not patchname:
1552 if not patchname:
1553 patchname = normname('%d.diff' % r)
1553 patchname = normname('%d.diff' % r)
1554 self.check_reserved_name(patchname)
1554 self.check_reserved_name(patchname)
1555 checkseries(patchname)
1555 checkseries(patchname)
1556 checkfile(patchname)
1556 checkfile(patchname)
1557 self.full_series.insert(0, patchname)
1557 self.full_series.insert(0, patchname)
1558
1558
1559 patchf = self.opener(patchname, "w")
1559 patchf = self.opener(patchname, "w")
1560 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1560 patch.export(repo, [n], fp=patchf, opts=self.diffopts())
1561 patchf.close()
1561 patchf.close()
1562
1562
1563 se = statusentry(revlog.hex(n), patchname)
1563 se = statusentry(revlog.hex(n), patchname)
1564 self.applied.insert(0, se)
1564 self.applied.insert(0, se)
1565
1565
1566 added.append(patchname)
1566 added.append(patchname)
1567 patchname = None
1567 patchname = None
1568 self.parse_series()
1568 self.parse_series()
1569 self.applied_dirty = 1
1569 self.applied_dirty = 1
1570
1570
1571 for filename in files:
1571 for filename in files:
1572 if existing:
1572 if existing:
1573 if filename == '-':
1573 if filename == '-':
1574 raise util.Abort(_('-e is incompatible with import from -'))
1574 raise util.Abort(_('-e is incompatible with import from -'))
1575 if not patchname:
1575 if not patchname:
1576 patchname = normname(filename)
1576 patchname = normname(filename)
1577 self.check_reserved_name(patchname)
1577 self.check_reserved_name(patchname)
1578 if not os.path.isfile(self.join(patchname)):
1578 if not os.path.isfile(self.join(patchname)):
1579 raise util.Abort(_("patch %s does not exist") % patchname)
1579 raise util.Abort(_("patch %s does not exist") % patchname)
1580 else:
1580 else:
1581 try:
1581 try:
1582 if filename == '-':
1582 if filename == '-':
1583 if not patchname:
1583 if not patchname:
1584 raise util.Abort(_('need --name to import a patch from -'))
1584 raise util.Abort(_('need --name to import a patch from -'))
1585 text = sys.stdin.read()
1585 text = sys.stdin.read()
1586 else:
1586 else:
1587 text = url.open(self.ui, filename).read()
1587 text = url.open(self.ui, filename).read()
1588 except (OSError, IOError):
1588 except (OSError, IOError):
1589 raise util.Abort(_("unable to read %s") % filename)
1589 raise util.Abort(_("unable to read %s") % filename)
1590 if not patchname:
1590 if not patchname:
1591 patchname = normname(os.path.basename(filename))
1591 patchname = normname(os.path.basename(filename))
1592 self.check_reserved_name(patchname)
1592 self.check_reserved_name(patchname)
1593 checkfile(patchname)
1593 checkfile(patchname)
1594 patchf = self.opener(patchname, "w")
1594 patchf = self.opener(patchname, "w")
1595 patchf.write(text)
1595 patchf.write(text)
1596 if not force:
1596 if not force:
1597 checkseries(patchname)
1597 checkseries(patchname)
1598 if patchname not in self.series:
1598 if patchname not in self.series:
1599 index = self.full_series_end() + i
1599 index = self.full_series_end() + i
1600 self.full_series[index:index] = [patchname]
1600 self.full_series[index:index] = [patchname]
1601 self.parse_series()
1601 self.parse_series()
1602 self.ui.warn(_("adding %s to series file\n") % patchname)
1602 self.ui.warn(_("adding %s to series file\n") % patchname)
1603 i += 1
1603 i += 1
1604 added.append(patchname)
1604 added.append(patchname)
1605 patchname = None
1605 patchname = None
1606 self.series_dirty = 1
1606 self.series_dirty = 1
1607 qrepo = self.qrepo()
1607 qrepo = self.qrepo()
1608 if qrepo:
1608 if qrepo:
1609 qrepo.add(added)
1609 qrepo.add(added)
1610
1610
1611 def delete(ui, repo, *patches, **opts):
1611 def delete(ui, repo, *patches, **opts):
1612 """remove patches from queue
1612 """remove patches from queue
1613
1613
1614 The patches must not be applied, unless they are arguments to
1614 The patches must not be applied, unless they are arguments to
1615 the --rev parameter. At least one patch or revision is required.
1615 the --rev parameter. At least one patch or revision is required.
1616
1616
1617 With --rev, mq will stop managing the named revisions (converting
1617 With --rev, mq will stop managing the named revisions (converting
1618 them to regular mercurial changesets). The qfinish command should be
1618 them to regular mercurial changesets). The qfinish command should be
1619 used as an alternative for qdel -r, as the latter option is deprecated.
1619 used as an alternative for qdel -r, as the latter option is deprecated.
1620
1620
1621 With --keep, the patch files are preserved in the patch directory."""
1621 With --keep, the patch files are preserved in the patch directory."""
1622 q = repo.mq
1622 q = repo.mq
1623 q.delete(repo, patches, opts)
1623 q.delete(repo, patches, opts)
1624 q.save_dirty()
1624 q.save_dirty()
1625 return 0
1625 return 0
1626
1626
1627 def applied(ui, repo, patch=None, **opts):
1627 def applied(ui, repo, patch=None, **opts):
1628 """print the patches already applied"""
1628 """print the patches already applied"""
1629 q = repo.mq
1629 q = repo.mq
1630 if patch:
1630 if patch:
1631 if patch not in q.series:
1631 if patch not in q.series:
1632 raise util.Abort(_("patch %s is not in series file") % patch)
1632 raise util.Abort(_("patch %s is not in series file") % patch)
1633 end = q.series.index(patch) + 1
1633 end = q.series.index(patch) + 1
1634 else:
1634 else:
1635 end = q.series_end(True)
1635 end = q.series_end(True)
1636 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1636 return q.qseries(repo, length=end, status='A', summary=opts.get('summary'))
1637
1637
1638 def unapplied(ui, repo, patch=None, **opts):
1638 def unapplied(ui, repo, patch=None, **opts):
1639 """print the patches not yet applied"""
1639 """print the patches not yet applied"""
1640 q = repo.mq
1640 q = repo.mq
1641 if patch:
1641 if patch:
1642 if patch not in q.series:
1642 if patch not in q.series:
1643 raise util.Abort(_("patch %s is not in series file") % patch)
1643 raise util.Abort(_("patch %s is not in series file") % patch)
1644 start = q.series.index(patch) + 1
1644 start = q.series.index(patch) + 1
1645 else:
1645 else:
1646 start = q.series_end(True)
1646 start = q.series_end(True)
1647 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1647 q.qseries(repo, start=start, status='U', summary=opts.get('summary'))
1648
1648
1649 def qimport(ui, repo, *filename, **opts):
1649 def qimport(ui, repo, *filename, **opts):
1650 """import a patch
1650 """import a patch
1651
1651
1652 The patch is inserted into the series after the last applied patch.
1652 The patch is inserted into the series after the last applied patch.
1653 If no patches have been applied, qimport prepends the patch
1653 If no patches have been applied, qimport prepends the patch
1654 to the series.
1654 to the series.
1655
1655
1656 The patch will have the same name as its source file unless you
1656 The patch will have the same name as its source file unless you
1657 give it a new one with --name.
1657 give it a new one with --name.
1658
1658
1659 You can register an existing patch inside the patch directory
1659 You can register an existing patch inside the patch directory
1660 with the --existing flag.
1660 with the --existing flag.
1661
1661
1662 With --force, an existing patch of the same name will be overwritten.
1662 With --force, an existing patch of the same name will be overwritten.
1663
1663
1664 An existing changeset may be placed under mq control with --rev
1664 An existing changeset may be placed under mq control with --rev
1665 (e.g. qimport --rev tip -n patch will place tip under mq control).
1665 (e.g. qimport --rev tip -n patch will place tip under mq control).
1666 With --git, patches imported with --rev will use the git diff
1666 With --git, patches imported with --rev will use the git diff
1667 format. See the diffs help topic for information on why this is
1667 format. See the diffs help topic for information on why this is
1668 important for preserving rename/copy information and permission changes.
1668 important for preserving rename/copy information and permission changes.
1669 """
1669 """
1670 q = repo.mq
1670 q = repo.mq
1671 q.qimport(repo, filename, patchname=opts['name'],
1671 q.qimport(repo, filename, patchname=opts['name'],
1672 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1672 existing=opts['existing'], force=opts['force'], rev=opts['rev'],
1673 git=opts['git'])
1673 git=opts['git'])
1674 q.save_dirty()
1674 q.save_dirty()
1675 return 0
1675 return 0
1676
1676
1677 def init(ui, repo, **opts):
1677 def init(ui, repo, **opts):
1678 """init a new queue repository
1678 """init a new queue repository
1679
1679
1680 The queue repository is unversioned by default. If -c is
1680 The queue repository is unversioned by default. If -c is
1681 specified, qinit will create a separate nested repository
1681 specified, qinit will create a separate nested repository
1682 for patches (qinit -c may also be run later to convert
1682 for patches (qinit -c may also be run later to convert
1683 an unversioned patch repository into a versioned one).
1683 an unversioned patch repository into a versioned one).
1684 You can use qcommit to commit changes to this queue repository."""
1684 You can use qcommit to commit changes to this queue repository."""
1685 q = repo.mq
1685 q = repo.mq
1686 r = q.init(repo, create=opts['create_repo'])
1686 r = q.init(repo, create=opts['create_repo'])
1687 q.save_dirty()
1687 q.save_dirty()
1688 if r:
1688 if r:
1689 if not os.path.exists(r.wjoin('.hgignore')):
1689 if not os.path.exists(r.wjoin('.hgignore')):
1690 fp = r.wopener('.hgignore', 'w')
1690 fp = r.wopener('.hgignore', 'w')
1691 fp.write('^\\.hg\n')
1691 fp.write('^\\.hg\n')
1692 fp.write('^\\.mq\n')
1692 fp.write('^\\.mq\n')
1693 fp.write('syntax: glob\n')
1693 fp.write('syntax: glob\n')
1694 fp.write('status\n')
1694 fp.write('status\n')
1695 fp.write('guards\n')
1695 fp.write('guards\n')
1696 fp.close()
1696 fp.close()
1697 if not os.path.exists(r.wjoin('series')):
1697 if not os.path.exists(r.wjoin('series')):
1698 r.wopener('series', 'w').close()
1698 r.wopener('series', 'w').close()
1699 r.add(['.hgignore', 'series'])
1699 r.add(['.hgignore', 'series'])
1700 commands.add(ui, r)
1700 commands.add(ui, r)
1701 return 0
1701 return 0
1702
1702
1703 def clone(ui, source, dest=None, **opts):
1703 def clone(ui, source, dest=None, **opts):
1704 '''clone main and patch repository at same time
1704 '''clone main and patch repository at same time
1705
1705
1706 If source is local, destination will have no patches applied. If
1706 If source is local, destination will have no patches applied. If
1707 source is remote, this command can not check if patches are
1707 source is remote, this command can not check if patches are
1708 applied in source, so cannot guarantee that patches are not
1708 applied in source, so cannot guarantee that patches are not
1709 applied in destination. If you clone remote repository, be sure
1709 applied in destination. If you clone remote repository, be sure
1710 before that it has no patches applied.
1710 before that it has no patches applied.
1711
1711
1712 Source patch repository is looked for in <src>/.hg/patches by
1712 Source patch repository is looked for in <src>/.hg/patches by
1713 default. Use -p <url> to change.
1713 default. Use -p <url> to change.
1714
1714
1715 The patch directory must be a nested mercurial repository, as
1715 The patch directory must be a nested mercurial repository, as
1716 would be created by qinit -c.
1716 would be created by qinit -c.
1717 '''
1717 '''
1718 def patchdir(repo):
1718 def patchdir(repo):
1719 url = repo.url()
1719 url = repo.url()
1720 if url.endswith('/'):
1720 if url.endswith('/'):
1721 url = url[:-1]
1721 url = url[:-1]
1722 return url + '/.hg/patches'
1722 return url + '/.hg/patches'
1723 cmdutil.setremoteconfig(ui, opts)
1723 cmdutil.setremoteconfig(ui, opts)
1724 if dest is None:
1724 if dest is None:
1725 dest = hg.defaultdest(source)
1725 dest = hg.defaultdest(source)
1726 sr = hg.repository(ui, ui.expandpath(source))
1726 sr = hg.repository(ui, ui.expandpath(source))
1727 patchespath = opts['patches'] or patchdir(sr)
1727 patchespath = opts['patches'] or patchdir(sr)
1728 try:
1728 try:
1729 pr = hg.repository(ui, patchespath)
1729 pr = hg.repository(ui, patchespath)
1730 except RepoError:
1730 except RepoError:
1731 raise util.Abort(_('versioned patch repository not found'
1731 raise util.Abort(_('versioned patch repository not found'
1732 ' (see qinit -c)'))
1732 ' (see qinit -c)'))
1733 qbase, destrev = None, None
1733 qbase, destrev = None, None
1734 if sr.local():
1734 if sr.local():
1735 if sr.mq.applied:
1735 if sr.mq.applied:
1736 qbase = revlog.bin(sr.mq.applied[0].rev)
1736 qbase = revlog.bin(sr.mq.applied[0].rev)
1737 if not hg.islocal(dest):
1737 if not hg.islocal(dest):
1738 heads = dict.fromkeys(sr.heads())
1738 heads = dict.fromkeys(sr.heads())
1739 for h in sr.heads(qbase):
1739 for h in sr.heads(qbase):
1740 del heads[h]
1740 del heads[h]
1741 destrev = heads.keys()
1741 destrev = heads.keys()
1742 destrev.append(sr.changelog.parents(qbase)[0])
1742 destrev.append(sr.changelog.parents(qbase)[0])
1743 elif sr.capable('lookup'):
1743 elif sr.capable('lookup'):
1744 try:
1744 try:
1745 qbase = sr.lookup('qbase')
1745 qbase = sr.lookup('qbase')
1746 except RepoError:
1746 except RepoError:
1747 pass
1747 pass
1748 ui.note(_('cloning main repo\n'))
1748 ui.note(_('cloning main repo\n'))
1749 sr, dr = hg.clone(ui, sr.url(), dest,
1749 sr, dr = hg.clone(ui, sr.url(), dest,
1750 pull=opts['pull'],
1750 pull=opts['pull'],
1751 rev=destrev,
1751 rev=destrev,
1752 update=False,
1752 update=False,
1753 stream=opts['uncompressed'])
1753 stream=opts['uncompressed'])
1754 ui.note(_('cloning patch repo\n'))
1754 ui.note(_('cloning patch repo\n'))
1755 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1755 spr, dpr = hg.clone(ui, opts['patches'] or patchdir(sr), patchdir(dr),
1756 pull=opts['pull'], update=not opts['noupdate'],
1756 pull=opts['pull'], update=not opts['noupdate'],
1757 stream=opts['uncompressed'])
1757 stream=opts['uncompressed'])
1758 if dr.local():
1758 if dr.local():
1759 if qbase:
1759 if qbase:
1760 ui.note(_('stripping applied patches from destination repo\n'))
1760 ui.note(_('stripping applied patches from destination repo\n'))
1761 dr.mq.strip(dr, qbase, update=False, backup=None)
1761 dr.mq.strip(dr, qbase, update=False, backup=None)
1762 if not opts['noupdate']:
1762 if not opts['noupdate']:
1763 ui.note(_('updating destination repo\n'))
1763 ui.note(_('updating destination repo\n'))
1764 hg.update(dr, dr.changelog.tip())
1764 hg.update(dr, dr.changelog.tip())
1765
1765
1766 def commit(ui, repo, *pats, **opts):
1766 def commit(ui, repo, *pats, **opts):
1767 """commit changes in the queue repository"""
1767 """commit changes in the queue repository"""
1768 q = repo.mq
1768 q = repo.mq
1769 r = q.qrepo()
1769 r = q.qrepo()
1770 if not r: raise util.Abort('no queue repository')
1770 if not r: raise util.Abort('no queue repository')
1771 commands.commit(r.ui, r, *pats, **opts)
1771 commands.commit(r.ui, r, *pats, **opts)
1772
1772
1773 def series(ui, repo, **opts):
1773 def series(ui, repo, **opts):
1774 """print the entire series file"""
1774 """print the entire series file"""
1775 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1775 repo.mq.qseries(repo, missing=opts['missing'], summary=opts['summary'])
1776 return 0
1776 return 0
1777
1777
1778 def top(ui, repo, **opts):
1778 def top(ui, repo, **opts):
1779 """print the name of the current patch"""
1779 """print the name of the current patch"""
1780 q = repo.mq
1780 q = repo.mq
1781 t = q.applied and q.series_end(True) or 0
1781 t = q.applied and q.series_end(True) or 0
1782 if t:
1782 if t:
1783 return q.qseries(repo, start=t-1, length=1, status='A',
1783 return q.qseries(repo, start=t-1, length=1, status='A',
1784 summary=opts.get('summary'))
1784 summary=opts.get('summary'))
1785 else:
1785 else:
1786 ui.write(_("No patches applied\n"))
1786 ui.write(_("No patches applied\n"))
1787 return 1
1787 return 1
1788
1788
1789 def next(ui, repo, **opts):
1789 def next(ui, repo, **opts):
1790 """print the name of the next patch"""
1790 """print the name of the next patch"""
1791 q = repo.mq
1791 q = repo.mq
1792 end = q.series_end()
1792 end = q.series_end()
1793 if end == len(q.series):
1793 if end == len(q.series):
1794 ui.write(_("All patches applied\n"))
1794 ui.write(_("All patches applied\n"))
1795 return 1
1795 return 1
1796 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1796 return q.qseries(repo, start=end, length=1, summary=opts.get('summary'))
1797
1797
1798 def prev(ui, repo, **opts):
1798 def prev(ui, repo, **opts):
1799 """print the name of the previous patch"""
1799 """print the name of the previous patch"""
1800 q = repo.mq
1800 q = repo.mq
1801 l = len(q.applied)
1801 l = len(q.applied)
1802 if l == 1:
1802 if l == 1:
1803 ui.write(_("Only one patch applied\n"))
1803 ui.write(_("Only one patch applied\n"))
1804 return 1
1804 return 1
1805 if not l:
1805 if not l:
1806 ui.write(_("No patches applied\n"))
1806 ui.write(_("No patches applied\n"))
1807 return 1
1807 return 1
1808 return q.qseries(repo, start=l-2, length=1, status='A',
1808 return q.qseries(repo, start=l-2, length=1, status='A',
1809 summary=opts.get('summary'))
1809 summary=opts.get('summary'))
1810
1810
1811 def setupheaderopts(ui, opts):
1811 def setupheaderopts(ui, opts):
1812 def do(opt,val):
1812 def do(opt,val):
1813 if not opts[opt] and opts['current' + opt]:
1813 if not opts[opt] and opts['current' + opt]:
1814 opts[opt] = val
1814 opts[opt] = val
1815 do('user', ui.username())
1815 do('user', ui.username())
1816 do('date', "%d %d" % util.makedate())
1816 do('date', "%d %d" % util.makedate())
1817
1817
1818 def new(ui, repo, patch, *args, **opts):
1818 def new(ui, repo, patch, *args, **opts):
1819 """create a new patch
1819 """create a new patch
1820
1820
1821 qnew creates a new patch on top of the currently-applied patch (if any).
1821 qnew creates a new patch on top of the currently-applied patch (if any).
1822 It will refuse to run if there are any outstanding changes unless -f is
1822 It will refuse to run if there are any outstanding changes unless -f is
1823 specified, in which case the patch will be initialized with them. You
1823 specified, in which case the patch will be initialized with them. You
1824 may also use -I, -X, and/or a list of files after the patch name to add
1824 may also use -I, -X, and/or a list of files after the patch name to add
1825 only changes to matching files to the new patch, leaving the rest as
1825 only changes to matching files to the new patch, leaving the rest as
1826 uncommitted modifications.
1826 uncommitted modifications.
1827
1827
1828 -u and -d can be used to set the (given) user and date, respectively.
1828 -u and -d can be used to set the (given) user and date, respectively.
1829 -U and -D set user to current user and date to current date.
1829 -U and -D set user to current user and date to current date.
1830
1830
1831 -e, -m or -l set the patch header as well as the commit message. If none
1831 -e, -m or -l set the patch header as well as the commit message. If none
1832 is specified, the header is empty and the commit message is '[mq]: PATCH'.
1832 is specified, the header is empty and the commit message is '[mq]: PATCH'.
1833
1833
1834 Use the --git option to keep the patch in the git extended diff
1834 Use the --git option to keep the patch in the git extended diff
1835 format. Read the diffs help topic for more information on why this
1835 format. Read the diffs help topic for more information on why this
1836 is important for preserving permission changes and copy/rename
1836 is important for preserving permission changes and copy/rename
1837 information.
1837 information.
1838 """
1838 """
1839 msg = cmdutil.logmessage(opts)
1839 msg = cmdutil.logmessage(opts)
1840 def getmsg(): return ui.edit(msg, ui.username())
1840 def getmsg(): return ui.edit(msg, ui.username())
1841 q = repo.mq
1841 q = repo.mq
1842 opts['msg'] = msg
1842 opts['msg'] = msg
1843 if opts.get('edit'):
1843 if opts.get('edit'):
1844 opts['msg'] = getmsg
1844 opts['msg'] = getmsg
1845 else:
1845 else:
1846 opts['msg'] = msg
1846 opts['msg'] = msg
1847 setupheaderopts(ui, opts)
1847 setupheaderopts(ui, opts)
1848 q.new(repo, patch, *args, **opts)
1848 q.new(repo, patch, *args, **opts)
1849 q.save_dirty()
1849 q.save_dirty()
1850 return 0
1850 return 0
1851
1851
1852 def refresh(ui, repo, *pats, **opts):
1852 def refresh(ui, repo, *pats, **opts):
1853 """update the current patch
1853 """update the current patch
1854
1854
1855 If any file patterns are provided, the refreshed patch will contain only
1855 If any file patterns are provided, the refreshed patch will contain only
1856 the modifications that match those patterns; the remaining modifications
1856 the modifications that match those patterns; the remaining modifications
1857 will remain in the working directory.
1857 will remain in the working directory.
1858
1858
1859 If --short is specified, files currently included in the patch will
1859 If --short is specified, files currently included in the patch will
1860 be refreshed just like matched files and remain in the patch.
1860 be refreshed just like matched files and remain in the patch.
1861
1861
1862 hg add/remove/copy/rename work as usual, though you might want to use
1862 hg add/remove/copy/rename work as usual, though you might want to use
1863 git-style patches (--git or [diff] git=1) to track copies and renames.
1863 git-style patches (--git or [diff] git=1) to track copies and renames.
1864 See the diffs help topic for more information on the git diff format.
1864 See the diffs help topic for more information on the git diff format.
1865 """
1865 """
1866 q = repo.mq
1866 q = repo.mq
1867 message = cmdutil.logmessage(opts)
1867 message = cmdutil.logmessage(opts)
1868 if opts['edit']:
1868 if opts['edit']:
1869 if not q.applied:
1869 if not q.applied:
1870 ui.write(_("No patches applied\n"))
1870 ui.write(_("No patches applied\n"))
1871 return 1
1871 return 1
1872 if message:
1872 if message:
1873 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1873 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1874 patch = q.applied[-1].name
1874 patch = q.applied[-1].name
1875 ph = q.readheaders(patch)
1875 ph = q.readheaders(patch)
1876 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
1876 message = ui.edit('\n'.join(ph.message), ph.user or ui.username())
1877 setupheaderopts(ui, opts)
1877 setupheaderopts(ui, opts)
1878 ret = q.refresh(repo, pats, msg=message, **opts)
1878 ret = q.refresh(repo, pats, msg=message, **opts)
1879 q.save_dirty()
1879 q.save_dirty()
1880 return ret
1880 return ret
1881
1881
1882 def diff(ui, repo, *pats, **opts):
1882 def diff(ui, repo, *pats, **opts):
1883 """diff of the current patch and subsequent modifications
1883 """diff of the current patch and subsequent modifications
1884
1884
1885 Shows a diff which includes the current patch as well as any changes which
1885 Shows a diff which includes the current patch as well as any changes which
1886 have been made in the working directory since the last refresh (thus
1886 have been made in the working directory since the last refresh (thus
1887 showing what the current patch would become after a qrefresh).
1887 showing what the current patch would become after a qrefresh).
1888
1888
1889 Use 'hg diff' if you only want to see the changes made since the last
1889 Use 'hg diff' if you only want to see the changes made since the last
1890 qrefresh, or 'hg export qtip' if you want to see changes made by the
1890 qrefresh, or 'hg export qtip' if you want to see changes made by the
1891 current patch without including changes made since the qrefresh.
1891 current patch without including changes made since the qrefresh.
1892 """
1892 """
1893 repo.mq.diff(repo, pats, opts)
1893 repo.mq.diff(repo, pats, opts)
1894 return 0
1894 return 0
1895
1895
1896 def fold(ui, repo, *files, **opts):
1896 def fold(ui, repo, *files, **opts):
1897 """fold the named patches into the current patch
1897 """fold the named patches into the current patch
1898
1898
1899 Patches must not yet be applied. Each patch will be successively
1899 Patches must not yet be applied. Each patch will be successively
1900 applied to the current patch in the order given. If all the
1900 applied to the current patch in the order given. If all the
1901 patches apply successfully, the current patch will be refreshed
1901 patches apply successfully, the current patch will be refreshed
1902 with the new cumulative patch, and the folded patches will
1902 with the new cumulative patch, and the folded patches will
1903 be deleted. With -k/--keep, the folded patch files will not
1903 be deleted. With -k/--keep, the folded patch files will not
1904 be removed afterwards.
1904 be removed afterwards.
1905
1905
1906 The header for each folded patch will be concatenated with
1906 The header for each folded patch will be concatenated with
1907 the current patch header, separated by a line of '* * *'."""
1907 the current patch header, separated by a line of '* * *'."""
1908
1908
1909 q = repo.mq
1909 q = repo.mq
1910
1910
1911 if not files:
1911 if not files:
1912 raise util.Abort(_('qfold requires at least one patch name'))
1912 raise util.Abort(_('qfold requires at least one patch name'))
1913 if not q.check_toppatch(repo):
1913 if not q.check_toppatch(repo):
1914 raise util.Abort(_('No patches applied'))
1914 raise util.Abort(_('No patches applied'))
1915
1915
1916 message = cmdutil.logmessage(opts)
1916 message = cmdutil.logmessage(opts)
1917 if opts['edit']:
1917 if opts['edit']:
1918 if message:
1918 if message:
1919 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1919 raise util.Abort(_('option "-e" incompatible with "-m" or "-l"'))
1920
1920
1921 parent = q.lookup('qtip')
1921 parent = q.lookup('qtip')
1922 patches = []
1922 patches = []
1923 messages = []
1923 messages = []
1924 for f in files:
1924 for f in files:
1925 p = q.lookup(f)
1925 p = q.lookup(f)
1926 if p in patches or p == parent:
1926 if p in patches or p == parent:
1927 ui.warn(_('Skipping already folded patch %s') % p)
1927 ui.warn(_('Skipping already folded patch %s') % p)
1928 if q.isapplied(p):
1928 if q.isapplied(p):
1929 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1929 raise util.Abort(_('qfold cannot fold already applied patch %s') % p)
1930 patches.append(p)
1930 patches.append(p)
1931
1931
1932 for p in patches:
1932 for p in patches:
1933 if not message:
1933 if not message:
1934 ph = q.readheaders(p)
1934 ph = q.readheaders(p)
1935 if ph.message:
1935 if ph.message:
1936 messages.append(ph.message)
1936 messages.append(ph.message)
1937 pf = q.join(p)
1937 pf = q.join(p)
1938 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1938 (patchsuccess, files, fuzz) = q.patch(repo, pf)
1939 if not patchsuccess:
1939 if not patchsuccess:
1940 raise util.Abort(_('Error folding patch %s') % p)
1940 raise util.Abort(_('Error folding patch %s') % p)
1941 patch.updatedir(ui, repo, files)
1941 patch.updatedir(ui, repo, files)
1942
1942
1943 if not message:
1943 if not message:
1944 ph = q.readheaders(parent)
1944 ph = q.readheaders(parent)
1945 message, user = ph.message, ph.user
1945 message, user = ph.message, ph.user
1946 for msg in messages:
1946 for msg in messages:
1947 message.append('* * *')
1947 message.append('* * *')
1948 message.extend(msg)
1948 message.extend(msg)
1949 message = '\n'.join(message)
1949 message = '\n'.join(message)
1950
1950
1951 if opts['edit']:
1951 if opts['edit']:
1952 message = ui.edit(message, user or ui.username())
1952 message = ui.edit(message, user or ui.username())
1953
1953
1954 q.refresh(repo, msg=message)
1954 q.refresh(repo, msg=message)
1955 q.delete(repo, patches, opts)
1955 q.delete(repo, patches, opts)
1956 q.save_dirty()
1956 q.save_dirty()
1957
1957
1958 def goto(ui, repo, patch, **opts):
1958 def goto(ui, repo, patch, **opts):
1959 '''push or pop patches until named patch is at top of stack'''
1959 '''push or pop patches until named patch is at top of stack'''
1960 q = repo.mq
1960 q = repo.mq
1961 patch = q.lookup(patch)
1961 patch = q.lookup(patch)
1962 if q.isapplied(patch):
1962 if q.isapplied(patch):
1963 ret = q.pop(repo, patch, force=opts['force'])
1963 ret = q.pop(repo, patch, force=opts['force'])
1964 else:
1964 else:
1965 ret = q.push(repo, patch, force=opts['force'])
1965 ret = q.push(repo, patch, force=opts['force'])
1966 q.save_dirty()
1966 q.save_dirty()
1967 return ret
1967 return ret
1968
1968
1969 def guard(ui, repo, *args, **opts):
1969 def guard(ui, repo, *args, **opts):
1970 '''set or print guards for a patch
1970 '''set or print guards for a patch
1971
1971
1972 Guards control whether a patch can be pushed. A patch with no
1972 Guards control whether a patch can be pushed. A patch with no
1973 guards is always pushed. A patch with a positive guard ("+foo") is
1973 guards is always pushed. A patch with a positive guard ("+foo") is
1974 pushed only if the qselect command has activated it. A patch with
1974 pushed only if the qselect command has activated it. A patch with
1975 a negative guard ("-foo") is never pushed if the qselect command
1975 a negative guard ("-foo") is never pushed if the qselect command
1976 has activated it.
1976 has activated it.
1977
1977
1978 With no arguments, print the currently active guards.
1978 With no arguments, print the currently active guards.
1979 With arguments, set guards for the named patch.
1979 With arguments, set guards for the named patch.
1980
1980
1981 To set a negative guard "-foo" on topmost patch ("--" is needed so
1981 To set a negative guard "-foo" on topmost patch ("--" is needed so
1982 hg will not interpret "-foo" as an option):
1982 hg will not interpret "-foo" as an option):
1983 hg qguard -- -foo
1983 hg qguard -- -foo
1984
1984
1985 To set guards on another patch:
1985 To set guards on another patch:
1986 hg qguard other.patch +2.6.17 -stable
1986 hg qguard other.patch +2.6.17 -stable
1987 '''
1987 '''
1988 def status(idx):
1988 def status(idx):
1989 guards = q.series_guards[idx] or ['unguarded']
1989 guards = q.series_guards[idx] or ['unguarded']
1990 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1990 ui.write('%s: %s\n' % (q.series[idx], ' '.join(guards)))
1991 q = repo.mq
1991 q = repo.mq
1992 patch = None
1992 patch = None
1993 args = list(args)
1993 args = list(args)
1994 if opts['list']:
1994 if opts['list']:
1995 if args or opts['none']:
1995 if args or opts['none']:
1996 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1996 raise util.Abort(_('cannot mix -l/--list with options or arguments'))
1997 for i in xrange(len(q.series)):
1997 for i in xrange(len(q.series)):
1998 status(i)
1998 status(i)
1999 return
1999 return
2000 if not args or args[0][0:1] in '-+':
2000 if not args or args[0][0:1] in '-+':
2001 if not q.applied:
2001 if not q.applied:
2002 raise util.Abort(_('no patches applied'))
2002 raise util.Abort(_('no patches applied'))
2003 patch = q.applied[-1].name
2003 patch = q.applied[-1].name
2004 if patch is None and args[0][0:1] not in '-+':
2004 if patch is None and args[0][0:1] not in '-+':
2005 patch = args.pop(0)
2005 patch = args.pop(0)
2006 if patch is None:
2006 if patch is None:
2007 raise util.Abort(_('no patch to work with'))
2007 raise util.Abort(_('no patch to work with'))
2008 if args or opts['none']:
2008 if args or opts['none']:
2009 idx = q.find_series(patch)
2009 idx = q.find_series(patch)
2010 if idx is None:
2010 if idx is None:
2011 raise util.Abort(_('no patch named %s') % patch)
2011 raise util.Abort(_('no patch named %s') % patch)
2012 q.set_guards(idx, args)
2012 q.set_guards(idx, args)
2013 q.save_dirty()
2013 q.save_dirty()
2014 else:
2014 else:
2015 status(q.series.index(q.lookup(patch)))
2015 status(q.series.index(q.lookup(patch)))
2016
2016
2017 def header(ui, repo, patch=None):
2017 def header(ui, repo, patch=None):
2018 """Print the header of the topmost or specified patch"""
2018 """print the header of the topmost or specified patch"""
2019 q = repo.mq
2019 q = repo.mq
2020
2020
2021 if patch:
2021 if patch:
2022 patch = q.lookup(patch)
2022 patch = q.lookup(patch)
2023 else:
2023 else:
2024 if not q.applied:
2024 if not q.applied:
2025 ui.write('No patches applied\n')
2025 ui.write('No patches applied\n')
2026 return 1
2026 return 1
2027 patch = q.lookup('qtip')
2027 patch = q.lookup('qtip')
2028 ph = repo.mq.readheaders(patch)
2028 ph = repo.mq.readheaders(patch)
2029
2029
2030 ui.write('\n'.join(ph.message) + '\n')
2030 ui.write('\n'.join(ph.message) + '\n')
2031
2031
2032 def lastsavename(path):
2032 def lastsavename(path):
2033 (directory, base) = os.path.split(path)
2033 (directory, base) = os.path.split(path)
2034 names = os.listdir(directory)
2034 names = os.listdir(directory)
2035 namere = re.compile("%s.([0-9]+)" % base)
2035 namere = re.compile("%s.([0-9]+)" % base)
2036 maxindex = None
2036 maxindex = None
2037 maxname = None
2037 maxname = None
2038 for f in names:
2038 for f in names:
2039 m = namere.match(f)
2039 m = namere.match(f)
2040 if m:
2040 if m:
2041 index = int(m.group(1))
2041 index = int(m.group(1))
2042 if maxindex == None or index > maxindex:
2042 if maxindex == None or index > maxindex:
2043 maxindex = index
2043 maxindex = index
2044 maxname = f
2044 maxname = f
2045 if maxname:
2045 if maxname:
2046 return (os.path.join(directory, maxname), maxindex)
2046 return (os.path.join(directory, maxname), maxindex)
2047 return (None, None)
2047 return (None, None)
2048
2048
2049 def savename(path):
2049 def savename(path):
2050 (last, index) = lastsavename(path)
2050 (last, index) = lastsavename(path)
2051 if last is None:
2051 if last is None:
2052 index = 0
2052 index = 0
2053 newpath = path + ".%d" % (index + 1)
2053 newpath = path + ".%d" % (index + 1)
2054 return newpath
2054 return newpath
2055
2055
2056 def push(ui, repo, patch=None, **opts):
2056 def push(ui, repo, patch=None, **opts):
2057 """push the next patch onto the stack
2057 """push the next patch onto the stack
2058
2058
2059 When --force is applied, all local changes in patched files will be lost.
2059 When --force is applied, all local changes in patched files will be lost.
2060 """
2060 """
2061 q = repo.mq
2061 q = repo.mq
2062 mergeq = None
2062 mergeq = None
2063
2063
2064 if opts['merge']:
2064 if opts['merge']:
2065 if opts['name']:
2065 if opts['name']:
2066 newpath = repo.join(opts['name'])
2066 newpath = repo.join(opts['name'])
2067 else:
2067 else:
2068 newpath, i = lastsavename(q.path)
2068 newpath, i = lastsavename(q.path)
2069 if not newpath:
2069 if not newpath:
2070 ui.warn(_("no saved queues found, please use -n\n"))
2070 ui.warn(_("no saved queues found, please use -n\n"))
2071 return 1
2071 return 1
2072 mergeq = queue(ui, repo.join(""), newpath)
2072 mergeq = queue(ui, repo.join(""), newpath)
2073 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2073 ui.warn(_("merging with queue at: %s\n") % mergeq.path)
2074 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2074 ret = q.push(repo, patch, force=opts['force'], list=opts['list'],
2075 mergeq=mergeq, all=opts.get('all'))
2075 mergeq=mergeq, all=opts.get('all'))
2076 return ret
2076 return ret
2077
2077
2078 def pop(ui, repo, patch=None, **opts):
2078 def pop(ui, repo, patch=None, **opts):
2079 """pop the current patch off the stack
2079 """pop the current patch off the stack
2080
2080
2081 By default, pops off the top of the patch stack. If given a patch name,
2081 By default, pops off the top of the patch stack. If given a patch name,
2082 keeps popping off patches until the named patch is at the top of the stack.
2082 keeps popping off patches until the named patch is at the top of the stack.
2083 """
2083 """
2084 localupdate = True
2084 localupdate = True
2085 if opts['name']:
2085 if opts['name']:
2086 q = queue(ui, repo.join(""), repo.join(opts['name']))
2086 q = queue(ui, repo.join(""), repo.join(opts['name']))
2087 ui.warn(_('using patch queue: %s\n') % q.path)
2087 ui.warn(_('using patch queue: %s\n') % q.path)
2088 localupdate = False
2088 localupdate = False
2089 else:
2089 else:
2090 q = repo.mq
2090 q = repo.mq
2091 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2091 ret = q.pop(repo, patch, force=opts['force'], update=localupdate,
2092 all=opts['all'])
2092 all=opts['all'])
2093 q.save_dirty()
2093 q.save_dirty()
2094 return ret
2094 return ret
2095
2095
2096 def rename(ui, repo, patch, name=None, **opts):
2096 def rename(ui, repo, patch, name=None, **opts):
2097 """rename a patch
2097 """rename a patch
2098
2098
2099 With one argument, renames the current patch to PATCH1.
2099 With one argument, renames the current patch to PATCH1.
2100 With two arguments, renames PATCH1 to PATCH2."""
2100 With two arguments, renames PATCH1 to PATCH2."""
2101
2101
2102 q = repo.mq
2102 q = repo.mq
2103
2103
2104 if not name:
2104 if not name:
2105 name = patch
2105 name = patch
2106 patch = None
2106 patch = None
2107
2107
2108 if patch:
2108 if patch:
2109 patch = q.lookup(patch)
2109 patch = q.lookup(patch)
2110 else:
2110 else:
2111 if not q.applied:
2111 if not q.applied:
2112 ui.write(_('No patches applied\n'))
2112 ui.write(_('No patches applied\n'))
2113 return
2113 return
2114 patch = q.lookup('qtip')
2114 patch = q.lookup('qtip')
2115 absdest = q.join(name)
2115 absdest = q.join(name)
2116 if os.path.isdir(absdest):
2116 if os.path.isdir(absdest):
2117 name = normname(os.path.join(name, os.path.basename(patch)))
2117 name = normname(os.path.join(name, os.path.basename(patch)))
2118 absdest = q.join(name)
2118 absdest = q.join(name)
2119 if os.path.exists(absdest):
2119 if os.path.exists(absdest):
2120 raise util.Abort(_('%s already exists') % absdest)
2120 raise util.Abort(_('%s already exists') % absdest)
2121
2121
2122 if name in q.series:
2122 if name in q.series:
2123 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2123 raise util.Abort(_('A patch named %s already exists in the series file') % name)
2124
2124
2125 if ui.verbose:
2125 if ui.verbose:
2126 ui.write('Renaming %s to %s\n' % (patch, name))
2126 ui.write('Renaming %s to %s\n' % (patch, name))
2127 i = q.find_series(patch)
2127 i = q.find_series(patch)
2128 guards = q.guard_re.findall(q.full_series[i])
2128 guards = q.guard_re.findall(q.full_series[i])
2129 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2129 q.full_series[i] = name + ''.join([' #' + g for g in guards])
2130 q.parse_series()
2130 q.parse_series()
2131 q.series_dirty = 1
2131 q.series_dirty = 1
2132
2132
2133 info = q.isapplied(patch)
2133 info = q.isapplied(patch)
2134 if info:
2134 if info:
2135 q.applied[info[0]] = statusentry(info[1], name)
2135 q.applied[info[0]] = statusentry(info[1], name)
2136 q.applied_dirty = 1
2136 q.applied_dirty = 1
2137
2137
2138 util.rename(q.join(patch), absdest)
2138 util.rename(q.join(patch), absdest)
2139 r = q.qrepo()
2139 r = q.qrepo()
2140 if r:
2140 if r:
2141 wlock = r.wlock()
2141 wlock = r.wlock()
2142 try:
2142 try:
2143 if r.dirstate[patch] == 'a':
2143 if r.dirstate[patch] == 'a':
2144 r.dirstate.forget(patch)
2144 r.dirstate.forget(patch)
2145 r.dirstate.add(name)
2145 r.dirstate.add(name)
2146 else:
2146 else:
2147 if r.dirstate[name] == 'r':
2147 if r.dirstate[name] == 'r':
2148 r.undelete([name])
2148 r.undelete([name])
2149 r.copy(patch, name)
2149 r.copy(patch, name)
2150 r.remove([patch], False)
2150 r.remove([patch], False)
2151 finally:
2151 finally:
2152 del wlock
2152 del wlock
2153
2153
2154 q.save_dirty()
2154 q.save_dirty()
2155
2155
2156 def restore(ui, repo, rev, **opts):
2156 def restore(ui, repo, rev, **opts):
2157 """restore the queue state saved by a rev"""
2157 """restore the queue state saved by a rev"""
2158 rev = repo.lookup(rev)
2158 rev = repo.lookup(rev)
2159 q = repo.mq
2159 q = repo.mq
2160 q.restore(repo, rev, delete=opts['delete'],
2160 q.restore(repo, rev, delete=opts['delete'],
2161 qupdate=opts['update'])
2161 qupdate=opts['update'])
2162 q.save_dirty()
2162 q.save_dirty()
2163 return 0
2163 return 0
2164
2164
2165 def save(ui, repo, **opts):
2165 def save(ui, repo, **opts):
2166 """save current queue state"""
2166 """save current queue state"""
2167 q = repo.mq
2167 q = repo.mq
2168 message = cmdutil.logmessage(opts)
2168 message = cmdutil.logmessage(opts)
2169 ret = q.save(repo, msg=message)
2169 ret = q.save(repo, msg=message)
2170 if ret:
2170 if ret:
2171 return ret
2171 return ret
2172 q.save_dirty()
2172 q.save_dirty()
2173 if opts['copy']:
2173 if opts['copy']:
2174 path = q.path
2174 path = q.path
2175 if opts['name']:
2175 if opts['name']:
2176 newpath = os.path.join(q.basepath, opts['name'])
2176 newpath = os.path.join(q.basepath, opts['name'])
2177 if os.path.exists(newpath):
2177 if os.path.exists(newpath):
2178 if not os.path.isdir(newpath):
2178 if not os.path.isdir(newpath):
2179 raise util.Abort(_('destination %s exists and is not '
2179 raise util.Abort(_('destination %s exists and is not '
2180 'a directory') % newpath)
2180 'a directory') % newpath)
2181 if not opts['force']:
2181 if not opts['force']:
2182 raise util.Abort(_('destination %s exists, '
2182 raise util.Abort(_('destination %s exists, '
2183 'use -f to force') % newpath)
2183 'use -f to force') % newpath)
2184 else:
2184 else:
2185 newpath = savename(path)
2185 newpath = savename(path)
2186 ui.warn(_("copy %s to %s\n") % (path, newpath))
2186 ui.warn(_("copy %s to %s\n") % (path, newpath))
2187 util.copyfiles(path, newpath)
2187 util.copyfiles(path, newpath)
2188 if opts['empty']:
2188 if opts['empty']:
2189 try:
2189 try:
2190 os.unlink(q.join(q.status_path))
2190 os.unlink(q.join(q.status_path))
2191 except:
2191 except:
2192 pass
2192 pass
2193 return 0
2193 return 0
2194
2194
2195 def strip(ui, repo, rev, **opts):
2195 def strip(ui, repo, rev, **opts):
2196 """strip a revision and all its descendants from the repository
2196 """strip a revision and all its descendants from the repository
2197
2197
2198 If one of the working dir's parent revisions is stripped, the working
2198 If one of the working dir's parent revisions is stripped, the working
2199 directory will be updated to the parent of the stripped revision.
2199 directory will be updated to the parent of the stripped revision.
2200 """
2200 """
2201 backup = 'all'
2201 backup = 'all'
2202 if opts['backup']:
2202 if opts['backup']:
2203 backup = 'strip'
2203 backup = 'strip'
2204 elif opts['nobackup']:
2204 elif opts['nobackup']:
2205 backup = 'none'
2205 backup = 'none'
2206
2206
2207 rev = repo.lookup(rev)
2207 rev = repo.lookup(rev)
2208 p = repo.dirstate.parents()
2208 p = repo.dirstate.parents()
2209 cl = repo.changelog
2209 cl = repo.changelog
2210 update = True
2210 update = True
2211 if p[0] == revlog.nullid:
2211 if p[0] == revlog.nullid:
2212 update = False
2212 update = False
2213 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2213 elif p[1] == revlog.nullid and rev != cl.ancestor(p[0], rev):
2214 update = False
2214 update = False
2215 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2215 elif rev not in (cl.ancestor(p[0], rev), cl.ancestor(p[1], rev)):
2216 update = False
2216 update = False
2217
2217
2218 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2218 repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
2219 return 0
2219 return 0
2220
2220
2221 def select(ui, repo, *args, **opts):
2221 def select(ui, repo, *args, **opts):
2222 '''set or print guarded patches to push
2222 '''set or print guarded patches to push
2223
2223
2224 Use the qguard command to set or print guards on patch, then use
2224 Use the qguard command to set or print guards on patch, then use
2225 qselect to tell mq which guards to use. A patch will be pushed if it
2225 qselect to tell mq which guards to use. A patch will be pushed if it
2226 has no guards or any positive guards match the currently selected guard,
2226 has no guards or any positive guards match the currently selected guard,
2227 but will not be pushed if any negative guards match the current guard.
2227 but will not be pushed if any negative guards match the current guard.
2228 For example:
2228 For example:
2229
2229
2230 qguard foo.patch -stable (negative guard)
2230 qguard foo.patch -stable (negative guard)
2231 qguard bar.patch +stable (positive guard)
2231 qguard bar.patch +stable (positive guard)
2232 qselect stable
2232 qselect stable
2233
2233
2234 This activates the "stable" guard. mq will skip foo.patch (because
2234 This activates the "stable" guard. mq will skip foo.patch (because
2235 it has a negative match) but push bar.patch (because it
2235 it has a negative match) but push bar.patch (because it
2236 has a positive match).
2236 has a positive match).
2237
2237
2238 With no arguments, prints the currently active guards.
2238 With no arguments, prints the currently active guards.
2239 With one argument, sets the active guard.
2239 With one argument, sets the active guard.
2240
2240
2241 Use -n/--none to deactivate guards (no other arguments needed).
2241 Use -n/--none to deactivate guards (no other arguments needed).
2242 When no guards are active, patches with positive guards are skipped
2242 When no guards are active, patches with positive guards are skipped
2243 and patches with negative guards are pushed.
2243 and patches with negative guards are pushed.
2244
2244
2245 qselect can change the guards on applied patches. It does not pop
2245 qselect can change the guards on applied patches. It does not pop
2246 guarded patches by default. Use --pop to pop back to the last applied
2246 guarded patches by default. Use --pop to pop back to the last applied
2247 patch that is not guarded. Use --reapply (which implies --pop) to push
2247 patch that is not guarded. Use --reapply (which implies --pop) to push
2248 back to the current patch afterwards, but skip guarded patches.
2248 back to the current patch afterwards, but skip guarded patches.
2249
2249
2250 Use -s/--series to print a list of all guards in the series file (no
2250 Use -s/--series to print a list of all guards in the series file (no
2251 other arguments needed). Use -v for more information.'''
2251 other arguments needed). Use -v for more information.'''
2252
2252
2253 q = repo.mq
2253 q = repo.mq
2254 guards = q.active()
2254 guards = q.active()
2255 if args or opts['none']:
2255 if args or opts['none']:
2256 old_unapplied = q.unapplied(repo)
2256 old_unapplied = q.unapplied(repo)
2257 old_guarded = [i for i in xrange(len(q.applied)) if
2257 old_guarded = [i for i in xrange(len(q.applied)) if
2258 not q.pushable(i)[0]]
2258 not q.pushable(i)[0]]
2259 q.set_active(args)
2259 q.set_active(args)
2260 q.save_dirty()
2260 q.save_dirty()
2261 if not args:
2261 if not args:
2262 ui.status(_('guards deactivated\n'))
2262 ui.status(_('guards deactivated\n'))
2263 if not opts['pop'] and not opts['reapply']:
2263 if not opts['pop'] and not opts['reapply']:
2264 unapplied = q.unapplied(repo)
2264 unapplied = q.unapplied(repo)
2265 guarded = [i for i in xrange(len(q.applied))
2265 guarded = [i for i in xrange(len(q.applied))
2266 if not q.pushable(i)[0]]
2266 if not q.pushable(i)[0]]
2267 if len(unapplied) != len(old_unapplied):
2267 if len(unapplied) != len(old_unapplied):
2268 ui.status(_('number of unguarded, unapplied patches has '
2268 ui.status(_('number of unguarded, unapplied patches has '
2269 'changed from %d to %d\n') %
2269 'changed from %d to %d\n') %
2270 (len(old_unapplied), len(unapplied)))
2270 (len(old_unapplied), len(unapplied)))
2271 if len(guarded) != len(old_guarded):
2271 if len(guarded) != len(old_guarded):
2272 ui.status(_('number of guarded, applied patches has changed '
2272 ui.status(_('number of guarded, applied patches has changed '
2273 'from %d to %d\n') %
2273 'from %d to %d\n') %
2274 (len(old_guarded), len(guarded)))
2274 (len(old_guarded), len(guarded)))
2275 elif opts['series']:
2275 elif opts['series']:
2276 guards = {}
2276 guards = {}
2277 noguards = 0
2277 noguards = 0
2278 for gs in q.series_guards:
2278 for gs in q.series_guards:
2279 if not gs:
2279 if not gs:
2280 noguards += 1
2280 noguards += 1
2281 for g in gs:
2281 for g in gs:
2282 guards.setdefault(g, 0)
2282 guards.setdefault(g, 0)
2283 guards[g] += 1
2283 guards[g] += 1
2284 if ui.verbose:
2284 if ui.verbose:
2285 guards['NONE'] = noguards
2285 guards['NONE'] = noguards
2286 guards = guards.items()
2286 guards = guards.items()
2287 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2287 guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
2288 if guards:
2288 if guards:
2289 ui.note(_('guards in series file:\n'))
2289 ui.note(_('guards in series file:\n'))
2290 for guard, count in guards:
2290 for guard, count in guards:
2291 ui.note('%2d ' % count)
2291 ui.note('%2d ' % count)
2292 ui.write(guard, '\n')
2292 ui.write(guard, '\n')
2293 else:
2293 else:
2294 ui.note(_('no guards in series file\n'))
2294 ui.note(_('no guards in series file\n'))
2295 else:
2295 else:
2296 if guards:
2296 if guards:
2297 ui.note(_('active guards:\n'))
2297 ui.note(_('active guards:\n'))
2298 for g in guards:
2298 for g in guards:
2299 ui.write(g, '\n')
2299 ui.write(g, '\n')
2300 else:
2300 else:
2301 ui.write(_('no active guards\n'))
2301 ui.write(_('no active guards\n'))
2302 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2302 reapply = opts['reapply'] and q.applied and q.appliedname(-1)
2303 popped = False
2303 popped = False
2304 if opts['pop'] or opts['reapply']:
2304 if opts['pop'] or opts['reapply']:
2305 for i in xrange(len(q.applied)):
2305 for i in xrange(len(q.applied)):
2306 pushable, reason = q.pushable(i)
2306 pushable, reason = q.pushable(i)
2307 if not pushable:
2307 if not pushable:
2308 ui.status(_('popping guarded patches\n'))
2308 ui.status(_('popping guarded patches\n'))
2309 popped = True
2309 popped = True
2310 if i == 0:
2310 if i == 0:
2311 q.pop(repo, all=True)
2311 q.pop(repo, all=True)
2312 else:
2312 else:
2313 q.pop(repo, i-1)
2313 q.pop(repo, i-1)
2314 break
2314 break
2315 if popped:
2315 if popped:
2316 try:
2316 try:
2317 if reapply:
2317 if reapply:
2318 ui.status(_('reapplying unguarded patches\n'))
2318 ui.status(_('reapplying unguarded patches\n'))
2319 q.push(repo, reapply)
2319 q.push(repo, reapply)
2320 finally:
2320 finally:
2321 q.save_dirty()
2321 q.save_dirty()
2322
2322
2323 def finish(ui, repo, *revrange, **opts):
2323 def finish(ui, repo, *revrange, **opts):
2324 """move applied patches into repository history
2324 """move applied patches into repository history
2325
2325
2326 Finishes the specified revisions (corresponding to applied patches) by
2326 Finishes the specified revisions (corresponding to applied patches) by
2327 moving them out of mq control into regular repository history.
2327 moving them out of mq control into regular repository history.
2328
2328
2329 Accepts a revision range or the --applied option. If --applied is
2329 Accepts a revision range or the --applied option. If --applied is
2330 specified, all applied mq revisions are removed from mq control.
2330 specified, all applied mq revisions are removed from mq control.
2331 Otherwise, the given revisions must be at the base of the stack of
2331 Otherwise, the given revisions must be at the base of the stack of
2332 applied patches.
2332 applied patches.
2333
2333
2334 This can be especially useful if your changes have been applied to an
2334 This can be especially useful if your changes have been applied to an
2335 upstream repository, or if you are about to push your changes to upstream.
2335 upstream repository, or if you are about to push your changes to upstream.
2336 """
2336 """
2337 if not opts['applied'] and not revrange:
2337 if not opts['applied'] and not revrange:
2338 raise util.Abort(_('no revisions specified'))
2338 raise util.Abort(_('no revisions specified'))
2339 elif opts['applied']:
2339 elif opts['applied']:
2340 revrange = ('qbase:qtip',) + revrange
2340 revrange = ('qbase:qtip',) + revrange
2341
2341
2342 q = repo.mq
2342 q = repo.mq
2343 if not q.applied:
2343 if not q.applied:
2344 ui.status(_('no patches applied\n'))
2344 ui.status(_('no patches applied\n'))
2345 return 0
2345 return 0
2346
2346
2347 revs = cmdutil.revrange(repo, revrange)
2347 revs = cmdutil.revrange(repo, revrange)
2348 q.finish(repo, revs)
2348 q.finish(repo, revs)
2349 q.save_dirty()
2349 q.save_dirty()
2350 return 0
2350 return 0
2351
2351
2352 def reposetup(ui, repo):
2352 def reposetup(ui, repo):
2353 class mqrepo(repo.__class__):
2353 class mqrepo(repo.__class__):
2354 def abort_if_wdir_patched(self, errmsg, force=False):
2354 def abort_if_wdir_patched(self, errmsg, force=False):
2355 if self.mq.applied and not force:
2355 if self.mq.applied and not force:
2356 parent = revlog.hex(self.dirstate.parents()[0])
2356 parent = revlog.hex(self.dirstate.parents()[0])
2357 if parent in [s.rev for s in self.mq.applied]:
2357 if parent in [s.rev for s in self.mq.applied]:
2358 raise util.Abort(errmsg)
2358 raise util.Abort(errmsg)
2359
2359
2360 def commit(self, *args, **opts):
2360 def commit(self, *args, **opts):
2361 if len(args) >= 6:
2361 if len(args) >= 6:
2362 force = args[5]
2362 force = args[5]
2363 else:
2363 else:
2364 force = opts.get('force')
2364 force = opts.get('force')
2365 self.abort_if_wdir_patched(
2365 self.abort_if_wdir_patched(
2366 _('cannot commit over an applied mq patch'),
2366 _('cannot commit over an applied mq patch'),
2367 force)
2367 force)
2368
2368
2369 return super(mqrepo, self).commit(*args, **opts)
2369 return super(mqrepo, self).commit(*args, **opts)
2370
2370
2371 def push(self, remote, force=False, revs=None):
2371 def push(self, remote, force=False, revs=None):
2372 if self.mq.applied and not force and not revs:
2372 if self.mq.applied and not force and not revs:
2373 raise util.Abort(_('source has mq patches applied'))
2373 raise util.Abort(_('source has mq patches applied'))
2374 return super(mqrepo, self).push(remote, force, revs)
2374 return super(mqrepo, self).push(remote, force, revs)
2375
2375
2376 def tags(self):
2376 def tags(self):
2377 if self.tagscache:
2377 if self.tagscache:
2378 return self.tagscache
2378 return self.tagscache
2379
2379
2380 tagscache = super(mqrepo, self).tags()
2380 tagscache = super(mqrepo, self).tags()
2381
2381
2382 q = self.mq
2382 q = self.mq
2383 if not q.applied:
2383 if not q.applied:
2384 return tagscache
2384 return tagscache
2385
2385
2386 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2386 mqtags = [(revlog.bin(patch.rev), patch.name) for patch in q.applied]
2387
2387
2388 if mqtags[-1][0] not in self.changelog.nodemap:
2388 if mqtags[-1][0] not in self.changelog.nodemap:
2389 self.ui.warn(_('mq status file refers to unknown node %s\n')
2389 self.ui.warn(_('mq status file refers to unknown node %s\n')
2390 % revlog.short(mqtags[-1][0]))
2390 % revlog.short(mqtags[-1][0]))
2391 return tagscache
2391 return tagscache
2392
2392
2393 mqtags.append((mqtags[-1][0], 'qtip'))
2393 mqtags.append((mqtags[-1][0], 'qtip'))
2394 mqtags.append((mqtags[0][0], 'qbase'))
2394 mqtags.append((mqtags[0][0], 'qbase'))
2395 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2395 mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
2396 for patch in mqtags:
2396 for patch in mqtags:
2397 if patch[1] in tagscache:
2397 if patch[1] in tagscache:
2398 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2398 self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
2399 % patch[1])
2399 % patch[1])
2400 else:
2400 else:
2401 tagscache[patch[1]] = patch[0]
2401 tagscache[patch[1]] = patch[0]
2402
2402
2403 return tagscache
2403 return tagscache
2404
2404
2405 def _branchtags(self, partial, lrev):
2405 def _branchtags(self, partial, lrev):
2406 q = self.mq
2406 q = self.mq
2407 if not q.applied:
2407 if not q.applied:
2408 return super(mqrepo, self)._branchtags(partial, lrev)
2408 return super(mqrepo, self)._branchtags(partial, lrev)
2409
2409
2410 cl = self.changelog
2410 cl = self.changelog
2411 qbasenode = revlog.bin(q.applied[0].rev)
2411 qbasenode = revlog.bin(q.applied[0].rev)
2412 if qbasenode not in cl.nodemap:
2412 if qbasenode not in cl.nodemap:
2413 self.ui.warn(_('mq status file refers to unknown node %s\n')
2413 self.ui.warn(_('mq status file refers to unknown node %s\n')
2414 % revlog.short(qbasenode))
2414 % revlog.short(qbasenode))
2415 return super(mqrepo, self)._branchtags(partial, lrev)
2415 return super(mqrepo, self)._branchtags(partial, lrev)
2416
2416
2417 qbase = cl.rev(qbasenode)
2417 qbase = cl.rev(qbasenode)
2418 start = lrev + 1
2418 start = lrev + 1
2419 if start < qbase:
2419 if start < qbase:
2420 # update the cache (excluding the patches) and save it
2420 # update the cache (excluding the patches) and save it
2421 self._updatebranchcache(partial, lrev+1, qbase)
2421 self._updatebranchcache(partial, lrev+1, qbase)
2422 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2422 self._writebranchcache(partial, cl.node(qbase-1), qbase-1)
2423 start = qbase
2423 start = qbase
2424 # if start = qbase, the cache is as updated as it should be.
2424 # if start = qbase, the cache is as updated as it should be.
2425 # if start > qbase, the cache includes (part of) the patches.
2425 # if start > qbase, the cache includes (part of) the patches.
2426 # we might as well use it, but we won't save it.
2426 # we might as well use it, but we won't save it.
2427
2427
2428 # update the cache up to the tip
2428 # update the cache up to the tip
2429 self._updatebranchcache(partial, start, len(cl))
2429 self._updatebranchcache(partial, start, len(cl))
2430
2430
2431 return partial
2431 return partial
2432
2432
2433 if repo.local():
2433 if repo.local():
2434 repo.__class__ = mqrepo
2434 repo.__class__ = mqrepo
2435 repo.mq = queue(ui, repo.join(""))
2435 repo.mq = queue(ui, repo.join(""))
2436
2436
2437 def mqimport(orig, ui, repo, *args, **kwargs):
2437 def mqimport(orig, ui, repo, *args, **kwargs):
2438 if hasattr(repo, 'abort_if_wdir_patched'):
2438 if hasattr(repo, 'abort_if_wdir_patched'):
2439 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2439 repo.abort_if_wdir_patched(_('cannot import over an applied patch'),
2440 kwargs.get('force'))
2440 kwargs.get('force'))
2441 return orig(ui, repo, *args, **kwargs)
2441 return orig(ui, repo, *args, **kwargs)
2442
2442
2443 def uisetup(ui):
2443 def uisetup(ui):
2444 extensions.wrapcommand(commands.table, 'import', mqimport)
2444 extensions.wrapcommand(commands.table, 'import', mqimport)
2445
2445
2446 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2446 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2447
2447
2448 cmdtable = {
2448 cmdtable = {
2449 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2449 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2450 "qclone":
2450 "qclone":
2451 (clone,
2451 (clone,
2452 [('', 'pull', None, _('use pull protocol to copy metadata')),
2452 [('', 'pull', None, _('use pull protocol to copy metadata')),
2453 ('U', 'noupdate', None, _('do not update the new working directories')),
2453 ('U', 'noupdate', None, _('do not update the new working directories')),
2454 ('', 'uncompressed', None,
2454 ('', 'uncompressed', None,
2455 _('use uncompressed transfer (fast over LAN)')),
2455 _('use uncompressed transfer (fast over LAN)')),
2456 ('p', 'patches', '', _('location of source patch repo')),
2456 ('p', 'patches', '', _('location of source patch repo')),
2457 ] + commands.remoteopts,
2457 ] + commands.remoteopts,
2458 _('hg qclone [OPTION]... SOURCE [DEST]')),
2458 _('hg qclone [OPTION]... SOURCE [DEST]')),
2459 "qcommit|qci":
2459 "qcommit|qci":
2460 (commit,
2460 (commit,
2461 commands.table["^commit|ci"][1],
2461 commands.table["^commit|ci"][1],
2462 _('hg qcommit [OPTION]... [FILE]...')),
2462 _('hg qcommit [OPTION]... [FILE]...')),
2463 "^qdiff":
2463 "^qdiff":
2464 (diff,
2464 (diff,
2465 commands.diffopts + commands.diffopts2 + commands.walkopts,
2465 commands.diffopts + commands.diffopts2 + commands.walkopts,
2466 _('hg qdiff [OPTION]... [FILE]...')),
2466 _('hg qdiff [OPTION]... [FILE]...')),
2467 "qdelete|qremove|qrm":
2467 "qdelete|qremove|qrm":
2468 (delete,
2468 (delete,
2469 [('k', 'keep', None, _('keep patch file')),
2469 [('k', 'keep', None, _('keep patch file')),
2470 ('r', 'rev', [], _('stop managing a revision'))],
2470 ('r', 'rev', [], _('stop managing a revision'))],
2471 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2471 _('hg qdelete [-k] [-r REV]... [PATCH]...')),
2472 'qfold':
2472 'qfold':
2473 (fold,
2473 (fold,
2474 [('e', 'edit', None, _('edit patch header')),
2474 [('e', 'edit', None, _('edit patch header')),
2475 ('k', 'keep', None, _('keep folded patch files')),
2475 ('k', 'keep', None, _('keep folded patch files')),
2476 ] + commands.commitopts,
2476 ] + commands.commitopts,
2477 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2477 _('hg qfold [-e] [-k] [-m TEXT] [-l FILE] PATCH...')),
2478 'qgoto':
2478 'qgoto':
2479 (goto,
2479 (goto,
2480 [('f', 'force', None, _('overwrite any local changes'))],
2480 [('f', 'force', None, _('overwrite any local changes'))],
2481 _('hg qgoto [OPTION]... PATCH')),
2481 _('hg qgoto [OPTION]... PATCH')),
2482 'qguard':
2482 'qguard':
2483 (guard,
2483 (guard,
2484 [('l', 'list', None, _('list all patches and guards')),
2484 [('l', 'list', None, _('list all patches and guards')),
2485 ('n', 'none', None, _('drop all guards'))],
2485 ('n', 'none', None, _('drop all guards'))],
2486 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2486 _('hg qguard [-l] [-n] [PATCH] [+GUARD]... [-GUARD]...')),
2487 'qheader': (header, [], _('hg qheader [PATCH]')),
2487 'qheader': (header, [], _('hg qheader [PATCH]')),
2488 "^qimport":
2488 "^qimport":
2489 (qimport,
2489 (qimport,
2490 [('e', 'existing', None, _('import file in patch dir')),
2490 [('e', 'existing', None, _('import file in patch dir')),
2491 ('n', 'name', '', _('patch file name')),
2491 ('n', 'name', '', _('patch file name')),
2492 ('f', 'force', None, _('overwrite existing files')),
2492 ('f', 'force', None, _('overwrite existing files')),
2493 ('r', 'rev', [], _('place existing revisions under mq control')),
2493 ('r', 'rev', [], _('place existing revisions under mq control')),
2494 ('g', 'git', None, _('use git extended diff format'))],
2494 ('g', 'git', None, _('use git extended diff format'))],
2495 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2495 _('hg qimport [-e] [-n NAME] [-f] [-g] [-r REV]... FILE...')),
2496 "^qinit":
2496 "^qinit":
2497 (init,
2497 (init,
2498 [('c', 'create-repo', None, _('create queue repository'))],
2498 [('c', 'create-repo', None, _('create queue repository'))],
2499 _('hg qinit [-c]')),
2499 _('hg qinit [-c]')),
2500 "qnew":
2500 "qnew":
2501 (new,
2501 (new,
2502 [('e', 'edit', None, _('edit commit message')),
2502 [('e', 'edit', None, _('edit commit message')),
2503 ('f', 'force', None, _('import uncommitted changes into patch')),
2503 ('f', 'force', None, _('import uncommitted changes into patch')),
2504 ('g', 'git', None, _('use git extended diff format')),
2504 ('g', 'git', None, _('use git extended diff format')),
2505 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2505 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2506 ('u', 'user', '', _('add "From: <given user>" to patch')),
2506 ('u', 'user', '', _('add "From: <given user>" to patch')),
2507 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2507 ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
2508 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2508 ('d', 'date', '', _('add "Date: <given date>" to patch'))
2509 ] + commands.walkopts + commands.commitopts,
2509 ] + commands.walkopts + commands.commitopts,
2510 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2510 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2511 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2511 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2512 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2512 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2513 "^qpop":
2513 "^qpop":
2514 (pop,
2514 (pop,
2515 [('a', 'all', None, _('pop all patches')),
2515 [('a', 'all', None, _('pop all patches')),
2516 ('n', 'name', '', _('queue name to pop')),
2516 ('n', 'name', '', _('queue name to pop')),
2517 ('f', 'force', None, _('forget any local changes'))],
2517 ('f', 'force', None, _('forget any local changes'))],
2518 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2518 _('hg qpop [-a] [-n NAME] [-f] [PATCH | INDEX]')),
2519 "^qpush":
2519 "^qpush":
2520 (push,
2520 (push,
2521 [('f', 'force', None, _('apply if the patch has rejects')),
2521 [('f', 'force', None, _('apply if the patch has rejects')),
2522 ('l', 'list', None, _('list patch name in commit text')),
2522 ('l', 'list', None, _('list patch name in commit text')),
2523 ('a', 'all', None, _('apply all patches')),
2523 ('a', 'all', None, _('apply all patches')),
2524 ('m', 'merge', None, _('merge from another queue')),
2524 ('m', 'merge', None, _('merge from another queue')),
2525 ('n', 'name', '', _('merge queue name'))],
2525 ('n', 'name', '', _('merge queue name'))],
2526 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2526 _('hg qpush [-f] [-l] [-a] [-m] [-n NAME] [PATCH | INDEX]')),
2527 "^qrefresh":
2527 "^qrefresh":
2528 (refresh,
2528 (refresh,
2529 [('e', 'edit', None, _('edit commit message')),
2529 [('e', 'edit', None, _('edit commit message')),
2530 ('g', 'git', None, _('use git extended diff format')),
2530 ('g', 'git', None, _('use git extended diff format')),
2531 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2531 ('s', 'short', None, _('refresh only files already in the patch and specified files')),
2532 ('U', 'currentuser', None, _('add/update "From: <current user>" in patch')),
2532 ('U', 'currentuser', None, _('add/update "From: <current user>" in patch')),
2533 ('u', 'user', '', _('add/update "From: <given user>" in patch')),
2533 ('u', 'user', '', _('add/update "From: <given user>" in patch')),
2534 ('D', 'currentdate', None, _('update "Date: <current date>" in patch (if present)')),
2534 ('D', 'currentdate', None, _('update "Date: <current date>" in patch (if present)')),
2535 ('d', 'date', '', _('update "Date: <given date>" in patch (if present)'))
2535 ('d', 'date', '', _('update "Date: <given date>" in patch (if present)'))
2536 ] + commands.walkopts + commands.commitopts,
2536 ] + commands.walkopts + commands.commitopts,
2537 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2537 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2538 'qrename|qmv':
2538 'qrename|qmv':
2539 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2539 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2540 "qrestore":
2540 "qrestore":
2541 (restore,
2541 (restore,
2542 [('d', 'delete', None, _('delete save entry')),
2542 [('d', 'delete', None, _('delete save entry')),
2543 ('u', 'update', None, _('update queue working dir'))],
2543 ('u', 'update', None, _('update queue working dir'))],
2544 _('hg qrestore [-d] [-u] REV')),
2544 _('hg qrestore [-d] [-u] REV')),
2545 "qsave":
2545 "qsave":
2546 (save,
2546 (save,
2547 [('c', 'copy', None, _('copy patch directory')),
2547 [('c', 'copy', None, _('copy patch directory')),
2548 ('n', 'name', '', _('copy directory name')),
2548 ('n', 'name', '', _('copy directory name')),
2549 ('e', 'empty', None, _('clear queue status file')),
2549 ('e', 'empty', None, _('clear queue status file')),
2550 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2550 ('f', 'force', None, _('force copy'))] + commands.commitopts,
2551 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2551 _('hg qsave [-m TEXT] [-l FILE] [-c] [-n NAME] [-e] [-f]')),
2552 "qselect":
2552 "qselect":
2553 (select,
2553 (select,
2554 [('n', 'none', None, _('disable all guards')),
2554 [('n', 'none', None, _('disable all guards')),
2555 ('s', 'series', None, _('list all guards in series file')),
2555 ('s', 'series', None, _('list all guards in series file')),
2556 ('', 'pop', None, _('pop to before first guarded applied patch')),
2556 ('', 'pop', None, _('pop to before first guarded applied patch')),
2557 ('', 'reapply', None, _('pop, then reapply patches'))],
2557 ('', 'reapply', None, _('pop, then reapply patches'))],
2558 _('hg qselect [OPTION]... [GUARD]...')),
2558 _('hg qselect [OPTION]... [GUARD]...')),
2559 "qseries":
2559 "qseries":
2560 (series,
2560 (series,
2561 [('m', 'missing', None, _('print patches not in series')),
2561 [('m', 'missing', None, _('print patches not in series')),
2562 ] + seriesopts,
2562 ] + seriesopts,
2563 _('hg qseries [-ms]')),
2563 _('hg qseries [-ms]')),
2564 "^strip":
2564 "^strip":
2565 (strip,
2565 (strip,
2566 [('f', 'force', None, _('force removal with local changes')),
2566 [('f', 'force', None, _('force removal with local changes')),
2567 ('b', 'backup', None, _('bundle unrelated changesets')),
2567 ('b', 'backup', None, _('bundle unrelated changesets')),
2568 ('n', 'nobackup', None, _('no backups'))],
2568 ('n', 'nobackup', None, _('no backups'))],
2569 _('hg strip [-f] [-b] [-n] REV')),
2569 _('hg strip [-f] [-b] [-n] REV')),
2570 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2570 "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
2571 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2571 "qunapplied": (unapplied, [] + seriesopts, _('hg qunapplied [-s] [PATCH]')),
2572 "qfinish":
2572 "qfinish":
2573 (finish,
2573 (finish,
2574 [('a', 'applied', None, _('finish all applied changesets'))],
2574 [('a', 'applied', None, _('finish all applied changesets'))],
2575 _('hg qfinish [-a] [REV...]')),
2575 _('hg qfinish [-a] [REV...]')),
2576 }
2576 }
@@ -1,122 +1,122 b''
1 # win32mbcs.py -- MBCS filename support for Mercurial
1 # win32mbcs.py -- MBCS filename support for Mercurial
2 #
2 #
3 # Copyright (c) 2008 Shun-ichi Goto <shunichi.goto@gmail.com>
3 # Copyright (c) 2008 Shun-ichi Goto <shunichi.goto@gmail.com>
4 #
4 #
5 # Version: 0.2
5 # Version: 0.2
6 # Author: Shun-ichi Goto <shunichi.goto@gmail.com>
6 # Author: Shun-ichi Goto <shunichi.goto@gmail.com>
7 #
7 #
8 # This software may be used and distributed according to the terms
8 # This software may be used and distributed according to the terms
9 # of the GNU General Public License, incorporated herein by reference.
9 # of the GNU General Public License, incorporated herein by reference.
10 #
10 #
11 """Allow to use MBCS path with problematic encoding.
11 """allow to use MBCS path with problematic encoding.
12
12
13 Some MBCS encodings are not good for some path operations
13 Some MBCS encodings are not good for some path operations
14 (i.e. splitting path, case conversion, etc.) with its encoded bytes.
14 (i.e. splitting path, case conversion, etc.) with its encoded bytes.
15 We call such a encoding (i.e. shift_jis and big5) as "problematic
15 We call such a encoding (i.e. shift_jis and big5) as "problematic
16 encoding". This extension can be used to fix the issue with those
16 encoding". This extension can be used to fix the issue with those
17 encodings by wrapping some functions to convert to unicode string
17 encodings by wrapping some functions to convert to unicode string
18 before path operation.
18 before path operation.
19
19
20 This extension is usefull for:
20 This extension is usefull for:
21 * Japanese Windows users using shift_jis encoding.
21 * Japanese Windows users using shift_jis encoding.
22 * Chinese Windows users using big5 encoding.
22 * Chinese Windows users using big5 encoding.
23 * All users who use a repository with one of problematic encodings
23 * All users who use a repository with one of problematic encodings
24 on case-insensitive file system.
24 on case-insensitive file system.
25
25
26 This extension is not needed for:
26 This extension is not needed for:
27 * Any user who use only ascii chars in path.
27 * Any user who use only ascii chars in path.
28 * Any user who do not use any of problematic encodings.
28 * Any user who do not use any of problematic encodings.
29
29
30 Note that there are some limitations on using this extension:
30 Note that there are some limitations on using this extension:
31 * You should use single encoding in one repository.
31 * You should use single encoding in one repository.
32 * You should set same encoding for the repository by locale or HGENCODING.
32 * You should set same encoding for the repository by locale or HGENCODING.
33
33
34 To use this extension, enable the extension in .hg/hgrc or ~/.hgrc:
34 To use this extension, enable the extension in .hg/hgrc or ~/.hgrc:
35
35
36 [extensions]
36 [extensions]
37 hgext.win32mbcs =
37 hgext.win32mbcs =
38
38
39 Path encoding conversion are done between unicode and util._encoding
39 Path encoding conversion are done between unicode and util._encoding
40 which is decided by mercurial from current locale setting or HGENCODING.
40 which is decided by mercurial from current locale setting or HGENCODING.
41
41
42 """
42 """
43
43
44 import os
44 import os
45 from mercurial.i18n import _
45 from mercurial.i18n import _
46 from mercurial import util
46 from mercurial import util
47
47
48 def decode(arg):
48 def decode(arg):
49 if isinstance(arg, str):
49 if isinstance(arg, str):
50 uarg = arg.decode(util._encoding)
50 uarg = arg.decode(util._encoding)
51 if arg == uarg.encode(util._encoding):
51 if arg == uarg.encode(util._encoding):
52 return uarg
52 return uarg
53 raise UnicodeError("Not local encoding")
53 raise UnicodeError("Not local encoding")
54 elif isinstance(arg, tuple):
54 elif isinstance(arg, tuple):
55 return tuple(map(decode, arg))
55 return tuple(map(decode, arg))
56 elif isinstance(arg, list):
56 elif isinstance(arg, list):
57 return map(decode, arg)
57 return map(decode, arg)
58 return arg
58 return arg
59
59
60 def encode(arg):
60 def encode(arg):
61 if isinstance(arg, unicode):
61 if isinstance(arg, unicode):
62 return arg.encode(util._encoding)
62 return arg.encode(util._encoding)
63 elif isinstance(arg, tuple):
63 elif isinstance(arg, tuple):
64 return tuple(map(encode, arg))
64 return tuple(map(encode, arg))
65 elif isinstance(arg, list):
65 elif isinstance(arg, list):
66 return map(encode, arg)
66 return map(encode, arg)
67 return arg
67 return arg
68
68
69 def wrapper(func, args):
69 def wrapper(func, args):
70 # check argument is unicode, then call original
70 # check argument is unicode, then call original
71 for arg in args:
71 for arg in args:
72 if isinstance(arg, unicode):
72 if isinstance(arg, unicode):
73 return func(*args)
73 return func(*args)
74
74
75 try:
75 try:
76 # convert arguments to unicode, call func, then convert back
76 # convert arguments to unicode, call func, then convert back
77 return encode(func(*decode(args)))
77 return encode(func(*decode(args)))
78 except UnicodeError:
78 except UnicodeError:
79 # If not encoded with util._encoding, report it then
79 # If not encoded with util._encoding, report it then
80 # continue with calling original function.
80 # continue with calling original function.
81 raise util.Abort(_("[win32mbcs] filename conversion fail with"
81 raise util.Abort(_("[win32mbcs] filename conversion fail with"
82 " %s encoding\n") % (util._encoding))
82 " %s encoding\n") % (util._encoding))
83
83
84 def wrapname(name):
84 def wrapname(name):
85 idx = name.rfind('.')
85 idx = name.rfind('.')
86 module = name[:idx]
86 module = name[:idx]
87 name = name[idx+1:]
87 name = name[idx+1:]
88 module = eval(module)
88 module = eval(module)
89 func = getattr(module, name)
89 func = getattr(module, name)
90 def f(*args):
90 def f(*args):
91 return wrapper(func, args)
91 return wrapper(func, args)
92 try:
92 try:
93 f.__name__ = func.__name__ # fail with python23
93 f.__name__ = func.__name__ # fail with python23
94 except Exception:
94 except Exception:
95 pass
95 pass
96 setattr(module, name, f)
96 setattr(module, name, f)
97
97
98 # List of functions to be wrapped.
98 # List of functions to be wrapped.
99 # NOTE: os.path.dirname() and os.path.basename() are safe because
99 # NOTE: os.path.dirname() and os.path.basename() are safe because
100 # they use result of os.path.split()
100 # they use result of os.path.split()
101 funcs = '''os.path.join os.path.split os.path.splitext
101 funcs = '''os.path.join os.path.split os.path.splitext
102 os.path.splitunc os.path.normpath os.path.normcase os.makedirs
102 os.path.splitunc os.path.normpath os.path.normcase os.makedirs
103 util.endswithsep util.splitpath util.checkcase util.fspath'''
103 util.endswithsep util.splitpath util.checkcase util.fspath'''
104
104
105 # codec and alias names of sjis and big5 to be faked.
105 # codec and alias names of sjis and big5 to be faked.
106 problematic_encodings = '''big5 big5-tw csbig5 big5hkscs big5-hkscs
106 problematic_encodings = '''big5 big5-tw csbig5 big5hkscs big5-hkscs
107 hkscs cp932 932 ms932 mskanji ms-kanji shift_jis csshiftjis shiftjis
107 hkscs cp932 932 ms932 mskanji ms-kanji shift_jis csshiftjis shiftjis
108 sjis s_jis shift_jis_2004 shiftjis2004 sjis_2004 sjis2004
108 sjis s_jis shift_jis_2004 shiftjis2004 sjis_2004 sjis2004
109 shift_jisx0213 shiftjisx0213 sjisx0213 s_jisx0213'''
109 shift_jisx0213 shiftjisx0213 sjisx0213 s_jisx0213'''
110
110
111 def reposetup(ui, repo):
111 def reposetup(ui, repo):
112 # TODO: decide use of config section for this extension
112 # TODO: decide use of config section for this extension
113 if not os.path.supports_unicode_filenames:
113 if not os.path.supports_unicode_filenames:
114 ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
114 ui.warn(_("[win32mbcs] cannot activate on this platform.\n"))
115 return
115 return
116
116
117 # fake is only for relevant environment.
117 # fake is only for relevant environment.
118 if util._encoding.lower() in problematic_encodings.split():
118 if util._encoding.lower() in problematic_encodings.split():
119 for f in funcs.split():
119 for f in funcs.split():
120 wrapname(f)
120 wrapname(f)
121 ui.debug(_("[win32mbcs] activated with encoding: %s\n") % util._encoding)
121 ui.debug(_("[win32mbcs] activated with encoding: %s\n") % util._encoding)
122
122
@@ -1,3418 +1,3418 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
11 import os, re, sys
12 import hg, util, revlog, bundlerepo, extensions, copies, context
12 import hg, util, revlog, bundlerepo, extensions, copies, context
13 import difflib, patch, time, help, mdiff, tempfile, url
13 import difflib, patch, time, help, mdiff, tempfile, url
14 import version
14 import version
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(_('no working directory: please specify a revision'))
159 raise util.Abort(_('no working directory: please specify a revision'))
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(repo[nodes[0]])
291 displayer.show(repo[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(repo[n])
297 displayer.show(repo[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 commandpath = util.find_exe(command)
331 commandpath = util.find_exe(command)
332 changesets = 1
332 changesets = 1
333 try:
333 try:
334 while changesets:
334 while changesets:
335 # update state
335 # update state
336 status = os.spawnl(os.P_WAIT, commandpath)
336 status = os.spawnl(os.P_WAIT, commandpath)
337 if status == 125:
337 if status == 125:
338 transition = "skip"
338 transition = "skip"
339 elif status == 0:
339 elif status == 0:
340 transition = "good"
340 transition = "good"
341 # status < 0 means process was killed
341 # status < 0 means process was killed
342 elif status == 127:
342 elif status == 127:
343 raise util.Abort(_("failed to execute %s") % command)
343 raise util.Abort(_("failed to execute %s") % command)
344 elif status < 0:
344 elif status < 0:
345 raise util.Abort(_("%s killed") % command)
345 raise util.Abort(_("%s killed") % command)
346 else:
346 else:
347 transition = "bad"
347 transition = "bad"
348 node = repo.lookup(rev or '.')
348 node = repo.lookup(rev or '.')
349 state[transition].append(node)
349 state[transition].append(node)
350 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
350 ui.note(_('Changeset %s: %s\n') % (short(node), transition))
351 check_state(state, interactive=False)
351 check_state(state, interactive=False)
352 # bisect
352 # bisect
353 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
353 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
354 # update to next check
354 # update to next check
355 cmdutil.bail_if_changed(repo)
355 cmdutil.bail_if_changed(repo)
356 hg.clean(repo, nodes[0], show_stats=False)
356 hg.clean(repo, nodes[0], show_stats=False)
357 finally:
357 finally:
358 hbisect.save_state(repo, state)
358 hbisect.save_state(repo, state)
359 return print_result(nodes, not status)
359 return print_result(nodes, not status)
360
360
361 # update state
361 # update state
362 node = repo.lookup(rev or '.')
362 node = repo.lookup(rev or '.')
363 if good:
363 if good:
364 state['good'].append(node)
364 state['good'].append(node)
365 elif bad:
365 elif bad:
366 state['bad'].append(node)
366 state['bad'].append(node)
367 elif skip:
367 elif skip:
368 state['skip'].append(node)
368 state['skip'].append(node)
369
369
370 hbisect.save_state(repo, state)
370 hbisect.save_state(repo, state)
371
371
372 if not check_state(state):
372 if not check_state(state):
373 return
373 return
374
374
375 # actually bisect
375 # actually bisect
376 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
376 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
377 if changesets == 0:
377 if changesets == 0:
378 print_result(nodes, good)
378 print_result(nodes, good)
379 else:
379 else:
380 assert len(nodes) == 1 # only a single node can be tested next
380 assert len(nodes) == 1 # only a single node can be tested next
381 node = nodes[0]
381 node = nodes[0]
382 # compute the approximate number of remaining tests
382 # compute the approximate number of remaining tests
383 tests, size = 0, 2
383 tests, size = 0, 2
384 while size <= changesets:
384 while size <= changesets:
385 tests, size = tests + 1, size * 2
385 tests, size = tests + 1, size * 2
386 rev = repo.changelog.rev(node)
386 rev = repo.changelog.rev(node)
387 ui.write(_("Testing changeset %s:%s "
387 ui.write(_("Testing changeset %s:%s "
388 "(%s changesets remaining, ~%s tests)\n")
388 "(%s changesets remaining, ~%s tests)\n")
389 % (rev, short(node), changesets, tests))
389 % (rev, short(node), changesets, tests))
390 if not noupdate:
390 if not noupdate:
391 cmdutil.bail_if_changed(repo)
391 cmdutil.bail_if_changed(repo)
392 return hg.clean(repo, node)
392 return hg.clean(repo, node)
393
393
394 def branch(ui, repo, label=None, **opts):
394 def branch(ui, repo, label=None, **opts):
395 """set or show the current branch name
395 """set or show the current branch name
396
396
397 With no argument, show the current branch name. With one argument,
397 With no argument, show the current branch name. With one argument,
398 set the working directory branch name (the branch does not exist in
398 set the working directory branch name (the branch does not exist in
399 the repository until the next commit).
399 the repository until the next commit).
400
400
401 Unless --force is specified, branch will not let you set a
401 Unless --force is specified, branch will not let you set a
402 branch name that shadows an existing branch.
402 branch name that shadows an existing branch.
403
403
404 Use --clean to reset the working directory branch to that of the
404 Use --clean to reset the working directory branch to that of the
405 parent of the working directory, negating a previous branch change.
405 parent of the working directory, negating a previous branch change.
406
406
407 Use the command 'hg update' to switch to an existing branch.
407 Use the command 'hg update' to switch to an existing branch.
408 """
408 """
409
409
410 if opts.get('clean'):
410 if opts.get('clean'):
411 label = repo[None].parents()[0].branch()
411 label = repo[None].parents()[0].branch()
412 repo.dirstate.setbranch(label)
412 repo.dirstate.setbranch(label)
413 ui.status(_('reset working directory to branch %s\n') % label)
413 ui.status(_('reset working directory to branch %s\n') % label)
414 elif label:
414 elif label:
415 if not opts.get('force') and label in repo.branchtags():
415 if not opts.get('force') and label in repo.branchtags():
416 if label not in [p.branch() for p in repo.parents()]:
416 if label not in [p.branch() for p in repo.parents()]:
417 raise util.Abort(_('a branch of the same name already exists'
417 raise util.Abort(_('a branch of the same name already exists'
418 ' (use --force to override)'))
418 ' (use --force to override)'))
419 repo.dirstate.setbranch(util.fromlocal(label))
419 repo.dirstate.setbranch(util.fromlocal(label))
420 ui.status(_('marked working directory as branch %s\n') % label)
420 ui.status(_('marked working directory as branch %s\n') % label)
421 else:
421 else:
422 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
422 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
423
423
424 def branches(ui, repo, active=False):
424 def branches(ui, repo, active=False):
425 """list repository named branches
425 """list repository named branches
426
426
427 List the repository's named branches, indicating which ones are
427 List the repository's named branches, indicating which ones are
428 inactive. If active is specified, only show active branches.
428 inactive. If active is specified, only show active branches.
429
429
430 A branch is considered active if it contains repository heads.
430 A branch is considered active if it contains repository heads.
431
431
432 Use the command 'hg update' to switch to an existing branch.
432 Use the command 'hg update' to switch to an existing branch.
433 """
433 """
434 hexfunc = ui.debugflag and hex or short
434 hexfunc = ui.debugflag and hex or short
435 activebranches = [util.tolocal(repo[n].branch())
435 activebranches = [util.tolocal(repo[n].branch())
436 for n in repo.heads()]
436 for n in repo.heads()]
437 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
437 branches = util.sort([(tag in activebranches, repo.changelog.rev(node), tag)
438 for tag, node in repo.branchtags().items()])
438 for tag, node in repo.branchtags().items()])
439 branches.reverse()
439 branches.reverse()
440
440
441 for isactive, node, tag in branches:
441 for isactive, node, tag in branches:
442 if (not active) or isactive:
442 if (not active) or isactive:
443 if ui.quiet:
443 if ui.quiet:
444 ui.write("%s\n" % tag)
444 ui.write("%s\n" % tag)
445 else:
445 else:
446 rev = str(node).rjust(31 - util.locallen(tag))
446 rev = str(node).rjust(31 - util.locallen(tag))
447 isinactive = ((not isactive) and " (inactive)") or ''
447 isinactive = ((not isactive) and " (inactive)") or ''
448 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
448 data = tag, rev, hexfunc(repo.lookup(node)), isinactive
449 ui.write("%s %s:%s%s\n" % data)
449 ui.write("%s %s:%s%s\n" % data)
450
450
451 def bundle(ui, repo, fname, dest=None, **opts):
451 def bundle(ui, repo, fname, dest=None, **opts):
452 """create a changegroup file
452 """create a changegroup file
453
453
454 Generate a compressed changegroup file collecting changesets not
454 Generate a compressed changegroup file collecting changesets not
455 found in the other repository.
455 found in the other repository.
456
456
457 If no destination repository is specified the destination is
457 If no destination repository is specified the destination is
458 assumed to have all the nodes specified by one or more --base
458 assumed to have all the nodes specified by one or more --base
459 parameters. To create a bundle containing all changesets, use
459 parameters. To create a bundle containing all changesets, use
460 --all (or --base null). To change the compression method applied,
460 --all (or --base null). To change the compression method applied,
461 use the -t option (by default, bundles are compressed using bz2).
461 use the -t option (by default, bundles are compressed using bz2).
462
462
463 The bundle file can then be transferred using conventional means and
463 The bundle file can then be transferred using conventional means and
464 applied to another repository with the unbundle or pull command.
464 applied to another repository with the unbundle or pull command.
465 This is useful when direct push and pull are not available or when
465 This is useful when direct push and pull are not available or when
466 exporting an entire repository is undesirable.
466 exporting an entire repository is undesirable.
467
467
468 Applying bundles preserves all changeset contents including
468 Applying bundles preserves all changeset contents including
469 permissions, copy/rename information, and revision history.
469 permissions, copy/rename information, and revision history.
470 """
470 """
471 revs = opts.get('rev') or None
471 revs = opts.get('rev') or None
472 if revs:
472 if revs:
473 revs = [repo.lookup(rev) for rev in revs]
473 revs = [repo.lookup(rev) for rev in revs]
474 if opts.get('all'):
474 if opts.get('all'):
475 base = ['null']
475 base = ['null']
476 else:
476 else:
477 base = opts.get('base')
477 base = opts.get('base')
478 if base:
478 if base:
479 if dest:
479 if dest:
480 raise util.Abort(_("--base is incompatible with specifiying "
480 raise util.Abort(_("--base is incompatible with specifiying "
481 "a destination"))
481 "a destination"))
482 base = [repo.lookup(rev) for rev in base]
482 base = [repo.lookup(rev) for rev in base]
483 # create the right base
483 # create the right base
484 # XXX: nodesbetween / changegroup* should be "fixed" instead
484 # XXX: nodesbetween / changegroup* should be "fixed" instead
485 o = []
485 o = []
486 has = {nullid: None}
486 has = {nullid: None}
487 for n in base:
487 for n in base:
488 has.update(repo.changelog.reachable(n))
488 has.update(repo.changelog.reachable(n))
489 if revs:
489 if revs:
490 visit = list(revs)
490 visit = list(revs)
491 else:
491 else:
492 visit = repo.changelog.heads()
492 visit = repo.changelog.heads()
493 seen = {}
493 seen = {}
494 while visit:
494 while visit:
495 n = visit.pop(0)
495 n = visit.pop(0)
496 parents = [p for p in repo.changelog.parents(n) if p not in has]
496 parents = [p for p in repo.changelog.parents(n) if p not in has]
497 if len(parents) == 0:
497 if len(parents) == 0:
498 o.insert(0, n)
498 o.insert(0, n)
499 else:
499 else:
500 for p in parents:
500 for p in parents:
501 if p not in seen:
501 if p not in seen:
502 seen[p] = 1
502 seen[p] = 1
503 visit.append(p)
503 visit.append(p)
504 else:
504 else:
505 cmdutil.setremoteconfig(ui, opts)
505 cmdutil.setremoteconfig(ui, opts)
506 dest, revs, checkout = hg.parseurl(
506 dest, revs, checkout = hg.parseurl(
507 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
507 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
508 other = hg.repository(ui, dest)
508 other = hg.repository(ui, dest)
509 o = repo.findoutgoing(other, force=opts.get('force'))
509 o = repo.findoutgoing(other, force=opts.get('force'))
510
510
511 if revs:
511 if revs:
512 cg = repo.changegroupsubset(o, revs, 'bundle')
512 cg = repo.changegroupsubset(o, revs, 'bundle')
513 else:
513 else:
514 cg = repo.changegroup(o, 'bundle')
514 cg = repo.changegroup(o, 'bundle')
515
515
516 bundletype = opts.get('type', 'bzip2').lower()
516 bundletype = opts.get('type', 'bzip2').lower()
517 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
517 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
518 bundletype = btypes.get(bundletype)
518 bundletype = btypes.get(bundletype)
519 if bundletype not in changegroup.bundletypes:
519 if bundletype not in changegroup.bundletypes:
520 raise util.Abort(_('unknown bundle type specified with --type'))
520 raise util.Abort(_('unknown bundle type specified with --type'))
521
521
522 changegroup.writebundle(cg, fname, bundletype)
522 changegroup.writebundle(cg, fname, bundletype)
523
523
524 def cat(ui, repo, file1, *pats, **opts):
524 def cat(ui, repo, file1, *pats, **opts):
525 """output the current or given revision of files
525 """output the current or given revision of files
526
526
527 Print the specified files as they were at the given revision.
527 Print the specified files as they were at the given revision.
528 If no revision is given, the parent of the working directory is used,
528 If no revision is given, the parent of the working directory is used,
529 or tip if no revision is checked out.
529 or tip if no revision is checked out.
530
530
531 Output may be to a file, in which case the name of the file is
531 Output may be to a file, in which case the name of the file is
532 given using a format string. The formatting rules are the same as
532 given using a format string. The formatting rules are the same as
533 for the export command, with the following additions:
533 for the export command, with the following additions:
534
534
535 %s basename of file being printed
535 %s basename of file being printed
536 %d dirname of file being printed, or '.' if in repo root
536 %d dirname of file being printed, or '.' if in repo root
537 %p root-relative path name of file being printed
537 %p root-relative path name of file being printed
538 """
538 """
539 ctx = repo[opts.get('rev')]
539 ctx = repo[opts.get('rev')]
540 err = 1
540 err = 1
541 m = cmdutil.match(repo, (file1,) + pats, opts)
541 m = cmdutil.match(repo, (file1,) + pats, opts)
542 for abs in ctx.walk(m):
542 for abs in ctx.walk(m):
543 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
543 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
544 data = ctx[abs].data()
544 data = ctx[abs].data()
545 if opts.get('decode'):
545 if opts.get('decode'):
546 data = repo.wwritedata(abs, data)
546 data = repo.wwritedata(abs, data)
547 fp.write(data)
547 fp.write(data)
548 err = 0
548 err = 0
549 return err
549 return err
550
550
551 def clone(ui, source, dest=None, **opts):
551 def clone(ui, source, dest=None, **opts):
552 """make a copy of an existing repository
552 """make a copy of an existing repository
553
553
554 Create a copy of an existing repository in a new directory.
554 Create a copy of an existing repository in a new directory.
555
555
556 If no destination directory name is specified, it defaults to the
556 If no destination directory name is specified, it defaults to the
557 basename of the source.
557 basename of the source.
558
558
559 The location of the source is added to the new repository's
559 The location of the source is added to the new repository's
560 .hg/hgrc file, as the default to be used for future pulls.
560 .hg/hgrc file, as the default to be used for future pulls.
561
561
562 For efficiency, hardlinks are used for cloning whenever the source
562 For efficiency, hardlinks are used for cloning whenever the source
563 and destination are on the same filesystem (note this applies only
563 and destination are on the same filesystem (note this applies only
564 to the repository data, not to the checked out files). Some
564 to the repository data, not to the checked out files). Some
565 filesystems, such as AFS, implement hardlinking incorrectly, but
565 filesystems, such as AFS, implement hardlinking incorrectly, but
566 do not report errors. In these cases, use the --pull option to
566 do not report errors. In these cases, use the --pull option to
567 avoid hardlinking.
567 avoid hardlinking.
568
568
569 In some cases, you can clone repositories and checked out files
569 In some cases, you can clone repositories and checked out files
570 using full hardlinks with
570 using full hardlinks with
571
571
572 $ cp -al REPO REPOCLONE
572 $ cp -al REPO REPOCLONE
573
573
574 This is the fastest way to clone, but it is not always safe. The
574 This is the fastest way to clone, but it is not always safe. The
575 operation is not atomic (making sure REPO is not modified during
575 operation is not atomic (making sure REPO is not modified during
576 the operation is up to you) and you have to make sure your editor
576 the operation is up to you) and you have to make sure your editor
577 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
577 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
578 this is not compatible with certain extensions that place their
578 this is not compatible with certain extensions that place their
579 metadata under the .hg directory, such as mq.
579 metadata under the .hg directory, such as mq.
580
580
581 If you use the -r option to clone up to a specific revision, no
581 If you use the -r option to clone up to a specific revision, no
582 subsequent revisions will be present in the cloned repository.
582 subsequent revisions will be present in the cloned repository.
583 This option implies --pull, even on local repositories.
583 This option implies --pull, even on local repositories.
584
584
585 If the -U option is used, the new clone will contain only a repository
585 If the -U option is used, the new clone will contain only a repository
586 (.hg) and no working copy (the working copy parent is the null revision).
586 (.hg) and no working copy (the working copy parent is the null revision).
587
587
588 See pull for valid source format details.
588 See pull for valid source format details.
589
589
590 It is possible to specify an ssh:// URL as the destination, but no
590 It is possible to specify an ssh:// URL as the destination, but no
591 .hg/hgrc and working directory will be created on the remote side.
591 .hg/hgrc and working directory will be created on the remote side.
592 Look at the help text for the pull command for important details
592 Look at the help text for the pull command for important details
593 about ssh:// URLs.
593 about ssh:// URLs.
594 """
594 """
595 cmdutil.setremoteconfig(ui, opts)
595 cmdutil.setremoteconfig(ui, opts)
596 hg.clone(ui, source, dest,
596 hg.clone(ui, source, dest,
597 pull=opts.get('pull'),
597 pull=opts.get('pull'),
598 stream=opts.get('uncompressed'),
598 stream=opts.get('uncompressed'),
599 rev=opts.get('rev'),
599 rev=opts.get('rev'),
600 update=not opts.get('noupdate'))
600 update=not opts.get('noupdate'))
601
601
602 def commit(ui, repo, *pats, **opts):
602 def commit(ui, repo, *pats, **opts):
603 """commit the specified files or all outstanding changes
603 """commit the specified files or all outstanding changes
604
604
605 Commit changes to the given files into the repository.
605 Commit changes to the given files into the repository.
606
606
607 If a list of files is omitted, all changes reported by "hg status"
607 If a list of files is omitted, all changes reported by "hg status"
608 will be committed.
608 will be committed.
609
609
610 If you are committing the result of a merge, do not provide any
610 If you are committing the result of a merge, do not provide any
611 file names or -I/-X filters.
611 file names or -I/-X filters.
612
612
613 If no commit message is specified, the configured editor is started to
613 If no commit message is specified, the configured editor is started to
614 enter a message.
614 enter a message.
615
615
616 See 'hg help dates' for a list of formats valid for -d/--date.
616 See 'hg help dates' for a list of formats valid for -d/--date.
617 """
617 """
618 def commitfunc(ui, repo, message, match, opts):
618 def commitfunc(ui, repo, message, match, opts):
619 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
619 return repo.commit(match.files(), message, opts.get('user'), opts.get('date'),
620 match, force_editor=opts.get('force_editor'))
620 match, force_editor=opts.get('force_editor'))
621
621
622 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
622 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
623 if not node:
623 if not node:
624 return
624 return
625 cl = repo.changelog
625 cl = repo.changelog
626 rev = cl.rev(node)
626 rev = cl.rev(node)
627 parents = cl.parentrevs(rev)
627 parents = cl.parentrevs(rev)
628 if rev - 1 in parents:
628 if rev - 1 in parents:
629 # one of the parents was the old tip
629 # one of the parents was the old tip
630 pass
630 pass
631 elif (parents == (nullrev, nullrev) or
631 elif (parents == (nullrev, nullrev) or
632 len(cl.heads(cl.node(parents[0]))) > 1 and
632 len(cl.heads(cl.node(parents[0]))) > 1 and
633 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
633 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
634 ui.status(_('created new head\n'))
634 ui.status(_('created new head\n'))
635
635
636 if ui.debugflag:
636 if ui.debugflag:
637 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
637 ui.write(_('committed changeset %d:%s\n') % (rev,hex(node)))
638 elif ui.verbose:
638 elif ui.verbose:
639 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
639 ui.write(_('committed changeset %d:%s\n') % (rev,short(node)))
640
640
641 def copy(ui, repo, *pats, **opts):
641 def copy(ui, repo, *pats, **opts):
642 """mark files as copied for the next commit
642 """mark files as copied for the next commit
643
643
644 Mark dest as having copies of source files. If dest is a
644 Mark dest as having copies of source files. If dest is a
645 directory, copies are put in that directory. If dest is a file,
645 directory, copies are put in that directory. If dest is a file,
646 there can only be one source.
646 there can only be one source.
647
647
648 By default, this command copies the contents of files as they
648 By default, this command copies the contents of files as they
649 stand in the working directory. If invoked with --after, the
649 stand in the working directory. If invoked with --after, the
650 operation is recorded, but no copying is performed.
650 operation is recorded, but no copying is performed.
651
651
652 This command takes effect in the next commit. To undo a copy
652 This command takes effect in the next commit. To undo a copy
653 before that, see hg revert.
653 before that, see hg revert.
654 """
654 """
655 wlock = repo.wlock(False)
655 wlock = repo.wlock(False)
656 try:
656 try:
657 return cmdutil.copy(ui, repo, pats, opts)
657 return cmdutil.copy(ui, repo, pats, opts)
658 finally:
658 finally:
659 del wlock
659 del wlock
660
660
661 def debugancestor(ui, repo, *args):
661 def debugancestor(ui, repo, *args):
662 """find the ancestor revision of two revisions in a given index"""
662 """find the ancestor revision of two revisions in a given index"""
663 if len(args) == 3:
663 if len(args) == 3:
664 index, rev1, rev2 = args
664 index, rev1, rev2 = args
665 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
665 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
666 lookup = r.lookup
666 lookup = r.lookup
667 elif len(args) == 2:
667 elif len(args) == 2:
668 if not repo:
668 if not repo:
669 raise util.Abort(_("There is no Mercurial repository here "
669 raise util.Abort(_("There is no Mercurial repository here "
670 "(.hg not found)"))
670 "(.hg not found)"))
671 rev1, rev2 = args
671 rev1, rev2 = args
672 r = repo.changelog
672 r = repo.changelog
673 lookup = repo.lookup
673 lookup = repo.lookup
674 else:
674 else:
675 raise util.Abort(_('either two or three arguments required'))
675 raise util.Abort(_('either two or three arguments required'))
676 a = r.ancestor(lookup(rev1), lookup(rev2))
676 a = r.ancestor(lookup(rev1), lookup(rev2))
677 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
677 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
678
678
679 def debugcomplete(ui, cmd='', **opts):
679 def debugcomplete(ui, cmd='', **opts):
680 """returns the completion list associated with the given command"""
680 """returns the completion list associated with the given command"""
681
681
682 if opts.get('options'):
682 if opts.get('options'):
683 options = []
683 options = []
684 otables = [globalopts]
684 otables = [globalopts]
685 if cmd:
685 if cmd:
686 aliases, entry = cmdutil.findcmd(cmd, table, False)
686 aliases, entry = cmdutil.findcmd(cmd, table, False)
687 otables.append(entry[1])
687 otables.append(entry[1])
688 for t in otables:
688 for t in otables:
689 for o in t:
689 for o in t:
690 if o[0]:
690 if o[0]:
691 options.append('-%s' % o[0])
691 options.append('-%s' % o[0])
692 options.append('--%s' % o[1])
692 options.append('--%s' % o[1])
693 ui.write("%s\n" % "\n".join(options))
693 ui.write("%s\n" % "\n".join(options))
694 return
694 return
695
695
696 cmdlist = cmdutil.findpossible(cmd, table)
696 cmdlist = cmdutil.findpossible(cmd, table)
697 if ui.verbose:
697 if ui.verbose:
698 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
698 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
699 ui.write("%s\n" % "\n".join(util.sort(cmdlist)))
699 ui.write("%s\n" % "\n".join(util.sort(cmdlist)))
700
700
701 def debugfsinfo(ui, path = "."):
701 def debugfsinfo(ui, path = "."):
702 file('.debugfsinfo', 'w').write('')
702 file('.debugfsinfo', 'w').write('')
703 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
703 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
704 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
704 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
705 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
705 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
706 and 'yes' or 'no'))
706 and 'yes' or 'no'))
707 os.unlink('.debugfsinfo')
707 os.unlink('.debugfsinfo')
708
708
709 def debugrebuildstate(ui, repo, rev="tip"):
709 def debugrebuildstate(ui, repo, rev="tip"):
710 """rebuild the dirstate as it would look like for the given revision"""
710 """rebuild the dirstate as it would look like for the given revision"""
711 ctx = repo[rev]
711 ctx = repo[rev]
712 wlock = repo.wlock()
712 wlock = repo.wlock()
713 try:
713 try:
714 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
714 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
715 finally:
715 finally:
716 del wlock
716 del wlock
717
717
718 def debugcheckstate(ui, repo):
718 def debugcheckstate(ui, repo):
719 """validate the correctness of the current dirstate"""
719 """validate the correctness of the current dirstate"""
720 parent1, parent2 = repo.dirstate.parents()
720 parent1, parent2 = repo.dirstate.parents()
721 m1 = repo[parent1].manifest()
721 m1 = repo[parent1].manifest()
722 m2 = repo[parent2].manifest()
722 m2 = repo[parent2].manifest()
723 errors = 0
723 errors = 0
724 for f in repo.dirstate:
724 for f in repo.dirstate:
725 state = repo.dirstate[f]
725 state = repo.dirstate[f]
726 if state in "nr" and f not in m1:
726 if state in "nr" and f not in m1:
727 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
727 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
728 errors += 1
728 errors += 1
729 if state in "a" and f in m1:
729 if state in "a" and f in m1:
730 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
730 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
731 errors += 1
731 errors += 1
732 if state in "m" and f not in m1 and f not in m2:
732 if state in "m" and f not in m1 and f not in m2:
733 ui.warn(_("%s in state %s, but not in either manifest\n") %
733 ui.warn(_("%s in state %s, but not in either manifest\n") %
734 (f, state))
734 (f, state))
735 errors += 1
735 errors += 1
736 for f in m1:
736 for f in m1:
737 state = repo.dirstate[f]
737 state = repo.dirstate[f]
738 if state not in "nrm":
738 if state not in "nrm":
739 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
739 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
740 errors += 1
740 errors += 1
741 if errors:
741 if errors:
742 error = _(".hg/dirstate inconsistent with current parent's manifest")
742 error = _(".hg/dirstate inconsistent with current parent's manifest")
743 raise util.Abort(error)
743 raise util.Abort(error)
744
744
745 def showconfig(ui, repo, *values, **opts):
745 def showconfig(ui, repo, *values, **opts):
746 """show combined config settings from all hgrc files
746 """show combined config settings from all hgrc files
747
747
748 With no args, print names and values of all config items.
748 With no args, print names and values of all config items.
749
749
750 With one arg of the form section.name, print just the value of
750 With one arg of the form section.name, print just the value of
751 that config item.
751 that config item.
752
752
753 With multiple args, print names and values of all config items
753 With multiple args, print names and values of all config items
754 with matching section names."""
754 with matching section names."""
755
755
756 untrusted = bool(opts.get('untrusted'))
756 untrusted = bool(opts.get('untrusted'))
757 if values:
757 if values:
758 if len([v for v in values if '.' in v]) > 1:
758 if len([v for v in values if '.' in v]) > 1:
759 raise util.Abort(_('only one config item permitted'))
759 raise util.Abort(_('only one config item permitted'))
760 for section, name, value in ui.walkconfig(untrusted=untrusted):
760 for section, name, value in ui.walkconfig(untrusted=untrusted):
761 sectname = section + '.' + name
761 sectname = section + '.' + name
762 if values:
762 if values:
763 for v in values:
763 for v in values:
764 if v == section:
764 if v == section:
765 ui.write('%s=%s\n' % (sectname, value))
765 ui.write('%s=%s\n' % (sectname, value))
766 elif v == sectname:
766 elif v == sectname:
767 ui.write(value, '\n')
767 ui.write(value, '\n')
768 else:
768 else:
769 ui.write('%s=%s\n' % (sectname, value))
769 ui.write('%s=%s\n' % (sectname, value))
770
770
771 def debugsetparents(ui, repo, rev1, rev2=None):
771 def debugsetparents(ui, repo, rev1, rev2=None):
772 """manually set the parents of the current working directory
772 """manually set the parents of the current working directory
773
773
774 This is useful for writing repository conversion tools, but should
774 This is useful for writing repository conversion tools, but should
775 be used with care.
775 be used with care.
776 """
776 """
777
777
778 if not rev2:
778 if not rev2:
779 rev2 = hex(nullid)
779 rev2 = hex(nullid)
780
780
781 wlock = repo.wlock()
781 wlock = repo.wlock()
782 try:
782 try:
783 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
783 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
784 finally:
784 finally:
785 del wlock
785 del wlock
786
786
787 def debugstate(ui, repo, nodates=None):
787 def debugstate(ui, repo, nodates=None):
788 """show the contents of the current dirstate"""
788 """show the contents of the current dirstate"""
789 timestr = ""
789 timestr = ""
790 showdate = not nodates
790 showdate = not nodates
791 for file_, ent in util.sort(repo.dirstate._map.items()):
791 for file_, ent in util.sort(repo.dirstate._map.items()):
792 if showdate:
792 if showdate:
793 if ent[3] == -1:
793 if ent[3] == -1:
794 # Pad or slice to locale representation
794 # Pad or slice to locale representation
795 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
795 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
796 timestr = 'unset'
796 timestr = 'unset'
797 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
797 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
798 else:
798 else:
799 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
799 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
800 if ent[1] & 020000:
800 if ent[1] & 020000:
801 mode = 'lnk'
801 mode = 'lnk'
802 else:
802 else:
803 mode = '%3o' % (ent[1] & 0777)
803 mode = '%3o' % (ent[1] & 0777)
804 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
804 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
805 for f in repo.dirstate.copies():
805 for f in repo.dirstate.copies():
806 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
806 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
807
807
808 def debugdata(ui, file_, rev):
808 def debugdata(ui, file_, rev):
809 """dump the contents of a data file revision"""
809 """dump the contents of a data file revision"""
810 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
810 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
811 try:
811 try:
812 ui.write(r.revision(r.lookup(rev)))
812 ui.write(r.revision(r.lookup(rev)))
813 except KeyError:
813 except KeyError:
814 raise util.Abort(_('invalid revision identifier %s') % rev)
814 raise util.Abort(_('invalid revision identifier %s') % rev)
815
815
816 def debugdate(ui, date, range=None, **opts):
816 def debugdate(ui, date, range=None, **opts):
817 """parse and display a date"""
817 """parse and display a date"""
818 if opts["extended"]:
818 if opts["extended"]:
819 d = util.parsedate(date, util.extendeddateformats)
819 d = util.parsedate(date, util.extendeddateformats)
820 else:
820 else:
821 d = util.parsedate(date)
821 d = util.parsedate(date)
822 ui.write("internal: %s %s\n" % d)
822 ui.write("internal: %s %s\n" % d)
823 ui.write("standard: %s\n" % util.datestr(d))
823 ui.write("standard: %s\n" % util.datestr(d))
824 if range:
824 if range:
825 m = util.matchdate(range)
825 m = util.matchdate(range)
826 ui.write("match: %s\n" % m(d[0]))
826 ui.write("match: %s\n" % m(d[0]))
827
827
828 def debugindex(ui, file_):
828 def debugindex(ui, file_):
829 """dump the contents of an index file"""
829 """dump the contents of an index file"""
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
830 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
831 ui.write(" rev offset length base linkrev" +
831 ui.write(" rev offset length base linkrev" +
832 " nodeid p1 p2\n")
832 " nodeid p1 p2\n")
833 for i in r:
833 for i in r:
834 node = r.node(i)
834 node = r.node(i)
835 try:
835 try:
836 pp = r.parents(node)
836 pp = r.parents(node)
837 except:
837 except:
838 pp = [nullid, nullid]
838 pp = [nullid, nullid]
839 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
839 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
840 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
840 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
841 short(node), short(pp[0]), short(pp[1])))
841 short(node), short(pp[0]), short(pp[1])))
842
842
843 def debugindexdot(ui, file_):
843 def debugindexdot(ui, file_):
844 """dump an index DAG as a .dot file"""
844 """dump an index DAG as a .dot file"""
845 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
845 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
846 ui.write("digraph G {\n")
846 ui.write("digraph G {\n")
847 for i in r:
847 for i in r:
848 node = r.node(i)
848 node = r.node(i)
849 pp = r.parents(node)
849 pp = r.parents(node)
850 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
850 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
851 if pp[1] != nullid:
851 if pp[1] != nullid:
852 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
852 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
853 ui.write("}\n")
853 ui.write("}\n")
854
854
855 def debuginstall(ui):
855 def debuginstall(ui):
856 '''test Mercurial installation'''
856 '''test Mercurial installation'''
857
857
858 def writetemp(contents):
858 def writetemp(contents):
859 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
859 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
860 f = os.fdopen(fd, "wb")
860 f = os.fdopen(fd, "wb")
861 f.write(contents)
861 f.write(contents)
862 f.close()
862 f.close()
863 return name
863 return name
864
864
865 problems = 0
865 problems = 0
866
866
867 # encoding
867 # encoding
868 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
868 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
869 try:
869 try:
870 util.fromlocal("test")
870 util.fromlocal("test")
871 except util.Abort, inst:
871 except util.Abort, inst:
872 ui.write(" %s\n" % inst)
872 ui.write(" %s\n" % inst)
873 ui.write(_(" (check that your locale is properly set)\n"))
873 ui.write(_(" (check that your locale is properly set)\n"))
874 problems += 1
874 problems += 1
875
875
876 # compiled modules
876 # compiled modules
877 ui.status(_("Checking extensions...\n"))
877 ui.status(_("Checking extensions...\n"))
878 try:
878 try:
879 import bdiff, mpatch, base85
879 import bdiff, mpatch, base85
880 except Exception, inst:
880 except Exception, inst:
881 ui.write(" %s\n" % inst)
881 ui.write(" %s\n" % inst)
882 ui.write(_(" One or more extensions could not be found"))
882 ui.write(_(" One or more extensions could not be found"))
883 ui.write(_(" (check that you compiled the extensions)\n"))
883 ui.write(_(" (check that you compiled the extensions)\n"))
884 problems += 1
884 problems += 1
885
885
886 # templates
886 # templates
887 ui.status(_("Checking templates...\n"))
887 ui.status(_("Checking templates...\n"))
888 try:
888 try:
889 import templater
889 import templater
890 t = templater.templater(templater.templatepath("map-cmdline.default"))
890 t = templater.templater(templater.templatepath("map-cmdline.default"))
891 except Exception, inst:
891 except Exception, inst:
892 ui.write(" %s\n" % inst)
892 ui.write(" %s\n" % inst)
893 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
893 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
894 problems += 1
894 problems += 1
895
895
896 # patch
896 # patch
897 ui.status(_("Checking patch...\n"))
897 ui.status(_("Checking patch...\n"))
898 patchproblems = 0
898 patchproblems = 0
899 a = "1\n2\n3\n4\n"
899 a = "1\n2\n3\n4\n"
900 b = "1\n2\n3\ninsert\n4\n"
900 b = "1\n2\n3\ninsert\n4\n"
901 fa = writetemp(a)
901 fa = writetemp(a)
902 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
902 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
903 os.path.basename(fa))
903 os.path.basename(fa))
904 fd = writetemp(d)
904 fd = writetemp(d)
905
905
906 files = {}
906 files = {}
907 try:
907 try:
908 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
908 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
909 except util.Abort, e:
909 except util.Abort, e:
910 ui.write(_(" patch call failed:\n"))
910 ui.write(_(" patch call failed:\n"))
911 ui.write(" " + str(e) + "\n")
911 ui.write(" " + str(e) + "\n")
912 patchproblems += 1
912 patchproblems += 1
913 else:
913 else:
914 if list(files) != [os.path.basename(fa)]:
914 if list(files) != [os.path.basename(fa)]:
915 ui.write(_(" unexpected patch output!\n"))
915 ui.write(_(" unexpected patch output!\n"))
916 patchproblems += 1
916 patchproblems += 1
917 a = file(fa).read()
917 a = file(fa).read()
918 if a != b:
918 if a != b:
919 ui.write(_(" patch test failed!\n"))
919 ui.write(_(" patch test failed!\n"))
920 patchproblems += 1
920 patchproblems += 1
921
921
922 if patchproblems:
922 if patchproblems:
923 if ui.config('ui', 'patch'):
923 if ui.config('ui', 'patch'):
924 ui.write(_(" (Current patch tool may be incompatible with patch,"
924 ui.write(_(" (Current patch tool may be incompatible with patch,"
925 " or misconfigured. Please check your .hgrc file)\n"))
925 " or misconfigured. Please check your .hgrc file)\n"))
926 else:
926 else:
927 ui.write(_(" Internal patcher failure, please report this error"
927 ui.write(_(" Internal patcher failure, please report this error"
928 " to http://www.selenic.com/mercurial/bts\n"))
928 " to http://www.selenic.com/mercurial/bts\n"))
929 problems += patchproblems
929 problems += patchproblems
930
930
931 os.unlink(fa)
931 os.unlink(fa)
932 os.unlink(fd)
932 os.unlink(fd)
933
933
934 # editor
934 # editor
935 ui.status(_("Checking commit editor...\n"))
935 ui.status(_("Checking commit editor...\n"))
936 editor = ui.geteditor()
936 editor = ui.geteditor()
937 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
937 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
938 if not cmdpath:
938 if not cmdpath:
939 if editor == 'vi':
939 if editor == 'vi':
940 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
940 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
941 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
941 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
942 else:
942 else:
943 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
943 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
944 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
944 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
945 problems += 1
945 problems += 1
946
946
947 # check username
947 # check username
948 ui.status(_("Checking username...\n"))
948 ui.status(_("Checking username...\n"))
949 user = os.environ.get("HGUSER")
949 user = os.environ.get("HGUSER")
950 if user is None:
950 if user is None:
951 user = ui.config("ui", "username")
951 user = ui.config("ui", "username")
952 if user is None:
952 if user is None:
953 user = os.environ.get("EMAIL")
953 user = os.environ.get("EMAIL")
954 if not user:
954 if not user:
955 ui.warn(" ")
955 ui.warn(" ")
956 ui.username()
956 ui.username()
957 ui.write(_(" (specify a username in your .hgrc file)\n"))
957 ui.write(_(" (specify a username in your .hgrc file)\n"))
958
958
959 if not problems:
959 if not problems:
960 ui.status(_("No problems detected\n"))
960 ui.status(_("No problems detected\n"))
961 else:
961 else:
962 ui.write(_("%s problems detected,"
962 ui.write(_("%s problems detected,"
963 " please check your install!\n") % problems)
963 " please check your install!\n") % problems)
964
964
965 return problems
965 return problems
966
966
967 def debugrename(ui, repo, file1, *pats, **opts):
967 def debugrename(ui, repo, file1, *pats, **opts):
968 """dump rename information"""
968 """dump rename information"""
969
969
970 ctx = repo[opts.get('rev')]
970 ctx = repo[opts.get('rev')]
971 m = cmdutil.match(repo, (file1,) + pats, opts)
971 m = cmdutil.match(repo, (file1,) + pats, opts)
972 for abs in ctx.walk(m):
972 for abs in ctx.walk(m):
973 fctx = ctx[abs]
973 fctx = ctx[abs]
974 o = fctx.filelog().renamed(fctx.filenode())
974 o = fctx.filelog().renamed(fctx.filenode())
975 rel = m.rel(abs)
975 rel = m.rel(abs)
976 if o:
976 if o:
977 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
977 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
978 else:
978 else:
979 ui.write(_("%s not renamed\n") % rel)
979 ui.write(_("%s not renamed\n") % rel)
980
980
981 def debugwalk(ui, repo, *pats, **opts):
981 def debugwalk(ui, repo, *pats, **opts):
982 """show how files match on given patterns"""
982 """show how files match on given patterns"""
983 m = cmdutil.match(repo, pats, opts)
983 m = cmdutil.match(repo, pats, opts)
984 items = list(repo.walk(m))
984 items = list(repo.walk(m))
985 if not items:
985 if not items:
986 return
986 return
987 fmt = 'f %%-%ds %%-%ds %%s' % (
987 fmt = 'f %%-%ds %%-%ds %%s' % (
988 max([len(abs) for abs in items]),
988 max([len(abs) for abs in items]),
989 max([len(m.rel(abs)) for abs in items]))
989 max([len(m.rel(abs)) for abs in items]))
990 for abs in items:
990 for abs in items:
991 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
991 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
992 ui.write("%s\n" % line.rstrip())
992 ui.write("%s\n" % line.rstrip())
993
993
994 def diff(ui, repo, *pats, **opts):
994 def diff(ui, repo, *pats, **opts):
995 """diff repository (or selected files)
995 """diff repository (or selected files)
996
996
997 Show differences between revisions for the specified files.
997 Show differences between revisions for the specified files.
998
998
999 Differences between files are shown using the unified diff format.
999 Differences between files are shown using the unified diff format.
1000
1000
1001 NOTE: diff may generate unexpected results for merges, as it will
1001 NOTE: diff may generate unexpected results for merges, as it will
1002 default to comparing against the working directory's first parent
1002 default to comparing against the working directory's first parent
1003 changeset if no revisions are specified.
1003 changeset if no revisions are specified.
1004
1004
1005 When two revision arguments are given, then changes are shown
1005 When two revision arguments are given, then changes are shown
1006 between those revisions. If only one revision is specified then
1006 between those revisions. If only one revision is specified then
1007 that revision is compared to the working directory, and, when no
1007 that revision is compared to the working directory, and, when no
1008 revisions are specified, the working directory files are compared
1008 revisions are specified, the working directory files are compared
1009 to its parent.
1009 to its parent.
1010
1010
1011 Without the -a option, diff will avoid generating diffs of files
1011 Without the -a option, diff will avoid generating diffs of files
1012 it detects as binary. With -a, diff will generate a diff anyway,
1012 it detects as binary. With -a, diff will generate a diff anyway,
1013 probably with undesirable results.
1013 probably with undesirable results.
1014
1014
1015 Use the --git option to generate diffs in the git extended diff
1015 Use the --git option to generate diffs in the git extended diff
1016 format. Read the diffs help topic for more information.
1016 format. Read the diffs help topic for more information.
1017 """
1017 """
1018 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1018 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
1019
1019
1020 m = cmdutil.match(repo, pats, opts)
1020 m = cmdutil.match(repo, pats, opts)
1021 it = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1021 it = patch.diff(repo, node1, node2, match=m, opts=patch.diffopts(ui, opts))
1022 for chunk in it:
1022 for chunk in it:
1023 repo.ui.write(chunk)
1023 repo.ui.write(chunk)
1024
1024
1025 def export(ui, repo, *changesets, **opts):
1025 def export(ui, repo, *changesets, **opts):
1026 """dump the header and diffs for one or more changesets
1026 """dump the header and diffs for one or more changesets
1027
1027
1028 Print the changeset header and diffs for one or more revisions.
1028 Print the changeset header and diffs for one or more revisions.
1029
1029
1030 The information shown in the changeset header is: author,
1030 The information shown in the changeset header is: author,
1031 changeset hash, parent(s) and commit comment.
1031 changeset hash, parent(s) and commit comment.
1032
1032
1033 NOTE: export may generate unexpected diff output for merge changesets,
1033 NOTE: export may generate unexpected diff output for merge changesets,
1034 as it will compare the merge changeset against its first parent only.
1034 as it will compare the merge changeset against its first parent only.
1035
1035
1036 Output may be to a file, in which case the name of the file is
1036 Output may be to a file, in which case the name of the file is
1037 given using a format string. The formatting rules are as follows:
1037 given using a format string. The formatting rules are as follows:
1038
1038
1039 %% literal "%" character
1039 %% literal "%" character
1040 %H changeset hash (40 bytes of hexadecimal)
1040 %H changeset hash (40 bytes of hexadecimal)
1041 %N number of patches being generated
1041 %N number of patches being generated
1042 %R changeset revision number
1042 %R changeset revision number
1043 %b basename of the exporting repository
1043 %b basename of the exporting repository
1044 %h short-form changeset hash (12 bytes of hexadecimal)
1044 %h short-form changeset hash (12 bytes of hexadecimal)
1045 %n zero-padded sequence number, starting at 1
1045 %n zero-padded sequence number, starting at 1
1046 %r zero-padded changeset revision number
1046 %r zero-padded changeset revision number
1047
1047
1048 Without the -a option, export will avoid generating diffs of files
1048 Without the -a option, export will avoid generating diffs of files
1049 it detects as binary. With -a, export will generate a diff anyway,
1049 it detects as binary. With -a, export will generate a diff anyway,
1050 probably with undesirable results.
1050 probably with undesirable results.
1051
1051
1052 Use the --git option to generate diffs in the git extended diff
1052 Use the --git option to generate diffs in the git extended diff
1053 format. Read the diffs help topic for more information.
1053 format. Read the diffs help topic for more information.
1054
1054
1055 With the --switch-parent option, the diff will be against the second
1055 With the --switch-parent option, the diff will be against the second
1056 parent. It can be useful to review a merge.
1056 parent. It can be useful to review a merge.
1057 """
1057 """
1058 if not changesets:
1058 if not changesets:
1059 raise util.Abort(_("export requires at least one changeset"))
1059 raise util.Abort(_("export requires at least one changeset"))
1060 revs = cmdutil.revrange(repo, changesets)
1060 revs = cmdutil.revrange(repo, changesets)
1061 if len(revs) > 1:
1061 if len(revs) > 1:
1062 ui.note(_('exporting patches:\n'))
1062 ui.note(_('exporting patches:\n'))
1063 else:
1063 else:
1064 ui.note(_('exporting patch:\n'))
1064 ui.note(_('exporting patch:\n'))
1065 patch.export(repo, revs, template=opts.get('output'),
1065 patch.export(repo, revs, template=opts.get('output'),
1066 switch_parent=opts.get('switch_parent'),
1066 switch_parent=opts.get('switch_parent'),
1067 opts=patch.diffopts(ui, opts))
1067 opts=patch.diffopts(ui, opts))
1068
1068
1069 def grep(ui, repo, pattern, *pats, **opts):
1069 def grep(ui, repo, pattern, *pats, **opts):
1070 """search for a pattern in specified files and revisions
1070 """search for a pattern in specified files and revisions
1071
1071
1072 Search revisions of files for a regular expression.
1072 Search revisions of files for a regular expression.
1073
1073
1074 This command behaves differently than Unix grep. It only accepts
1074 This command behaves differently than Unix grep. It only accepts
1075 Python/Perl regexps. It searches repository history, not the
1075 Python/Perl regexps. It searches repository history, not the
1076 working directory. It always prints the revision number in which
1076 working directory. It always prints the revision number in which
1077 a match appears.
1077 a match appears.
1078
1078
1079 By default, grep only prints output for the first revision of a
1079 By default, grep only prints output for the first revision of a
1080 file in which it finds a match. To get it to print every revision
1080 file in which it finds a match. To get it to print every revision
1081 that contains a change in match status ("-" for a match that
1081 that contains a change in match status ("-" for a match that
1082 becomes a non-match, or "+" for a non-match that becomes a match),
1082 becomes a non-match, or "+" for a non-match that becomes a match),
1083 use the --all flag.
1083 use the --all flag.
1084 """
1084 """
1085 reflags = 0
1085 reflags = 0
1086 if opts.get('ignore_case'):
1086 if opts.get('ignore_case'):
1087 reflags |= re.I
1087 reflags |= re.I
1088 try:
1088 try:
1089 regexp = re.compile(pattern, reflags)
1089 regexp = re.compile(pattern, reflags)
1090 except Exception, inst:
1090 except Exception, inst:
1091 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1091 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1092 return None
1092 return None
1093 sep, eol = ':', '\n'
1093 sep, eol = ':', '\n'
1094 if opts.get('print0'):
1094 if opts.get('print0'):
1095 sep = eol = '\0'
1095 sep = eol = '\0'
1096
1096
1097 fcache = {}
1097 fcache = {}
1098 def getfile(fn):
1098 def getfile(fn):
1099 if fn not in fcache:
1099 if fn not in fcache:
1100 fcache[fn] = repo.file(fn)
1100 fcache[fn] = repo.file(fn)
1101 return fcache[fn]
1101 return fcache[fn]
1102
1102
1103 def matchlines(body):
1103 def matchlines(body):
1104 begin = 0
1104 begin = 0
1105 linenum = 0
1105 linenum = 0
1106 while True:
1106 while True:
1107 match = regexp.search(body, begin)
1107 match = regexp.search(body, begin)
1108 if not match:
1108 if not match:
1109 break
1109 break
1110 mstart, mend = match.span()
1110 mstart, mend = match.span()
1111 linenum += body.count('\n', begin, mstart) + 1
1111 linenum += body.count('\n', begin, mstart) + 1
1112 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1112 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1113 begin = body.find('\n', mend) + 1 or len(body)
1113 begin = body.find('\n', mend) + 1 or len(body)
1114 lend = begin - 1
1114 lend = begin - 1
1115 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1115 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1116
1116
1117 class linestate(object):
1117 class linestate(object):
1118 def __init__(self, line, linenum, colstart, colend):
1118 def __init__(self, line, linenum, colstart, colend):
1119 self.line = line
1119 self.line = line
1120 self.linenum = linenum
1120 self.linenum = linenum
1121 self.colstart = colstart
1121 self.colstart = colstart
1122 self.colend = colend
1122 self.colend = colend
1123
1123
1124 def __hash__(self):
1124 def __hash__(self):
1125 return hash((self.linenum, self.line))
1125 return hash((self.linenum, self.line))
1126
1126
1127 def __eq__(self, other):
1127 def __eq__(self, other):
1128 return self.line == other.line
1128 return self.line == other.line
1129
1129
1130 matches = {}
1130 matches = {}
1131 copies = {}
1131 copies = {}
1132 def grepbody(fn, rev, body):
1132 def grepbody(fn, rev, body):
1133 matches[rev].setdefault(fn, [])
1133 matches[rev].setdefault(fn, [])
1134 m = matches[rev][fn]
1134 m = matches[rev][fn]
1135 for lnum, cstart, cend, line in matchlines(body):
1135 for lnum, cstart, cend, line in matchlines(body):
1136 s = linestate(line, lnum, cstart, cend)
1136 s = linestate(line, lnum, cstart, cend)
1137 m.append(s)
1137 m.append(s)
1138
1138
1139 def difflinestates(a, b):
1139 def difflinestates(a, b):
1140 sm = difflib.SequenceMatcher(None, a, b)
1140 sm = difflib.SequenceMatcher(None, a, b)
1141 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1141 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1142 if tag == 'insert':
1142 if tag == 'insert':
1143 for i in xrange(blo, bhi):
1143 for i in xrange(blo, bhi):
1144 yield ('+', b[i])
1144 yield ('+', b[i])
1145 elif tag == 'delete':
1145 elif tag == 'delete':
1146 for i in xrange(alo, ahi):
1146 for i in xrange(alo, ahi):
1147 yield ('-', a[i])
1147 yield ('-', a[i])
1148 elif tag == 'replace':
1148 elif tag == 'replace':
1149 for i in xrange(alo, ahi):
1149 for i in xrange(alo, ahi):
1150 yield ('-', a[i])
1150 yield ('-', a[i])
1151 for i in xrange(blo, bhi):
1151 for i in xrange(blo, bhi):
1152 yield ('+', b[i])
1152 yield ('+', b[i])
1153
1153
1154 prev = {}
1154 prev = {}
1155 def display(fn, rev, states, prevstates):
1155 def display(fn, rev, states, prevstates):
1156 datefunc = ui.quiet and util.shortdate or util.datestr
1156 datefunc = ui.quiet and util.shortdate or util.datestr
1157 found = False
1157 found = False
1158 filerevmatches = {}
1158 filerevmatches = {}
1159 r = prev.get(fn, -1)
1159 r = prev.get(fn, -1)
1160 if opts.get('all'):
1160 if opts.get('all'):
1161 iter = difflinestates(states, prevstates)
1161 iter = difflinestates(states, prevstates)
1162 else:
1162 else:
1163 iter = [('', l) for l in prevstates]
1163 iter = [('', l) for l in prevstates]
1164 for change, l in iter:
1164 for change, l in iter:
1165 cols = [fn, str(r)]
1165 cols = [fn, str(r)]
1166 if opts.get('line_number'):
1166 if opts.get('line_number'):
1167 cols.append(str(l.linenum))
1167 cols.append(str(l.linenum))
1168 if opts.get('all'):
1168 if opts.get('all'):
1169 cols.append(change)
1169 cols.append(change)
1170 if opts.get('user'):
1170 if opts.get('user'):
1171 cols.append(ui.shortuser(get(r)[1]))
1171 cols.append(ui.shortuser(get(r)[1]))
1172 if opts.get('date'):
1172 if opts.get('date'):
1173 cols.append(datefunc(get(r)[2]))
1173 cols.append(datefunc(get(r)[2]))
1174 if opts.get('files_with_matches'):
1174 if opts.get('files_with_matches'):
1175 c = (fn, r)
1175 c = (fn, r)
1176 if c in filerevmatches:
1176 if c in filerevmatches:
1177 continue
1177 continue
1178 filerevmatches[c] = 1
1178 filerevmatches[c] = 1
1179 else:
1179 else:
1180 cols.append(l.line)
1180 cols.append(l.line)
1181 ui.write(sep.join(cols), eol)
1181 ui.write(sep.join(cols), eol)
1182 found = True
1182 found = True
1183 return found
1183 return found
1184
1184
1185 fstate = {}
1185 fstate = {}
1186 skip = {}
1186 skip = {}
1187 get = util.cachefunc(lambda r: repo[r].changeset())
1187 get = util.cachefunc(lambda r: repo[r].changeset())
1188 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1188 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1189 found = False
1189 found = False
1190 follow = opts.get('follow')
1190 follow = opts.get('follow')
1191 for st, rev, fns in changeiter:
1191 for st, rev, fns in changeiter:
1192 if st == 'window':
1192 if st == 'window':
1193 matches.clear()
1193 matches.clear()
1194 elif st == 'add':
1194 elif st == 'add':
1195 ctx = repo[rev]
1195 ctx = repo[rev]
1196 matches[rev] = {}
1196 matches[rev] = {}
1197 for fn in fns:
1197 for fn in fns:
1198 if fn in skip:
1198 if fn in skip:
1199 continue
1199 continue
1200 try:
1200 try:
1201 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1201 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1202 fstate.setdefault(fn, [])
1202 fstate.setdefault(fn, [])
1203 if follow:
1203 if follow:
1204 copied = getfile(fn).renamed(ctx.filenode(fn))
1204 copied = getfile(fn).renamed(ctx.filenode(fn))
1205 if copied:
1205 if copied:
1206 copies.setdefault(rev, {})[fn] = copied[0]
1206 copies.setdefault(rev, {})[fn] = copied[0]
1207 except revlog.LookupError:
1207 except revlog.LookupError:
1208 pass
1208 pass
1209 elif st == 'iter':
1209 elif st == 'iter':
1210 for fn, m in util.sort(matches[rev].items()):
1210 for fn, m in util.sort(matches[rev].items()):
1211 copy = copies.get(rev, {}).get(fn)
1211 copy = copies.get(rev, {}).get(fn)
1212 if fn in skip:
1212 if fn in skip:
1213 if copy:
1213 if copy:
1214 skip[copy] = True
1214 skip[copy] = True
1215 continue
1215 continue
1216 if fn in prev or fstate[fn]:
1216 if fn in prev or fstate[fn]:
1217 r = display(fn, rev, m, fstate[fn])
1217 r = display(fn, rev, m, fstate[fn])
1218 found = found or r
1218 found = found or r
1219 if r and not opts.get('all'):
1219 if r and not opts.get('all'):
1220 skip[fn] = True
1220 skip[fn] = True
1221 if copy:
1221 if copy:
1222 skip[copy] = True
1222 skip[copy] = True
1223 fstate[fn] = m
1223 fstate[fn] = m
1224 if copy:
1224 if copy:
1225 fstate[copy] = m
1225 fstate[copy] = m
1226 prev[fn] = rev
1226 prev[fn] = rev
1227
1227
1228 for fn, state in util.sort(fstate.items()):
1228 for fn, state in util.sort(fstate.items()):
1229 if fn in skip:
1229 if fn in skip:
1230 continue
1230 continue
1231 if fn not in copies.get(prev[fn], {}):
1231 if fn not in copies.get(prev[fn], {}):
1232 found = display(fn, rev, {}, state) or found
1232 found = display(fn, rev, {}, state) or found
1233 return (not found and 1) or 0
1233 return (not found and 1) or 0
1234
1234
1235 def heads(ui, repo, *branchrevs, **opts):
1235 def heads(ui, repo, *branchrevs, **opts):
1236 """show current repository heads or show branch heads
1236 """show current repository heads or show branch heads
1237
1237
1238 With no arguments, show all repository head changesets.
1238 With no arguments, show all repository head changesets.
1239
1239
1240 If branch or revisions names are given this will show the heads of
1240 If branch or revisions names are given this will show the heads of
1241 the specified branches or the branches those revisions are tagged
1241 the specified branches or the branches those revisions are tagged
1242 with.
1242 with.
1243
1243
1244 Repository "heads" are changesets that don't have child
1244 Repository "heads" are changesets that don't have child
1245 changesets. They are where development generally takes place and
1245 changesets. They are where development generally takes place and
1246 are the usual targets for update and merge operations.
1246 are the usual targets for update and merge operations.
1247
1247
1248 Branch heads are changesets that have a given branch tag, but have
1248 Branch heads are changesets that have a given branch tag, but have
1249 no child changesets with that tag. They are usually where
1249 no child changesets with that tag. They are usually where
1250 development on the given branch takes place.
1250 development on the given branch takes place.
1251 """
1251 """
1252 if opts.get('rev'):
1252 if opts.get('rev'):
1253 start = repo.lookup(opts['rev'])
1253 start = repo.lookup(opts['rev'])
1254 else:
1254 else:
1255 start = None
1255 start = None
1256 if not branchrevs:
1256 if not branchrevs:
1257 # Assume we're looking repo-wide heads if no revs were specified.
1257 # Assume we're looking repo-wide heads if no revs were specified.
1258 heads = repo.heads(start)
1258 heads = repo.heads(start)
1259 else:
1259 else:
1260 heads = []
1260 heads = []
1261 visitedset = util.set()
1261 visitedset = util.set()
1262 for branchrev in branchrevs:
1262 for branchrev in branchrevs:
1263 branch = repo[branchrev].branch()
1263 branch = repo[branchrev].branch()
1264 if branch in visitedset:
1264 if branch in visitedset:
1265 continue
1265 continue
1266 visitedset.add(branch)
1266 visitedset.add(branch)
1267 bheads = repo.branchheads(branch, start)
1267 bheads = repo.branchheads(branch, start)
1268 if not bheads:
1268 if not bheads:
1269 if branch != branchrev:
1269 if branch != branchrev:
1270 ui.warn(_("no changes on branch %s containing %s are "
1270 ui.warn(_("no changes on branch %s containing %s are "
1271 "reachable from %s\n")
1271 "reachable from %s\n")
1272 % (branch, branchrev, opts.get('rev')))
1272 % (branch, branchrev, opts.get('rev')))
1273 else:
1273 else:
1274 ui.warn(_("no changes on branch %s are reachable from %s\n")
1274 ui.warn(_("no changes on branch %s are reachable from %s\n")
1275 % (branch, opts.get('rev')))
1275 % (branch, opts.get('rev')))
1276 heads.extend(bheads)
1276 heads.extend(bheads)
1277 if not heads:
1277 if not heads:
1278 return 1
1278 return 1
1279 displayer = cmdutil.show_changeset(ui, repo, opts)
1279 displayer = cmdutil.show_changeset(ui, repo, opts)
1280 for n in heads:
1280 for n in heads:
1281 displayer.show(repo[n])
1281 displayer.show(repo[n])
1282
1282
1283 def help_(ui, name=None, with_version=False):
1283 def help_(ui, name=None, with_version=False):
1284 """show help for a given topic or a help overview
1284 """show help for a given topic or a help overview
1285
1285
1286 With no arguments, print a list of commands and short help.
1286 With no arguments, print a list of commands and short help.
1287
1287
1288 Given a topic, extension, or command name, print help for that topic."""
1288 Given a topic, extension, or command name, print help for that topic."""
1289 option_lists = []
1289 option_lists = []
1290
1290
1291 def addglobalopts(aliases):
1291 def addglobalopts(aliases):
1292 if ui.verbose:
1292 if ui.verbose:
1293 option_lists.append((_("global options:"), globalopts))
1293 option_lists.append((_("global options:"), globalopts))
1294 if name == 'shortlist':
1294 if name == 'shortlist':
1295 option_lists.append((_('use "hg help" for the full list '
1295 option_lists.append((_('use "hg help" for the full list '
1296 'of commands'), ()))
1296 'of commands'), ()))
1297 else:
1297 else:
1298 if name == 'shortlist':
1298 if name == 'shortlist':
1299 msg = _('use "hg help" for the full list of commands '
1299 msg = _('use "hg help" for the full list of commands '
1300 'or "hg -v" for details')
1300 'or "hg -v" for details')
1301 elif aliases:
1301 elif aliases:
1302 msg = _('use "hg -v help%s" to show aliases and '
1302 msg = _('use "hg -v help%s" to show aliases and '
1303 'global options') % (name and " " + name or "")
1303 'global options') % (name and " " + name or "")
1304 else:
1304 else:
1305 msg = _('use "hg -v help %s" to show global options') % name
1305 msg = _('use "hg -v help %s" to show global options') % name
1306 option_lists.append((msg, ()))
1306 option_lists.append((msg, ()))
1307
1307
1308 def helpcmd(name):
1308 def helpcmd(name):
1309 if with_version:
1309 if with_version:
1310 version_(ui)
1310 version_(ui)
1311 ui.write('\n')
1311 ui.write('\n')
1312
1312
1313 try:
1313 try:
1314 aliases, i = cmdutil.findcmd(name, table, False)
1314 aliases, i = cmdutil.findcmd(name, table, False)
1315 except cmdutil.AmbiguousCommand, inst:
1315 except cmdutil.AmbiguousCommand, inst:
1316 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1316 select = lambda c: c.lstrip('^').startswith(inst.args[0])
1317 helplist(_('list of commands:\n\n'), select)
1317 helplist(_('list of commands:\n\n'), select)
1318 return
1318 return
1319
1319
1320 # synopsis
1320 # synopsis
1321 if len(i) > 2:
1321 if len(i) > 2:
1322 if i[2].startswith('hg'):
1322 if i[2].startswith('hg'):
1323 ui.write("%s\n" % i[2])
1323 ui.write("%s\n" % i[2])
1324 else:
1324 else:
1325 ui.write('hg %s %s\n' % (aliases[0], i[2]))
1325 ui.write('hg %s %s\n' % (aliases[0], i[2]))
1326 else:
1326 else:
1327 ui.write('hg %s\n' % aliases[0])
1327 ui.write('hg %s\n' % aliases[0])
1328
1328
1329 # aliases
1329 # aliases
1330 if not ui.quiet and len(aliases) > 1:
1330 if not ui.quiet and len(aliases) > 1:
1331 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1331 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1332
1332
1333 # description
1333 # description
1334 doc = gettext(i[0].__doc__)
1334 doc = gettext(i[0].__doc__)
1335 if not doc:
1335 if not doc:
1336 doc = _("(No help text available)")
1336 doc = _("(no help text available)")
1337 if ui.quiet:
1337 if ui.quiet:
1338 doc = doc.splitlines(0)[0]
1338 doc = doc.splitlines(0)[0]
1339 ui.write("\n%s\n" % doc.rstrip())
1339 ui.write("\n%s\n" % doc.rstrip())
1340
1340
1341 if not ui.quiet:
1341 if not ui.quiet:
1342 # options
1342 # options
1343 if i[1]:
1343 if i[1]:
1344 option_lists.append((_("options:\n"), i[1]))
1344 option_lists.append((_("options:\n"), i[1]))
1345
1345
1346 addglobalopts(False)
1346 addglobalopts(False)
1347
1347
1348 def helplist(header, select=None):
1348 def helplist(header, select=None):
1349 h = {}
1349 h = {}
1350 cmds = {}
1350 cmds = {}
1351 for c, e in table.items():
1351 for c, e in table.items():
1352 f = c.split("|", 1)[0]
1352 f = c.split("|", 1)[0]
1353 if select and not select(f):
1353 if select and not select(f):
1354 continue
1354 continue
1355 if (not select and name != 'shortlist' and
1355 if (not select and name != 'shortlist' and
1356 e[0].__module__ != __name__):
1356 e[0].__module__ != __name__):
1357 continue
1357 continue
1358 if name == "shortlist" and not f.startswith("^"):
1358 if name == "shortlist" and not f.startswith("^"):
1359 continue
1359 continue
1360 f = f.lstrip("^")
1360 f = f.lstrip("^")
1361 if not ui.debugflag and f.startswith("debug"):
1361 if not ui.debugflag and f.startswith("debug"):
1362 continue
1362 continue
1363 doc = gettext(e[0].__doc__)
1363 doc = gettext(e[0].__doc__)
1364 if not doc:
1364 if not doc:
1365 doc = _("(No help text available)")
1365 doc = _("(no help text available)")
1366 h[f] = doc.splitlines(0)[0].rstrip()
1366 h[f] = doc.splitlines(0)[0].rstrip()
1367 cmds[f] = c.lstrip("^")
1367 cmds[f] = c.lstrip("^")
1368
1368
1369 if not h:
1369 if not h:
1370 ui.status(_('no commands defined\n'))
1370 ui.status(_('no commands defined\n'))
1371 return
1371 return
1372
1372
1373 ui.status(header)
1373 ui.status(header)
1374 fns = util.sort(h)
1374 fns = util.sort(h)
1375 m = max(map(len, fns))
1375 m = max(map(len, fns))
1376 for f in fns:
1376 for f in fns:
1377 if ui.verbose:
1377 if ui.verbose:
1378 commands = cmds[f].replace("|",", ")
1378 commands = cmds[f].replace("|",", ")
1379 ui.write(" %s:\n %s\n"%(commands, h[f]))
1379 ui.write(" %s:\n %s\n"%(commands, h[f]))
1380 else:
1380 else:
1381 ui.write(' %-*s %s\n' % (m, f, h[f]))
1381 ui.write(' %-*s %s\n' % (m, f, h[f]))
1382
1382
1383 exts = list(extensions.extensions())
1383 exts = list(extensions.extensions())
1384 if exts and name != 'shortlist':
1384 if exts and name != 'shortlist':
1385 ui.write(_('\nenabled extensions:\n\n'))
1385 ui.write(_('\nenabled extensions:\n\n'))
1386 maxlength = 0
1386 maxlength = 0
1387 exthelps = []
1387 exthelps = []
1388 for ename, ext in exts:
1388 for ename, ext in exts:
1389 doc = (ext.__doc__ or _('(no help text available)'))
1389 doc = (ext.__doc__ or _('(no help text available)'))
1390 ename = ename.split('.')[-1]
1390 ename = ename.split('.')[-1]
1391 maxlength = max(len(ename), maxlength)
1391 maxlength = max(len(ename), maxlength)
1392 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1392 exthelps.append((ename, doc.splitlines(0)[0].strip()))
1393 for ename, text in exthelps:
1393 for ename, text in exthelps:
1394 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1394 ui.write(_(' %s %s\n') % (ename.ljust(maxlength), text))
1395
1395
1396 if not ui.quiet:
1396 if not ui.quiet:
1397 addglobalopts(True)
1397 addglobalopts(True)
1398
1398
1399 def helptopic(name):
1399 def helptopic(name):
1400 for names, header, doc in help.helptable:
1400 for names, header, doc in help.helptable:
1401 if name in names:
1401 if name in names:
1402 break
1402 break
1403 else:
1403 else:
1404 raise cmdutil.UnknownCommand(name)
1404 raise cmdutil.UnknownCommand(name)
1405
1405
1406 # description
1406 # description
1407 if not doc:
1407 if not doc:
1408 doc = _("(No help text available)")
1408 doc = _("(no help text available)")
1409 if callable(doc):
1409 if callable(doc):
1410 doc = doc()
1410 doc = doc()
1411
1411
1412 ui.write("%s\n" % header)
1412 ui.write("%s\n" % header)
1413 ui.write("%s\n" % doc.rstrip())
1413 ui.write("%s\n" % doc.rstrip())
1414
1414
1415 def helpext(name):
1415 def helpext(name):
1416 try:
1416 try:
1417 mod = extensions.find(name)
1417 mod = extensions.find(name)
1418 except KeyError:
1418 except KeyError:
1419 raise cmdutil.UnknownCommand(name)
1419 raise cmdutil.UnknownCommand(name)
1420
1420
1421 doc = gettext(mod.__doc__) or _('No help text available')
1421 doc = gettext(mod.__doc__) or _('no help text available')
1422 doc = doc.splitlines(0)
1422 doc = doc.splitlines(0)
1423 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1423 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1424 for d in doc[1:]:
1424 for d in doc[1:]:
1425 ui.write(d, '\n')
1425 ui.write(d, '\n')
1426
1426
1427 ui.status('\n')
1427 ui.status('\n')
1428
1428
1429 try:
1429 try:
1430 ct = mod.cmdtable
1430 ct = mod.cmdtable
1431 except AttributeError:
1431 except AttributeError:
1432 ct = {}
1432 ct = {}
1433
1433
1434 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1434 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1435 helplist(_('list of commands:\n\n'), modcmds.has_key)
1435 helplist(_('list of commands:\n\n'), modcmds.has_key)
1436
1436
1437 if name and name != 'shortlist':
1437 if name and name != 'shortlist':
1438 i = None
1438 i = None
1439 for f in (helptopic, helpcmd, helpext):
1439 for f in (helptopic, helpcmd, helpext):
1440 try:
1440 try:
1441 f(name)
1441 f(name)
1442 i = None
1442 i = None
1443 break
1443 break
1444 except cmdutil.UnknownCommand, inst:
1444 except cmdutil.UnknownCommand, inst:
1445 i = inst
1445 i = inst
1446 if i:
1446 if i:
1447 raise i
1447 raise i
1448
1448
1449 else:
1449 else:
1450 # program name
1450 # program name
1451 if ui.verbose or with_version:
1451 if ui.verbose or with_version:
1452 version_(ui)
1452 version_(ui)
1453 else:
1453 else:
1454 ui.status(_("Mercurial Distributed SCM\n"))
1454 ui.status(_("Mercurial Distributed SCM\n"))
1455 ui.status('\n')
1455 ui.status('\n')
1456
1456
1457 # list of commands
1457 # list of commands
1458 if name == "shortlist":
1458 if name == "shortlist":
1459 header = _('basic commands:\n\n')
1459 header = _('basic commands:\n\n')
1460 else:
1460 else:
1461 header = _('list of commands:\n\n')
1461 header = _('list of commands:\n\n')
1462
1462
1463 helplist(header)
1463 helplist(header)
1464
1464
1465 # list all option lists
1465 # list all option lists
1466 opt_output = []
1466 opt_output = []
1467 for title, options in option_lists:
1467 for title, options in option_lists:
1468 opt_output.append(("\n%s" % title, None))
1468 opt_output.append(("\n%s" % title, None))
1469 for shortopt, longopt, default, desc in options:
1469 for shortopt, longopt, default, desc in options:
1470 if "DEPRECATED" in desc and not ui.verbose: continue
1470 if "DEPRECATED" in desc and not ui.verbose: continue
1471 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1471 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1472 longopt and " --%s" % longopt),
1472 longopt and " --%s" % longopt),
1473 "%s%s" % (desc,
1473 "%s%s" % (desc,
1474 default
1474 default
1475 and _(" (default: %s)") % default
1475 and _(" (default: %s)") % default
1476 or "")))
1476 or "")))
1477
1477
1478 if not name:
1478 if not name:
1479 ui.write(_("\nadditional help topics:\n\n"))
1479 ui.write(_("\nadditional help topics:\n\n"))
1480 topics = []
1480 topics = []
1481 for names, header, doc in help.helptable:
1481 for names, header, doc in help.helptable:
1482 names = [(-len(name), name) for name in names]
1482 names = [(-len(name), name) for name in names]
1483 names.sort()
1483 names.sort()
1484 topics.append((names[0][1], header))
1484 topics.append((names[0][1], header))
1485 topics_len = max([len(s[0]) for s in topics])
1485 topics_len = max([len(s[0]) for s in topics])
1486 for t, desc in topics:
1486 for t, desc in topics:
1487 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1487 ui.write(" %-*s %s\n" % (topics_len, t, desc))
1488
1488
1489 if opt_output:
1489 if opt_output:
1490 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1490 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1491 for first, second in opt_output:
1491 for first, second in opt_output:
1492 if second:
1492 if second:
1493 ui.write(" %-*s %s\n" % (opts_len, first, second))
1493 ui.write(" %-*s %s\n" % (opts_len, first, second))
1494 else:
1494 else:
1495 ui.write("%s\n" % first)
1495 ui.write("%s\n" % first)
1496
1496
1497 def identify(ui, repo, source=None,
1497 def identify(ui, repo, source=None,
1498 rev=None, num=None, id=None, branch=None, tags=None):
1498 rev=None, num=None, id=None, branch=None, tags=None):
1499 """identify the working copy or specified revision
1499 """identify the working copy or specified revision
1500
1500
1501 With no revision, print a summary of the current state of the repo.
1501 With no revision, print a summary of the current state of the repo.
1502
1502
1503 With a path, do a lookup in another repository.
1503 With a path, do a lookup in another repository.
1504
1504
1505 This summary identifies the repository state using one or two parent
1505 This summary identifies the repository state using one or two parent
1506 hash identifiers, followed by a "+" if there are uncommitted changes
1506 hash identifiers, followed by a "+" if there are uncommitted changes
1507 in the working directory, a list of tags for this revision and a branch
1507 in the working directory, a list of tags for this revision and a branch
1508 name for non-default branches.
1508 name for non-default branches.
1509 """
1509 """
1510
1510
1511 if not repo and not source:
1511 if not repo and not source:
1512 raise util.Abort(_("There is no Mercurial repository here "
1512 raise util.Abort(_("There is no Mercurial repository here "
1513 "(.hg not found)"))
1513 "(.hg not found)"))
1514
1514
1515 hexfunc = ui.debugflag and hex or short
1515 hexfunc = ui.debugflag and hex or short
1516 default = not (num or id or branch or tags)
1516 default = not (num or id or branch or tags)
1517 output = []
1517 output = []
1518
1518
1519 if source:
1519 if source:
1520 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1520 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1521 srepo = hg.repository(ui, source)
1521 srepo = hg.repository(ui, source)
1522 if not rev and revs:
1522 if not rev and revs:
1523 rev = revs[0]
1523 rev = revs[0]
1524 if not rev:
1524 if not rev:
1525 rev = "tip"
1525 rev = "tip"
1526 if num or branch or tags:
1526 if num or branch or tags:
1527 raise util.Abort(
1527 raise util.Abort(
1528 "can't query remote revision number, branch, or tags")
1528 "can't query remote revision number, branch, or tags")
1529 output = [hexfunc(srepo.lookup(rev))]
1529 output = [hexfunc(srepo.lookup(rev))]
1530 elif not rev:
1530 elif not rev:
1531 ctx = repo[None]
1531 ctx = repo[None]
1532 parents = ctx.parents()
1532 parents = ctx.parents()
1533 changed = False
1533 changed = False
1534 if default or id or num:
1534 if default or id or num:
1535 changed = ctx.files() + ctx.deleted()
1535 changed = ctx.files() + ctx.deleted()
1536 if default or id:
1536 if default or id:
1537 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1537 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1538 (changed) and "+" or "")]
1538 (changed) and "+" or "")]
1539 if num:
1539 if num:
1540 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1540 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1541 (changed) and "+" or ""))
1541 (changed) and "+" or ""))
1542 else:
1542 else:
1543 ctx = repo[rev]
1543 ctx = repo[rev]
1544 if default or id:
1544 if default or id:
1545 output = [hexfunc(ctx.node())]
1545 output = [hexfunc(ctx.node())]
1546 if num:
1546 if num:
1547 output.append(str(ctx.rev()))
1547 output.append(str(ctx.rev()))
1548
1548
1549 if not source and default and not ui.quiet:
1549 if not source and default and not ui.quiet:
1550 b = util.tolocal(ctx.branch())
1550 b = util.tolocal(ctx.branch())
1551 if b != 'default':
1551 if b != 'default':
1552 output.append("(%s)" % b)
1552 output.append("(%s)" % b)
1553
1553
1554 # multiple tags for a single parent separated by '/'
1554 # multiple tags for a single parent separated by '/'
1555 t = "/".join(ctx.tags())
1555 t = "/".join(ctx.tags())
1556 if t:
1556 if t:
1557 output.append(t)
1557 output.append(t)
1558
1558
1559 if branch:
1559 if branch:
1560 output.append(util.tolocal(ctx.branch()))
1560 output.append(util.tolocal(ctx.branch()))
1561
1561
1562 if tags:
1562 if tags:
1563 output.extend(ctx.tags())
1563 output.extend(ctx.tags())
1564
1564
1565 ui.write("%s\n" % ' '.join(output))
1565 ui.write("%s\n" % ' '.join(output))
1566
1566
1567 def import_(ui, repo, patch1, *patches, **opts):
1567 def import_(ui, repo, patch1, *patches, **opts):
1568 """import an ordered set of patches
1568 """import an ordered set of patches
1569
1569
1570 Import a list of patches and commit them individually.
1570 Import a list of patches and commit them individually.
1571
1571
1572 If there are outstanding changes in the working directory, import
1572 If there are outstanding changes in the working directory, import
1573 will abort unless given the -f flag.
1573 will abort unless given the -f flag.
1574
1574
1575 You can import a patch straight from a mail message. Even patches
1575 You can import a patch straight from a mail message. Even patches
1576 as attachments work (body part must be type text/plain or
1576 as attachments work (body part must be type text/plain or
1577 text/x-patch to be used). From and Subject headers of email
1577 text/x-patch to be used). From and Subject headers of email
1578 message are used as default committer and commit message. All
1578 message are used as default committer and commit message. All
1579 text/plain body parts before first diff are added to commit
1579 text/plain body parts before first diff are added to commit
1580 message.
1580 message.
1581
1581
1582 If the imported patch was generated by hg export, user and description
1582 If the imported patch was generated by hg export, user and description
1583 from patch override values from message headers and body. Values
1583 from patch override values from message headers and body. Values
1584 given on command line with -m and -u override these.
1584 given on command line with -m and -u override these.
1585
1585
1586 If --exact is specified, import will set the working directory
1586 If --exact is specified, import will set the working directory
1587 to the parent of each patch before applying it, and will abort
1587 to the parent of each patch before applying it, and will abort
1588 if the resulting changeset has a different ID than the one
1588 if the resulting changeset has a different ID than the one
1589 recorded in the patch. This may happen due to character set
1589 recorded in the patch. This may happen due to character set
1590 problems or other deficiencies in the text patch format.
1590 problems or other deficiencies in the text patch format.
1591
1591
1592 With --similarity, hg will attempt to discover renames and copies
1592 With --similarity, hg will attempt to discover renames and copies
1593 in the patch in the same way as 'addremove'.
1593 in the patch in the same way as 'addremove'.
1594
1594
1595 To read a patch from standard input, use patch name "-".
1595 To read a patch from standard input, use patch name "-".
1596 See 'hg help dates' for a list of formats valid for -d/--date.
1596 See 'hg help dates' for a list of formats valid for -d/--date.
1597 """
1597 """
1598 patches = (patch1,) + patches
1598 patches = (patch1,) + patches
1599
1599
1600 date = opts.get('date')
1600 date = opts.get('date')
1601 if date:
1601 if date:
1602 opts['date'] = util.parsedate(date)
1602 opts['date'] = util.parsedate(date)
1603
1603
1604 try:
1604 try:
1605 sim = float(opts.get('similarity') or 0)
1605 sim = float(opts.get('similarity') or 0)
1606 except ValueError:
1606 except ValueError:
1607 raise util.Abort(_('similarity must be a number'))
1607 raise util.Abort(_('similarity must be a number'))
1608 if sim < 0 or sim > 100:
1608 if sim < 0 or sim > 100:
1609 raise util.Abort(_('similarity must be between 0 and 100'))
1609 raise util.Abort(_('similarity must be between 0 and 100'))
1610
1610
1611 if opts.get('exact') or not opts.get('force'):
1611 if opts.get('exact') or not opts.get('force'):
1612 cmdutil.bail_if_changed(repo)
1612 cmdutil.bail_if_changed(repo)
1613
1613
1614 d = opts["base"]
1614 d = opts["base"]
1615 strip = opts["strip"]
1615 strip = opts["strip"]
1616 wlock = lock = None
1616 wlock = lock = None
1617 try:
1617 try:
1618 wlock = repo.wlock()
1618 wlock = repo.wlock()
1619 lock = repo.lock()
1619 lock = repo.lock()
1620 for p in patches:
1620 for p in patches:
1621 pf = os.path.join(d, p)
1621 pf = os.path.join(d, p)
1622
1622
1623 if pf == '-':
1623 if pf == '-':
1624 ui.status(_("applying patch from stdin\n"))
1624 ui.status(_("applying patch from stdin\n"))
1625 pf = sys.stdin
1625 pf = sys.stdin
1626 else:
1626 else:
1627 ui.status(_("applying %s\n") % p)
1627 ui.status(_("applying %s\n") % p)
1628 pf = url.open(ui, pf)
1628 pf = url.open(ui, pf)
1629 data = patch.extract(ui, pf)
1629 data = patch.extract(ui, pf)
1630 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1630 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1631
1631
1632 if tmpname is None:
1632 if tmpname is None:
1633 raise util.Abort(_('no diffs found'))
1633 raise util.Abort(_('no diffs found'))
1634
1634
1635 try:
1635 try:
1636 cmdline_message = cmdutil.logmessage(opts)
1636 cmdline_message = cmdutil.logmessage(opts)
1637 if cmdline_message:
1637 if cmdline_message:
1638 # pickup the cmdline msg
1638 # pickup the cmdline msg
1639 message = cmdline_message
1639 message = cmdline_message
1640 elif message:
1640 elif message:
1641 # pickup the patch msg
1641 # pickup the patch msg
1642 message = message.strip()
1642 message = message.strip()
1643 else:
1643 else:
1644 # launch the editor
1644 # launch the editor
1645 message = None
1645 message = None
1646 ui.debug(_('message:\n%s\n') % message)
1646 ui.debug(_('message:\n%s\n') % message)
1647
1647
1648 wp = repo.parents()
1648 wp = repo.parents()
1649 if opts.get('exact'):
1649 if opts.get('exact'):
1650 if not nodeid or not p1:
1650 if not nodeid or not p1:
1651 raise util.Abort(_('not a mercurial patch'))
1651 raise util.Abort(_('not a mercurial patch'))
1652 p1 = repo.lookup(p1)
1652 p1 = repo.lookup(p1)
1653 p2 = repo.lookup(p2 or hex(nullid))
1653 p2 = repo.lookup(p2 or hex(nullid))
1654
1654
1655 if p1 != wp[0].node():
1655 if p1 != wp[0].node():
1656 hg.clean(repo, p1)
1656 hg.clean(repo, p1)
1657 repo.dirstate.setparents(p1, p2)
1657 repo.dirstate.setparents(p1, p2)
1658 elif p2:
1658 elif p2:
1659 try:
1659 try:
1660 p1 = repo.lookup(p1)
1660 p1 = repo.lookup(p1)
1661 p2 = repo.lookup(p2)
1661 p2 = repo.lookup(p2)
1662 if p1 == wp[0].node():
1662 if p1 == wp[0].node():
1663 repo.dirstate.setparents(p1, p2)
1663 repo.dirstate.setparents(p1, p2)
1664 except RepoError:
1664 except RepoError:
1665 pass
1665 pass
1666 if opts.get('exact') or opts.get('import_branch'):
1666 if opts.get('exact') or opts.get('import_branch'):
1667 repo.dirstate.setbranch(branch or 'default')
1667 repo.dirstate.setbranch(branch or 'default')
1668
1668
1669 files = {}
1669 files = {}
1670 try:
1670 try:
1671 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1671 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1672 files=files)
1672 files=files)
1673 finally:
1673 finally:
1674 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1674 files = patch.updatedir(ui, repo, files, similarity=sim/100.)
1675 if not opts.get('no_commit'):
1675 if not opts.get('no_commit'):
1676 n = repo.commit(files, message, opts.get('user') or user,
1676 n = repo.commit(files, message, opts.get('user') or user,
1677 opts.get('date') or date)
1677 opts.get('date') or date)
1678 if opts.get('exact'):
1678 if opts.get('exact'):
1679 if hex(n) != nodeid:
1679 if hex(n) != nodeid:
1680 repo.rollback()
1680 repo.rollback()
1681 raise util.Abort(_('patch is damaged'
1681 raise util.Abort(_('patch is damaged'
1682 ' or loses information'))
1682 ' or loses information'))
1683 # Force a dirstate write so that the next transaction
1683 # Force a dirstate write so that the next transaction
1684 # backups an up-do-date file.
1684 # backups an up-do-date file.
1685 repo.dirstate.write()
1685 repo.dirstate.write()
1686 finally:
1686 finally:
1687 os.unlink(tmpname)
1687 os.unlink(tmpname)
1688 finally:
1688 finally:
1689 del lock, wlock
1689 del lock, wlock
1690
1690
1691 def incoming(ui, repo, source="default", **opts):
1691 def incoming(ui, repo, source="default", **opts):
1692 """show new changesets found in source
1692 """show new changesets found in source
1693
1693
1694 Show new changesets found in the specified path/URL or the default
1694 Show new changesets found in the specified path/URL or the default
1695 pull location. These are the changesets that would be pulled if a pull
1695 pull location. These are the changesets that would be pulled if a pull
1696 was requested.
1696 was requested.
1697
1697
1698 For remote repository, using --bundle avoids downloading the changesets
1698 For remote repository, using --bundle avoids downloading the changesets
1699 twice if the incoming is followed by a pull.
1699 twice if the incoming is followed by a pull.
1700
1700
1701 See pull for valid source format details.
1701 See pull for valid source format details.
1702 """
1702 """
1703 limit = cmdutil.loglimit(opts)
1703 limit = cmdutil.loglimit(opts)
1704 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1704 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
1705 cmdutil.setremoteconfig(ui, opts)
1705 cmdutil.setremoteconfig(ui, opts)
1706
1706
1707 other = hg.repository(ui, source)
1707 other = hg.repository(ui, source)
1708 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1708 ui.status(_('comparing with %s\n') % url.hidepassword(source))
1709 if revs:
1709 if revs:
1710 revs = [other.lookup(rev) for rev in revs]
1710 revs = [other.lookup(rev) for rev in revs]
1711 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1711 common, incoming, rheads = repo.findcommonincoming(other, heads=revs,
1712 force=opts["force"])
1712 force=opts["force"])
1713 if not incoming:
1713 if not incoming:
1714 try:
1714 try:
1715 os.unlink(opts["bundle"])
1715 os.unlink(opts["bundle"])
1716 except:
1716 except:
1717 pass
1717 pass
1718 ui.status(_("no changes found\n"))
1718 ui.status(_("no changes found\n"))
1719 return 1
1719 return 1
1720
1720
1721 cleanup = None
1721 cleanup = None
1722 try:
1722 try:
1723 fname = opts["bundle"]
1723 fname = opts["bundle"]
1724 if fname or not other.local():
1724 if fname or not other.local():
1725 # create a bundle (uncompressed if other repo is not local)
1725 # create a bundle (uncompressed if other repo is not local)
1726
1726
1727 if revs is None and other.capable('changegroupsubset'):
1727 if revs is None and other.capable('changegroupsubset'):
1728 revs = rheads
1728 revs = rheads
1729
1729
1730 if revs is None:
1730 if revs is None:
1731 cg = other.changegroup(incoming, "incoming")
1731 cg = other.changegroup(incoming, "incoming")
1732 else:
1732 else:
1733 cg = other.changegroupsubset(incoming, revs, 'incoming')
1733 cg = other.changegroupsubset(incoming, revs, 'incoming')
1734 bundletype = other.local() and "HG10BZ" or "HG10UN"
1734 bundletype = other.local() and "HG10BZ" or "HG10UN"
1735 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1735 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1736 # keep written bundle?
1736 # keep written bundle?
1737 if opts["bundle"]:
1737 if opts["bundle"]:
1738 cleanup = None
1738 cleanup = None
1739 if not other.local():
1739 if not other.local():
1740 # use the created uncompressed bundlerepo
1740 # use the created uncompressed bundlerepo
1741 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1741 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1742
1742
1743 o = other.changelog.nodesbetween(incoming, revs)[0]
1743 o = other.changelog.nodesbetween(incoming, revs)[0]
1744 if opts.get('newest_first'):
1744 if opts.get('newest_first'):
1745 o.reverse()
1745 o.reverse()
1746 displayer = cmdutil.show_changeset(ui, other, opts)
1746 displayer = cmdutil.show_changeset(ui, other, opts)
1747 count = 0
1747 count = 0
1748 for n in o:
1748 for n in o:
1749 if count >= limit:
1749 if count >= limit:
1750 break
1750 break
1751 parents = [p for p in other.changelog.parents(n) if p != nullid]
1751 parents = [p for p in other.changelog.parents(n) if p != nullid]
1752 if opts.get('no_merges') and len(parents) == 2:
1752 if opts.get('no_merges') and len(parents) == 2:
1753 continue
1753 continue
1754 count += 1
1754 count += 1
1755 displayer.show(other[n])
1755 displayer.show(other[n])
1756 finally:
1756 finally:
1757 if hasattr(other, 'close'):
1757 if hasattr(other, 'close'):
1758 other.close()
1758 other.close()
1759 if cleanup:
1759 if cleanup:
1760 os.unlink(cleanup)
1760 os.unlink(cleanup)
1761
1761
1762 def init(ui, dest=".", **opts):
1762 def init(ui, dest=".", **opts):
1763 """create a new repository in the given directory
1763 """create a new repository in the given directory
1764
1764
1765 Initialize a new repository in the given directory. If the given
1765 Initialize a new repository in the given directory. If the given
1766 directory does not exist, it is created.
1766 directory does not exist, it is created.
1767
1767
1768 If no directory is given, the current directory is used.
1768 If no directory is given, the current directory is used.
1769
1769
1770 It is possible to specify an ssh:// URL as the destination.
1770 It is possible to specify an ssh:// URL as the destination.
1771 Look at the help text for the pull command for important details
1771 Look at the help text for the pull command for important details
1772 about ssh:// URLs.
1772 about ssh:// URLs.
1773 """
1773 """
1774 cmdutil.setremoteconfig(ui, opts)
1774 cmdutil.setremoteconfig(ui, opts)
1775 hg.repository(ui, dest, create=1)
1775 hg.repository(ui, dest, create=1)
1776
1776
1777 def locate(ui, repo, *pats, **opts):
1777 def locate(ui, repo, *pats, **opts):
1778 """locate files matching specific patterns
1778 """locate files matching specific patterns
1779
1779
1780 Print all files under Mercurial control whose names match the
1780 Print all files under Mercurial control whose names match the
1781 given patterns.
1781 given patterns.
1782
1782
1783 This command searches the entire repository by default. To search
1783 This command searches the entire repository by default. To search
1784 just the current directory and its subdirectories, use
1784 just the current directory and its subdirectories, use
1785 "--include .".
1785 "--include .".
1786
1786
1787 If no patterns are given to match, this command prints all file
1787 If no patterns are given to match, this command prints all file
1788 names.
1788 names.
1789
1789
1790 If you want to feed the output of this command into the "xargs"
1790 If you want to feed the output of this command into the "xargs"
1791 command, use the "-0" option to both this command and "xargs".
1791 command, use the "-0" option to both this command and "xargs".
1792 This will avoid the problem of "xargs" treating single filenames
1792 This will avoid the problem of "xargs" treating single filenames
1793 that contain white space as multiple filenames.
1793 that contain white space as multiple filenames.
1794 """
1794 """
1795 end = opts.get('print0') and '\0' or '\n'
1795 end = opts.get('print0') and '\0' or '\n'
1796 rev = opts.get('rev') or None
1796 rev = opts.get('rev') or None
1797
1797
1798 ret = 1
1798 ret = 1
1799 m = cmdutil.match(repo, pats, opts, default='relglob')
1799 m = cmdutil.match(repo, pats, opts, default='relglob')
1800 m.bad = lambda x,y: False
1800 m.bad = lambda x,y: False
1801 for abs in repo[rev].walk(m):
1801 for abs in repo[rev].walk(m):
1802 if not rev and abs not in repo.dirstate:
1802 if not rev and abs not in repo.dirstate:
1803 continue
1803 continue
1804 if opts.get('fullpath'):
1804 if opts.get('fullpath'):
1805 ui.write(repo.wjoin(abs), end)
1805 ui.write(repo.wjoin(abs), end)
1806 else:
1806 else:
1807 ui.write(((pats and m.rel(abs)) or abs), end)
1807 ui.write(((pats and m.rel(abs)) or abs), end)
1808 ret = 0
1808 ret = 0
1809
1809
1810 return ret
1810 return ret
1811
1811
1812 def log(ui, repo, *pats, **opts):
1812 def log(ui, repo, *pats, **opts):
1813 """show revision history of entire repository or files
1813 """show revision history of entire repository or files
1814
1814
1815 Print the revision history of the specified files or the entire
1815 Print the revision history of the specified files or the entire
1816 project.
1816 project.
1817
1817
1818 File history is shown without following rename or copy history of
1818 File history is shown without following rename or copy history of
1819 files. Use -f/--follow with a file name to follow history across
1819 files. Use -f/--follow with a file name to follow history across
1820 renames and copies. --follow without a file name will only show
1820 renames and copies. --follow without a file name will only show
1821 ancestors or descendants of the starting revision. --follow-first
1821 ancestors or descendants of the starting revision. --follow-first
1822 only follows the first parent of merge revisions.
1822 only follows the first parent of merge revisions.
1823
1823
1824 If no revision range is specified, the default is tip:0 unless
1824 If no revision range is specified, the default is tip:0 unless
1825 --follow is set, in which case the working directory parent is
1825 --follow is set, in which case the working directory parent is
1826 used as the starting revision.
1826 used as the starting revision.
1827
1827
1828 See 'hg help dates' for a list of formats valid for -d/--date.
1828 See 'hg help dates' for a list of formats valid for -d/--date.
1829
1829
1830 By default this command outputs: changeset id and hash, tags,
1830 By default this command outputs: changeset id and hash, tags,
1831 non-trivial parents, user, date and time, and a summary for each
1831 non-trivial parents, user, date and time, and a summary for each
1832 commit. When the -v/--verbose switch is used, the list of changed
1832 commit. When the -v/--verbose switch is used, the list of changed
1833 files and full commit message is shown.
1833 files and full commit message is shown.
1834
1834
1835 NOTE: log -p may generate unexpected diff output for merge
1835 NOTE: log -p may generate unexpected diff output for merge
1836 changesets, as it will compare the merge changeset against its
1836 changesets, as it will compare the merge changeset against its
1837 first parent only. Also, the files: list will only reflect files
1837 first parent only. Also, the files: list will only reflect files
1838 that are different from BOTH parents.
1838 that are different from BOTH parents.
1839
1839
1840 """
1840 """
1841
1841
1842 get = util.cachefunc(lambda r: repo[r].changeset())
1842 get = util.cachefunc(lambda r: repo[r].changeset())
1843 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1843 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1844
1844
1845 limit = cmdutil.loglimit(opts)
1845 limit = cmdutil.loglimit(opts)
1846 count = 0
1846 count = 0
1847
1847
1848 if opts.get('copies') and opts.get('rev'):
1848 if opts.get('copies') and opts.get('rev'):
1849 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1849 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
1850 else:
1850 else:
1851 endrev = len(repo)
1851 endrev = len(repo)
1852 rcache = {}
1852 rcache = {}
1853 ncache = {}
1853 ncache = {}
1854 def getrenamed(fn, rev):
1854 def getrenamed(fn, rev):
1855 '''looks up all renames for a file (up to endrev) the first
1855 '''looks up all renames for a file (up to endrev) the first
1856 time the file is given. It indexes on the changerev and only
1856 time the file is given. It indexes on the changerev and only
1857 parses the manifest if linkrev != changerev.
1857 parses the manifest if linkrev != changerev.
1858 Returns rename info for fn at changerev rev.'''
1858 Returns rename info for fn at changerev rev.'''
1859 if fn not in rcache:
1859 if fn not in rcache:
1860 rcache[fn] = {}
1860 rcache[fn] = {}
1861 ncache[fn] = {}
1861 ncache[fn] = {}
1862 fl = repo.file(fn)
1862 fl = repo.file(fn)
1863 for i in fl:
1863 for i in fl:
1864 node = fl.node(i)
1864 node = fl.node(i)
1865 lr = fl.linkrev(i)
1865 lr = fl.linkrev(i)
1866 renamed = fl.renamed(node)
1866 renamed = fl.renamed(node)
1867 rcache[fn][lr] = renamed
1867 rcache[fn][lr] = renamed
1868 if renamed:
1868 if renamed:
1869 ncache[fn][node] = renamed
1869 ncache[fn][node] = renamed
1870 if lr >= endrev:
1870 if lr >= endrev:
1871 break
1871 break
1872 if rev in rcache[fn]:
1872 if rev in rcache[fn]:
1873 return rcache[fn][rev]
1873 return rcache[fn][rev]
1874
1874
1875 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1875 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1876 # filectx logic.
1876 # filectx logic.
1877
1877
1878 try:
1878 try:
1879 return repo[rev][fn].renamed()
1879 return repo[rev][fn].renamed()
1880 except revlog.LookupError:
1880 except revlog.LookupError:
1881 pass
1881 pass
1882 return None
1882 return None
1883
1883
1884 df = False
1884 df = False
1885 if opts["date"]:
1885 if opts["date"]:
1886 df = util.matchdate(opts["date"])
1886 df = util.matchdate(opts["date"])
1887
1887
1888 only_branches = opts.get('only_branch')
1888 only_branches = opts.get('only_branch')
1889
1889
1890 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1890 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1891 for st, rev, fns in changeiter:
1891 for st, rev, fns in changeiter:
1892 if st == 'add':
1892 if st == 'add':
1893 parents = [p for p in repo.changelog.parentrevs(rev)
1893 parents = [p for p in repo.changelog.parentrevs(rev)
1894 if p != nullrev]
1894 if p != nullrev]
1895 if opts.get('no_merges') and len(parents) == 2:
1895 if opts.get('no_merges') and len(parents) == 2:
1896 continue
1896 continue
1897 if opts.get('only_merges') and len(parents) != 2:
1897 if opts.get('only_merges') and len(parents) != 2:
1898 continue
1898 continue
1899
1899
1900 if only_branches:
1900 if only_branches:
1901 revbranch = get(rev)[5]['branch']
1901 revbranch = get(rev)[5]['branch']
1902 if revbranch not in only_branches:
1902 if revbranch not in only_branches:
1903 continue
1903 continue
1904
1904
1905 if df:
1905 if df:
1906 changes = get(rev)
1906 changes = get(rev)
1907 if not df(changes[2][0]):
1907 if not df(changes[2][0]):
1908 continue
1908 continue
1909
1909
1910 if opts.get('keyword'):
1910 if opts.get('keyword'):
1911 changes = get(rev)
1911 changes = get(rev)
1912 miss = 0
1912 miss = 0
1913 for k in [kw.lower() for kw in opts['keyword']]:
1913 for k in [kw.lower() for kw in opts['keyword']]:
1914 if not (k in changes[1].lower() or
1914 if not (k in changes[1].lower() or
1915 k in changes[4].lower() or
1915 k in changes[4].lower() or
1916 k in " ".join(changes[3]).lower()):
1916 k in " ".join(changes[3]).lower()):
1917 miss = 1
1917 miss = 1
1918 break
1918 break
1919 if miss:
1919 if miss:
1920 continue
1920 continue
1921
1921
1922 if opts['user']:
1922 if opts['user']:
1923 changes = get(rev)
1923 changes = get(rev)
1924 miss = 0
1924 miss = 0
1925 for k in opts['user']:
1925 for k in opts['user']:
1926 if k != changes[1]:
1926 if k != changes[1]:
1927 miss = 1
1927 miss = 1
1928 break
1928 break
1929 if miss:
1929 if miss:
1930 continue
1930 continue
1931
1931
1932 copies = []
1932 copies = []
1933 if opts.get('copies') and rev:
1933 if opts.get('copies') and rev:
1934 for fn in get(rev)[3]:
1934 for fn in get(rev)[3]:
1935 rename = getrenamed(fn, rev)
1935 rename = getrenamed(fn, rev)
1936 if rename:
1936 if rename:
1937 copies.append((fn, rename[0]))
1937 copies.append((fn, rename[0]))
1938 displayer.show(context.changectx(repo, rev), copies=copies)
1938 displayer.show(context.changectx(repo, rev), copies=copies)
1939 elif st == 'iter':
1939 elif st == 'iter':
1940 if count == limit: break
1940 if count == limit: break
1941 if displayer.flush(rev):
1941 if displayer.flush(rev):
1942 count += 1
1942 count += 1
1943
1943
1944 def manifest(ui, repo, node=None, rev=None):
1944 def manifest(ui, repo, node=None, rev=None):
1945 """output the current or given revision of the project manifest
1945 """output the current or given revision of the project manifest
1946
1946
1947 Print a list of version controlled files for the given revision.
1947 Print a list of version controlled files for the given revision.
1948 If no revision is given, the parent of the working directory is used,
1948 If no revision is given, the parent of the working directory is used,
1949 or tip if no revision is checked out.
1949 or tip if no revision is checked out.
1950
1950
1951 The manifest is the list of files being version controlled. If no revision
1951 The manifest is the list of files being version controlled. If no revision
1952 is given then the first parent of the working directory is used.
1952 is given then the first parent of the working directory is used.
1953
1953
1954 With -v flag, print file permissions, symlink and executable bits. With
1954 With -v flag, print file permissions, symlink and executable bits. With
1955 --debug flag, print file revision hashes.
1955 --debug flag, print file revision hashes.
1956 """
1956 """
1957
1957
1958 if rev and node:
1958 if rev and node:
1959 raise util.Abort(_("please specify just one revision"))
1959 raise util.Abort(_("please specify just one revision"))
1960
1960
1961 if not node:
1961 if not node:
1962 node = rev
1962 node = rev
1963
1963
1964 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1964 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
1965 ctx = repo[node]
1965 ctx = repo[node]
1966 for f in ctx:
1966 for f in ctx:
1967 if ui.debugflag:
1967 if ui.debugflag:
1968 ui.write("%40s " % hex(ctx.manifest()[f]))
1968 ui.write("%40s " % hex(ctx.manifest()[f]))
1969 if ui.verbose:
1969 if ui.verbose:
1970 ui.write(decor[ctx.flags(f)])
1970 ui.write(decor[ctx.flags(f)])
1971 ui.write("%s\n" % f)
1971 ui.write("%s\n" % f)
1972
1972
1973 def merge(ui, repo, node=None, force=None, rev=None):
1973 def merge(ui, repo, node=None, force=None, rev=None):
1974 """merge working directory with another revision
1974 """merge working directory with another revision
1975
1975
1976 Merge the contents of the current working directory and the
1976 Merge the contents of the current working directory and the
1977 requested revision. Files that changed between either parent are
1977 requested revision. Files that changed between either parent are
1978 marked as changed for the next commit and a commit must be
1978 marked as changed for the next commit and a commit must be
1979 performed before any further updates are allowed.
1979 performed before any further updates are allowed.
1980
1980
1981 If no revision is specified, the working directory's parent is a
1981 If no revision is specified, the working directory's parent is a
1982 head revision, and the current branch contains exactly one other head,
1982 head revision, and the current branch contains exactly one other head,
1983 the other head is merged with by default. Otherwise, an explicit
1983 the other head is merged with by default. Otherwise, an explicit
1984 revision to merge with must be provided.
1984 revision to merge with must be provided.
1985 """
1985 """
1986
1986
1987 if rev and node:
1987 if rev and node:
1988 raise util.Abort(_("please specify just one revision"))
1988 raise util.Abort(_("please specify just one revision"))
1989 if not node:
1989 if not node:
1990 node = rev
1990 node = rev
1991
1991
1992 if not node:
1992 if not node:
1993 branch = repo.changectx(None).branch()
1993 branch = repo.changectx(None).branch()
1994 bheads = repo.branchheads(branch)
1994 bheads = repo.branchheads(branch)
1995 if len(bheads) > 2:
1995 if len(bheads) > 2:
1996 raise util.Abort(_("branch '%s' has %d heads - "
1996 raise util.Abort(_("branch '%s' has %d heads - "
1997 "please merge with an explicit rev") %
1997 "please merge with an explicit rev") %
1998 (branch, len(bheads)))
1998 (branch, len(bheads)))
1999
1999
2000 parent = repo.dirstate.parents()[0]
2000 parent = repo.dirstate.parents()[0]
2001 if len(bheads) == 1:
2001 if len(bheads) == 1:
2002 if len(repo.heads()) > 1:
2002 if len(repo.heads()) > 1:
2003 raise util.Abort(_("branch '%s' has one head - "
2003 raise util.Abort(_("branch '%s' has one head - "
2004 "please merge with an explicit rev") %
2004 "please merge with an explicit rev") %
2005 branch)
2005 branch)
2006 msg = _('there is nothing to merge')
2006 msg = _('there is nothing to merge')
2007 if parent != repo.lookup(repo[None].branch()):
2007 if parent != repo.lookup(repo[None].branch()):
2008 msg = _('%s - use "hg update" instead') % msg
2008 msg = _('%s - use "hg update" instead') % msg
2009 raise util.Abort(msg)
2009 raise util.Abort(msg)
2010
2010
2011 if parent not in bheads:
2011 if parent not in bheads:
2012 raise util.Abort(_('working dir not at a head rev - '
2012 raise util.Abort(_('working dir not at a head rev - '
2013 'use "hg update" or merge with an explicit rev'))
2013 'use "hg update" or merge with an explicit rev'))
2014 node = parent == bheads[0] and bheads[-1] or bheads[0]
2014 node = parent == bheads[0] and bheads[-1] or bheads[0]
2015 return hg.merge(repo, node, force=force)
2015 return hg.merge(repo, node, force=force)
2016
2016
2017 def outgoing(ui, repo, dest=None, **opts):
2017 def outgoing(ui, repo, dest=None, **opts):
2018 """show changesets not found in destination
2018 """show changesets not found in destination
2019
2019
2020 Show changesets not found in the specified destination repository or
2020 Show changesets not found in the specified destination repository or
2021 the default push location. These are the changesets that would be pushed
2021 the default push location. These are the changesets that would be pushed
2022 if a push was requested.
2022 if a push was requested.
2023
2023
2024 See pull for valid destination format details.
2024 See pull for valid destination format details.
2025 """
2025 """
2026 limit = cmdutil.loglimit(opts)
2026 limit = cmdutil.loglimit(opts)
2027 dest, revs, checkout = hg.parseurl(
2027 dest, revs, checkout = hg.parseurl(
2028 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2028 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2029 cmdutil.setremoteconfig(ui, opts)
2029 cmdutil.setremoteconfig(ui, opts)
2030 if revs:
2030 if revs:
2031 revs = [repo.lookup(rev) for rev in revs]
2031 revs = [repo.lookup(rev) for rev in revs]
2032
2032
2033 other = hg.repository(ui, dest)
2033 other = hg.repository(ui, dest)
2034 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2034 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
2035 o = repo.findoutgoing(other, force=opts.get('force'))
2035 o = repo.findoutgoing(other, force=opts.get('force'))
2036 if not o:
2036 if not o:
2037 ui.status(_("no changes found\n"))
2037 ui.status(_("no changes found\n"))
2038 return 1
2038 return 1
2039 o = repo.changelog.nodesbetween(o, revs)[0]
2039 o = repo.changelog.nodesbetween(o, revs)[0]
2040 if opts.get('newest_first'):
2040 if opts.get('newest_first'):
2041 o.reverse()
2041 o.reverse()
2042 displayer = cmdutil.show_changeset(ui, repo, opts)
2042 displayer = cmdutil.show_changeset(ui, repo, opts)
2043 count = 0
2043 count = 0
2044 for n in o:
2044 for n in o:
2045 if count >= limit:
2045 if count >= limit:
2046 break
2046 break
2047 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2047 parents = [p for p in repo.changelog.parents(n) if p != nullid]
2048 if opts.get('no_merges') and len(parents) == 2:
2048 if opts.get('no_merges') and len(parents) == 2:
2049 continue
2049 continue
2050 count += 1
2050 count += 1
2051 displayer.show(repo[n])
2051 displayer.show(repo[n])
2052
2052
2053 def parents(ui, repo, file_=None, **opts):
2053 def parents(ui, repo, file_=None, **opts):
2054 """show the parents of the working dir or revision
2054 """show the parents of the working dir or revision
2055
2055
2056 Print the working directory's parent revisions. If a
2056 Print the working directory's parent revisions. If a
2057 revision is given via --rev, the parent of that revision
2057 revision is given via --rev, the parent of that revision
2058 will be printed. If a file argument is given, revision in
2058 will be printed. If a file argument is given, revision in
2059 which the file was last changed (before the working directory
2059 which the file was last changed (before the working directory
2060 revision or the argument to --rev if given) is printed.
2060 revision or the argument to --rev if given) is printed.
2061 """
2061 """
2062 rev = opts.get('rev')
2062 rev = opts.get('rev')
2063 if rev:
2063 if rev:
2064 ctx = repo[rev]
2064 ctx = repo[rev]
2065 else:
2065 else:
2066 ctx = repo[None]
2066 ctx = repo[None]
2067
2067
2068 if file_:
2068 if file_:
2069 m = cmdutil.match(repo, (file_,), opts)
2069 m = cmdutil.match(repo, (file_,), opts)
2070 if m.anypats() or len(m.files()) != 1:
2070 if m.anypats() or len(m.files()) != 1:
2071 raise util.Abort(_('can only specify an explicit file name'))
2071 raise util.Abort(_('can only specify an explicit file name'))
2072 file_ = m.files()[0]
2072 file_ = m.files()[0]
2073 filenodes = []
2073 filenodes = []
2074 for cp in ctx.parents():
2074 for cp in ctx.parents():
2075 if not cp:
2075 if not cp:
2076 continue
2076 continue
2077 try:
2077 try:
2078 filenodes.append(cp.filenode(file_))
2078 filenodes.append(cp.filenode(file_))
2079 except revlog.LookupError:
2079 except revlog.LookupError:
2080 pass
2080 pass
2081 if not filenodes:
2081 if not filenodes:
2082 raise util.Abort(_("'%s' not found in manifest!") % file_)
2082 raise util.Abort(_("'%s' not found in manifest!") % file_)
2083 fl = repo.file(file_)
2083 fl = repo.file(file_)
2084 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2084 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2085 else:
2085 else:
2086 p = [cp.node() for cp in ctx.parents()]
2086 p = [cp.node() for cp in ctx.parents()]
2087
2087
2088 displayer = cmdutil.show_changeset(ui, repo, opts)
2088 displayer = cmdutil.show_changeset(ui, repo, opts)
2089 for n in p:
2089 for n in p:
2090 if n != nullid:
2090 if n != nullid:
2091 displayer.show(repo[n])
2091 displayer.show(repo[n])
2092
2092
2093 def paths(ui, repo, search=None):
2093 def paths(ui, repo, search=None):
2094 """show definition of symbolic path names
2094 """show definition of symbolic path names
2095
2095
2096 Show definition of symbolic path name NAME. If no name is given, show
2096 Show definition of symbolic path name NAME. If no name is given, show
2097 definition of available names.
2097 definition of available names.
2098
2098
2099 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2099 Path names are defined in the [paths] section of /etc/mercurial/hgrc
2100 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2100 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
2101 """
2101 """
2102 if search:
2102 if search:
2103 for name, path in ui.configitems("paths"):
2103 for name, path in ui.configitems("paths"):
2104 if name == search:
2104 if name == search:
2105 ui.write("%s\n" % url.hidepassword(path))
2105 ui.write("%s\n" % url.hidepassword(path))
2106 return
2106 return
2107 ui.warn(_("not found!\n"))
2107 ui.warn(_("not found!\n"))
2108 return 1
2108 return 1
2109 else:
2109 else:
2110 for name, path in ui.configitems("paths"):
2110 for name, path in ui.configitems("paths"):
2111 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2111 ui.write("%s = %s\n" % (name, url.hidepassword(path)))
2112
2112
2113 def postincoming(ui, repo, modheads, optupdate, checkout):
2113 def postincoming(ui, repo, modheads, optupdate, checkout):
2114 if modheads == 0:
2114 if modheads == 0:
2115 return
2115 return
2116 if optupdate:
2116 if optupdate:
2117 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2117 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2118 return hg.update(repo, checkout)
2118 return hg.update(repo, checkout)
2119 else:
2119 else:
2120 ui.status(_("not updating, since new heads added\n"))
2120 ui.status(_("not updating, since new heads added\n"))
2121 if modheads > 1:
2121 if modheads > 1:
2122 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2122 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2123 else:
2123 else:
2124 ui.status(_("(run 'hg update' to get a working copy)\n"))
2124 ui.status(_("(run 'hg update' to get a working copy)\n"))
2125
2125
2126 def pull(ui, repo, source="default", **opts):
2126 def pull(ui, repo, source="default", **opts):
2127 """pull changes from the specified source
2127 """pull changes from the specified source
2128
2128
2129 Pull changes from a remote repository to a local one.
2129 Pull changes from a remote repository to a local one.
2130
2130
2131 This finds all changes from the repository at the specified path
2131 This finds all changes from the repository at the specified path
2132 or URL and adds them to the local repository. By default, this
2132 or URL and adds them to the local repository. By default, this
2133 does not update the copy of the project in the working directory.
2133 does not update the copy of the project in the working directory.
2134
2134
2135 Valid URLs are of the form:
2135 Valid URLs are of the form:
2136
2136
2137 local/filesystem/path (or file://local/filesystem/path)
2137 local/filesystem/path (or file://local/filesystem/path)
2138 http://[user[:pass]@]host[:port]/[path]
2138 http://[user[:pass]@]host[:port]/[path]
2139 https://[user[:pass]@]host[:port]/[path]
2139 https://[user[:pass]@]host[:port]/[path]
2140 ssh://[user[:pass]@]host[:port]/[path]
2140 ssh://[user[:pass]@]host[:port]/[path]
2141
2141
2142 Paths in the local filesystem can either point to Mercurial
2142 Paths in the local filesystem can either point to Mercurial
2143 repositories or to bundle files (as created by 'hg bundle' or
2143 repositories or to bundle files (as created by 'hg bundle' or
2144 'hg incoming --bundle').
2144 'hg incoming --bundle').
2145
2145
2146 An optional identifier after # indicates a particular branch, tag,
2146 An optional identifier after # indicates a particular branch, tag,
2147 or changeset to pull.
2147 or changeset to pull.
2148
2148
2149 Some notes about using SSH with Mercurial:
2149 Some notes about using SSH with Mercurial:
2150 - SSH requires an accessible shell account on the destination machine
2150 - SSH requires an accessible shell account on the destination machine
2151 and a copy of hg in the remote path or specified with as remotecmd.
2151 and a copy of hg in the remote path or specified with as remotecmd.
2152 - path is relative to the remote user's home directory by default.
2152 - path is relative to the remote user's home directory by default.
2153 Use an extra slash at the start of a path to specify an absolute path:
2153 Use an extra slash at the start of a path to specify an absolute path:
2154 ssh://example.com//tmp/repository
2154 ssh://example.com//tmp/repository
2155 - Mercurial doesn't use its own compression via SSH; the right thing
2155 - Mercurial doesn't use its own compression via SSH; the right thing
2156 to do is to configure it in your ~/.ssh/config, e.g.:
2156 to do is to configure it in your ~/.ssh/config, e.g.:
2157 Host *.mylocalnetwork.example.com
2157 Host *.mylocalnetwork.example.com
2158 Compression no
2158 Compression no
2159 Host *
2159 Host *
2160 Compression yes
2160 Compression yes
2161 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2161 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2162 with the --ssh command line option.
2162 with the --ssh command line option.
2163 """
2163 """
2164 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2164 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev'))
2165 cmdutil.setremoteconfig(ui, opts)
2165 cmdutil.setremoteconfig(ui, opts)
2166
2166
2167 other = hg.repository(ui, source)
2167 other = hg.repository(ui, source)
2168 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2168 ui.status(_('pulling from %s\n') % url.hidepassword(source))
2169 if revs:
2169 if revs:
2170 try:
2170 try:
2171 revs = [other.lookup(rev) for rev in revs]
2171 revs = [other.lookup(rev) for rev in revs]
2172 except NoCapability:
2172 except NoCapability:
2173 error = _("Other repository doesn't support revision lookup, "
2173 error = _("Other repository doesn't support revision lookup, "
2174 "so a rev cannot be specified.")
2174 "so a rev cannot be specified.")
2175 raise util.Abort(error)
2175 raise util.Abort(error)
2176
2176
2177 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2177 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
2178 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2178 return postincoming(ui, repo, modheads, opts.get('update'), checkout)
2179
2179
2180 def push(ui, repo, dest=None, **opts):
2180 def push(ui, repo, dest=None, **opts):
2181 """push changes to the specified destination
2181 """push changes to the specified destination
2182
2182
2183 Push changes from the local repository to the given destination.
2183 Push changes from the local repository to the given destination.
2184
2184
2185 This is the symmetrical operation for pull. It helps to move
2185 This is the symmetrical operation for pull. It helps to move
2186 changes from the current repository to a different one. If the
2186 changes from the current repository to a different one. If the
2187 destination is local this is identical to a pull in that directory
2187 destination is local this is identical to a pull in that directory
2188 from the current one.
2188 from the current one.
2189
2189
2190 By default, push will refuse to run if it detects the result would
2190 By default, push will refuse to run if it detects the result would
2191 increase the number of remote heads. This generally indicates the
2191 increase the number of remote heads. This generally indicates the
2192 the client has forgotten to pull and merge before pushing.
2192 the client has forgotten to pull and merge before pushing.
2193
2193
2194 Valid URLs are of the form:
2194 Valid URLs are of the form:
2195
2195
2196 local/filesystem/path (or file://local/filesystem/path)
2196 local/filesystem/path (or file://local/filesystem/path)
2197 ssh://[user[:pass]@]host[:port]/[path]
2197 ssh://[user[:pass]@]host[:port]/[path]
2198 http://[user[:pass]@]host[:port]/[path]
2198 http://[user[:pass]@]host[:port]/[path]
2199 https://[user[:pass]@]host[:port]/[path]
2199 https://[user[:pass]@]host[:port]/[path]
2200
2200
2201 An optional identifier after # indicates a particular branch, tag,
2201 An optional identifier after # indicates a particular branch, tag,
2202 or changeset to push. If -r is used, the named changeset and all its
2202 or changeset to push. If -r is used, the named changeset and all its
2203 ancestors will be pushed to the remote repository.
2203 ancestors will be pushed to the remote repository.
2204
2204
2205 Look at the help text for the pull command for important details
2205 Look at the help text for the pull command for important details
2206 about ssh:// URLs.
2206 about ssh:// URLs.
2207
2207
2208 Pushing to http:// and https:// URLs is only possible, if this
2208 Pushing to http:// and https:// URLs is only possible, if this
2209 feature is explicitly enabled on the remote Mercurial server.
2209 feature is explicitly enabled on the remote Mercurial server.
2210 """
2210 """
2211 dest, revs, checkout = hg.parseurl(
2211 dest, revs, checkout = hg.parseurl(
2212 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2212 ui.expandpath(dest or 'default-push', dest or 'default'), opts.get('rev'))
2213 cmdutil.setremoteconfig(ui, opts)
2213 cmdutil.setremoteconfig(ui, opts)
2214
2214
2215 other = hg.repository(ui, dest)
2215 other = hg.repository(ui, dest)
2216 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2216 ui.status(_('pushing to %s\n') % url.hidepassword(dest))
2217 if revs:
2217 if revs:
2218 revs = [repo.lookup(rev) for rev in revs]
2218 revs = [repo.lookup(rev) for rev in revs]
2219 r = repo.push(other, opts.get('force'), revs=revs)
2219 r = repo.push(other, opts.get('force'), revs=revs)
2220 return r == 0
2220 return r == 0
2221
2221
2222 def rawcommit(ui, repo, *pats, **opts):
2222 def rawcommit(ui, repo, *pats, **opts):
2223 """raw commit interface (DEPRECATED)
2223 """raw commit interface (DEPRECATED)
2224
2224
2225 (DEPRECATED)
2225 (DEPRECATED)
2226 Lowlevel commit, for use in helper scripts.
2226 Lowlevel commit, for use in helper scripts.
2227
2227
2228 This command is not intended to be used by normal users, as it is
2228 This command is not intended to be used by normal users, as it is
2229 primarily useful for importing from other SCMs.
2229 primarily useful for importing from other SCMs.
2230
2230
2231 This command is now deprecated and will be removed in a future
2231 This command is now deprecated and will be removed in a future
2232 release, please use debugsetparents and commit instead.
2232 release, please use debugsetparents and commit instead.
2233 """
2233 """
2234
2234
2235 ui.warn(_("(the rawcommit command is deprecated)\n"))
2235 ui.warn(_("(the rawcommit command is deprecated)\n"))
2236
2236
2237 message = cmdutil.logmessage(opts)
2237 message = cmdutil.logmessage(opts)
2238
2238
2239 files = cmdutil.match(repo, pats, opts).files()
2239 files = cmdutil.match(repo, pats, opts).files()
2240 if opts.get('files'):
2240 if opts.get('files'):
2241 files += open(opts['files']).read().splitlines()
2241 files += open(opts['files']).read().splitlines()
2242
2242
2243 parents = [repo.lookup(p) for p in opts['parent']]
2243 parents = [repo.lookup(p) for p in opts['parent']]
2244
2244
2245 try:
2245 try:
2246 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2246 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2247 except ValueError, inst:
2247 except ValueError, inst:
2248 raise util.Abort(str(inst))
2248 raise util.Abort(str(inst))
2249
2249
2250 def recover(ui, repo):
2250 def recover(ui, repo):
2251 """roll back an interrupted transaction
2251 """roll back an interrupted transaction
2252
2252
2253 Recover from an interrupted commit or pull.
2253 Recover from an interrupted commit or pull.
2254
2254
2255 This command tries to fix the repository status after an interrupted
2255 This command tries to fix the repository status after an interrupted
2256 operation. It should only be necessary when Mercurial suggests it.
2256 operation. It should only be necessary when Mercurial suggests it.
2257 """
2257 """
2258 if repo.recover():
2258 if repo.recover():
2259 return hg.verify(repo)
2259 return hg.verify(repo)
2260 return 1
2260 return 1
2261
2261
2262 def remove(ui, repo, *pats, **opts):
2262 def remove(ui, repo, *pats, **opts):
2263 """remove the specified files on the next commit
2263 """remove the specified files on the next commit
2264
2264
2265 Schedule the indicated files for removal from the repository.
2265 Schedule the indicated files for removal from the repository.
2266
2266
2267 This only removes files from the current branch, not from the entire
2267 This only removes files from the current branch, not from the entire
2268 project history. -A can be used to remove only files that have already
2268 project history. -A can be used to remove only files that have already
2269 been deleted, -f can be used to force deletion, and -Af can be used
2269 been deleted, -f can be used to force deletion, and -Af can be used
2270 to remove files from the next revision without deleting them.
2270 to remove files from the next revision without deleting them.
2271
2271
2272 The following table details the behavior of remove for different file
2272 The following table details the behavior of remove for different file
2273 states (columns) and option combinations (rows). The file states are
2273 states (columns) and option combinations (rows). The file states are
2274 Added, Clean, Modified and Missing (as reported by hg status). The
2274 Added, Clean, Modified and Missing (as reported by hg status). The
2275 actions are Warn, Remove (from branch) and Delete (from disk).
2275 actions are Warn, Remove (from branch) and Delete (from disk).
2276
2276
2277 A C M !
2277 A C M !
2278 none W RD W R
2278 none W RD W R
2279 -f R RD RD R
2279 -f R RD RD R
2280 -A W W W R
2280 -A W W W R
2281 -Af R R R R
2281 -Af R R R R
2282
2282
2283 This command schedules the files to be removed at the next commit.
2283 This command schedules the files to be removed at the next commit.
2284 To undo a remove before that, see hg revert.
2284 To undo a remove before that, see hg revert.
2285 """
2285 """
2286
2286
2287 after, force = opts.get('after'), opts.get('force')
2287 after, force = opts.get('after'), opts.get('force')
2288 if not pats and not after:
2288 if not pats and not after:
2289 raise util.Abort(_('no files specified'))
2289 raise util.Abort(_('no files specified'))
2290
2290
2291 m = cmdutil.match(repo, pats, opts)
2291 m = cmdutil.match(repo, pats, opts)
2292 s = repo.status(match=m, clean=True)
2292 s = repo.status(match=m, clean=True)
2293 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2293 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
2294
2294
2295 def warn(files, reason):
2295 def warn(files, reason):
2296 for f in files:
2296 for f in files:
2297 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2297 ui.warn(_('not removing %s: file %s (use -f to force removal)\n')
2298 % (m.rel(f), reason))
2298 % (m.rel(f), reason))
2299
2299
2300 if force:
2300 if force:
2301 remove, forget = modified + deleted + clean, added
2301 remove, forget = modified + deleted + clean, added
2302 elif after:
2302 elif after:
2303 remove, forget = deleted, []
2303 remove, forget = deleted, []
2304 warn(modified + added + clean, _('still exists'))
2304 warn(modified + added + clean, _('still exists'))
2305 else:
2305 else:
2306 remove, forget = deleted + clean, []
2306 remove, forget = deleted + clean, []
2307 warn(modified, _('is modified'))
2307 warn(modified, _('is modified'))
2308 warn(added, _('has been marked for add'))
2308 warn(added, _('has been marked for add'))
2309
2309
2310 for f in util.sort(remove + forget):
2310 for f in util.sort(remove + forget):
2311 if ui.verbose or not m.exact(f):
2311 if ui.verbose or not m.exact(f):
2312 ui.status(_('removing %s\n') % m.rel(f))
2312 ui.status(_('removing %s\n') % m.rel(f))
2313
2313
2314 repo.forget(forget)
2314 repo.forget(forget)
2315 repo.remove(remove, unlink=not after)
2315 repo.remove(remove, unlink=not after)
2316
2316
2317 def rename(ui, repo, *pats, **opts):
2317 def rename(ui, repo, *pats, **opts):
2318 """rename files; equivalent of copy + remove
2318 """rename files; equivalent of copy + remove
2319
2319
2320 Mark dest as copies of sources; mark sources for deletion. If
2320 Mark dest as copies of sources; mark sources for deletion. If
2321 dest is a directory, copies are put in that directory. If dest is
2321 dest is a directory, copies are put in that directory. If dest is
2322 a file, there can only be one source.
2322 a file, there can only be one source.
2323
2323
2324 By default, this command copies the contents of files as they
2324 By default, this command copies the contents of files as they
2325 stand in the working directory. If invoked with --after, the
2325 stand in the working directory. If invoked with --after, the
2326 operation is recorded, but no copying is performed.
2326 operation is recorded, but no copying is performed.
2327
2327
2328 This command takes effect in the next commit. To undo a rename
2328 This command takes effect in the next commit. To undo a rename
2329 before that, see hg revert.
2329 before that, see hg revert.
2330 """
2330 """
2331 wlock = repo.wlock(False)
2331 wlock = repo.wlock(False)
2332 try:
2332 try:
2333 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2333 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2334 finally:
2334 finally:
2335 del wlock
2335 del wlock
2336
2336
2337 def resolve(ui, repo, *pats, **opts):
2337 def resolve(ui, repo, *pats, **opts):
2338 """retry file merges from a merge or update
2338 """retry file merges from a merge or update
2339
2339
2340 This command will cleanly retry unresolved file merges using file
2340 This command will cleanly retry unresolved file merges using file
2341 revisions preserved from the last update or merge. To attempt to
2341 revisions preserved from the last update or merge. To attempt to
2342 resolve all unresolved files, use the -a switch.
2342 resolve all unresolved files, use the -a switch.
2343
2343
2344 This command will also allow listing resolved files and manually
2344 This command will also allow listing resolved files and manually
2345 marking and unmarking files as resolved.
2345 marking and unmarking files as resolved.
2346
2346
2347 The codes used to show the status of files are:
2347 The codes used to show the status of files are:
2348 U = unresolved
2348 U = unresolved
2349 R = resolved
2349 R = resolved
2350 """
2350 """
2351
2351
2352 all, mark, unmark, show = [opts.get(o) for o in 'all mark unmark list'.split()]
2352 all, mark, unmark, show = [opts.get(o) for o in 'all mark unmark list'.split()]
2353
2353
2354 if (show and (mark or unmark)) or (mark and unmark):
2354 if (show and (mark or unmark)) or (mark and unmark):
2355 raise util.Abort(_("too many options specified"))
2355 raise util.Abort(_("too many options specified"))
2356 if pats and all:
2356 if pats and all:
2357 raise util.Abort(_("can't specify --all and patterns"))
2357 raise util.Abort(_("can't specify --all and patterns"))
2358 if not (all or pats or show or mark or unmark):
2358 if not (all or pats or show or mark or unmark):
2359 raise util.Abort(_('no files or directories specified; '
2359 raise util.Abort(_('no files or directories specified; '
2360 'use --all to remerge all files'))
2360 'use --all to remerge all files'))
2361
2361
2362 ms = merge_.mergestate(repo)
2362 ms = merge_.mergestate(repo)
2363 m = cmdutil.match(repo, pats, opts)
2363 m = cmdutil.match(repo, pats, opts)
2364
2364
2365 for f in ms:
2365 for f in ms:
2366 if m(f):
2366 if m(f):
2367 if show:
2367 if show:
2368 ui.write("%s %s\n" % (ms[f].upper(), f))
2368 ui.write("%s %s\n" % (ms[f].upper(), f))
2369 elif mark:
2369 elif mark:
2370 ms.mark(f, "r")
2370 ms.mark(f, "r")
2371 elif unmark:
2371 elif unmark:
2372 ms.mark(f, "u")
2372 ms.mark(f, "u")
2373 else:
2373 else:
2374 wctx = repo[None]
2374 wctx = repo[None]
2375 mctx = wctx.parents()[-1]
2375 mctx = wctx.parents()[-1]
2376 ms.resolve(f, wctx, mctx)
2376 ms.resolve(f, wctx, mctx)
2377
2377
2378 def revert(ui, repo, *pats, **opts):
2378 def revert(ui, repo, *pats, **opts):
2379 """restore individual files or dirs to an earlier state
2379 """restore individual files or dirs to an earlier state
2380
2380
2381 (use update -r to check out earlier revisions, revert does not
2381 (use update -r to check out earlier revisions, revert does not
2382 change the working dir parents)
2382 change the working dir parents)
2383
2383
2384 With no revision specified, revert the named files or directories
2384 With no revision specified, revert the named files or directories
2385 to the contents they had in the parent of the working directory.
2385 to the contents they had in the parent of the working directory.
2386 This restores the contents of the affected files to an unmodified
2386 This restores the contents of the affected files to an unmodified
2387 state and unschedules adds, removes, copies, and renames. If the
2387 state and unschedules adds, removes, copies, and renames. If the
2388 working directory has two parents, you must explicitly specify the
2388 working directory has two parents, you must explicitly specify the
2389 revision to revert to.
2389 revision to revert to.
2390
2390
2391 Using the -r option, revert the given files or directories to their
2391 Using the -r option, revert the given files or directories to their
2392 contents as of a specific revision. This can be helpful to "roll
2392 contents as of a specific revision. This can be helpful to "roll
2393 back" some or all of an earlier change.
2393 back" some or all of an earlier change.
2394 See 'hg help dates' for a list of formats valid for -d/--date.
2394 See 'hg help dates' for a list of formats valid for -d/--date.
2395
2395
2396 Revert modifies the working directory. It does not commit any
2396 Revert modifies the working directory. It does not commit any
2397 changes, or change the parent of the working directory. If you
2397 changes, or change the parent of the working directory. If you
2398 revert to a revision other than the parent of the working
2398 revert to a revision other than the parent of the working
2399 directory, the reverted files will thus appear modified
2399 directory, the reverted files will thus appear modified
2400 afterwards.
2400 afterwards.
2401
2401
2402 If a file has been deleted, it is restored. If the executable
2402 If a file has been deleted, it is restored. If the executable
2403 mode of a file was changed, it is reset.
2403 mode of a file was changed, it is reset.
2404
2404
2405 If names are given, all files matching the names are reverted.
2405 If names are given, all files matching the names are reverted.
2406 If no arguments are given, no files are reverted.
2406 If no arguments are given, no files are reverted.
2407
2407
2408 Modified files are saved with a .orig suffix before reverting.
2408 Modified files are saved with a .orig suffix before reverting.
2409 To disable these backups, use --no-backup.
2409 To disable these backups, use --no-backup.
2410 """
2410 """
2411
2411
2412 if opts["date"]:
2412 if opts["date"]:
2413 if opts["rev"]:
2413 if opts["rev"]:
2414 raise util.Abort(_("you can't specify a revision and a date"))
2414 raise util.Abort(_("you can't specify a revision and a date"))
2415 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2415 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2416
2416
2417 if not pats and not opts.get('all'):
2417 if not pats and not opts.get('all'):
2418 raise util.Abort(_('no files or directories specified; '
2418 raise util.Abort(_('no files or directories specified; '
2419 'use --all to revert the whole repo'))
2419 'use --all to revert the whole repo'))
2420
2420
2421 parent, p2 = repo.dirstate.parents()
2421 parent, p2 = repo.dirstate.parents()
2422 if not opts.get('rev') and p2 != nullid:
2422 if not opts.get('rev') and p2 != nullid:
2423 raise util.Abort(_('uncommitted merge - please provide a '
2423 raise util.Abort(_('uncommitted merge - please provide a '
2424 'specific revision'))
2424 'specific revision'))
2425 ctx = repo[opts.get('rev')]
2425 ctx = repo[opts.get('rev')]
2426 node = ctx.node()
2426 node = ctx.node()
2427 mf = ctx.manifest()
2427 mf = ctx.manifest()
2428 if node == parent:
2428 if node == parent:
2429 pmf = mf
2429 pmf = mf
2430 else:
2430 else:
2431 pmf = None
2431 pmf = None
2432
2432
2433 # need all matching names in dirstate and manifest of target rev,
2433 # need all matching names in dirstate and manifest of target rev,
2434 # so have to walk both. do not print errors if files exist in one
2434 # so have to walk both. do not print errors if files exist in one
2435 # but not other.
2435 # but not other.
2436
2436
2437 names = {}
2437 names = {}
2438
2438
2439 wlock = repo.wlock()
2439 wlock = repo.wlock()
2440 try:
2440 try:
2441 # walk dirstate.
2441 # walk dirstate.
2442 files = []
2442 files = []
2443
2443
2444 m = cmdutil.match(repo, pats, opts)
2444 m = cmdutil.match(repo, pats, opts)
2445 m.bad = lambda x,y: False
2445 m.bad = lambda x,y: False
2446 for abs in repo.walk(m):
2446 for abs in repo.walk(m):
2447 names[abs] = m.rel(abs), m.exact(abs)
2447 names[abs] = m.rel(abs), m.exact(abs)
2448
2448
2449 # walk target manifest.
2449 # walk target manifest.
2450
2450
2451 def badfn(path, msg):
2451 def badfn(path, msg):
2452 if path in names:
2452 if path in names:
2453 return False
2453 return False
2454 path_ = path + '/'
2454 path_ = path + '/'
2455 for f in names:
2455 for f in names:
2456 if f.startswith(path_):
2456 if f.startswith(path_):
2457 return False
2457 return False
2458 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2458 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2459 return False
2459 return False
2460
2460
2461 m = cmdutil.match(repo, pats, opts)
2461 m = cmdutil.match(repo, pats, opts)
2462 m.bad = badfn
2462 m.bad = badfn
2463 for abs in repo[node].walk(m):
2463 for abs in repo[node].walk(m):
2464 if abs not in names:
2464 if abs not in names:
2465 names[abs] = m.rel(abs), m.exact(abs)
2465 names[abs] = m.rel(abs), m.exact(abs)
2466
2466
2467 m = cmdutil.matchfiles(repo, names)
2467 m = cmdutil.matchfiles(repo, names)
2468 changes = repo.status(match=m)[:4]
2468 changes = repo.status(match=m)[:4]
2469 modified, added, removed, deleted = map(dict.fromkeys, changes)
2469 modified, added, removed, deleted = map(dict.fromkeys, changes)
2470
2470
2471 # if f is a rename, also revert the source
2471 # if f is a rename, also revert the source
2472 cwd = repo.getcwd()
2472 cwd = repo.getcwd()
2473 for f in added:
2473 for f in added:
2474 src = repo.dirstate.copied(f)
2474 src = repo.dirstate.copied(f)
2475 if src and src not in names and repo.dirstate[src] == 'r':
2475 if src and src not in names and repo.dirstate[src] == 'r':
2476 removed[src] = None
2476 removed[src] = None
2477 names[src] = (repo.pathto(src, cwd), True)
2477 names[src] = (repo.pathto(src, cwd), True)
2478
2478
2479 def removeforget(abs):
2479 def removeforget(abs):
2480 if repo.dirstate[abs] == 'a':
2480 if repo.dirstate[abs] == 'a':
2481 return _('forgetting %s\n')
2481 return _('forgetting %s\n')
2482 return _('removing %s\n')
2482 return _('removing %s\n')
2483
2483
2484 revert = ([], _('reverting %s\n'))
2484 revert = ([], _('reverting %s\n'))
2485 add = ([], _('adding %s\n'))
2485 add = ([], _('adding %s\n'))
2486 remove = ([], removeforget)
2486 remove = ([], removeforget)
2487 undelete = ([], _('undeleting %s\n'))
2487 undelete = ([], _('undeleting %s\n'))
2488
2488
2489 disptable = (
2489 disptable = (
2490 # dispatch table:
2490 # dispatch table:
2491 # file state
2491 # file state
2492 # action if in target manifest
2492 # action if in target manifest
2493 # action if not in target manifest
2493 # action if not in target manifest
2494 # make backup if in target manifest
2494 # make backup if in target manifest
2495 # make backup if not in target manifest
2495 # make backup if not in target manifest
2496 (modified, revert, remove, True, True),
2496 (modified, revert, remove, True, True),
2497 (added, revert, remove, True, False),
2497 (added, revert, remove, True, False),
2498 (removed, undelete, None, False, False),
2498 (removed, undelete, None, False, False),
2499 (deleted, revert, remove, False, False),
2499 (deleted, revert, remove, False, False),
2500 )
2500 )
2501
2501
2502 for abs, (rel, exact) in util.sort(names.items()):
2502 for abs, (rel, exact) in util.sort(names.items()):
2503 mfentry = mf.get(abs)
2503 mfentry = mf.get(abs)
2504 target = repo.wjoin(abs)
2504 target = repo.wjoin(abs)
2505 def handle(xlist, dobackup):
2505 def handle(xlist, dobackup):
2506 xlist[0].append(abs)
2506 xlist[0].append(abs)
2507 if dobackup and not opts.get('no_backup') and util.lexists(target):
2507 if dobackup and not opts.get('no_backup') and util.lexists(target):
2508 bakname = "%s.orig" % rel
2508 bakname = "%s.orig" % rel
2509 ui.note(_('saving current version of %s as %s\n') %
2509 ui.note(_('saving current version of %s as %s\n') %
2510 (rel, bakname))
2510 (rel, bakname))
2511 if not opts.get('dry_run'):
2511 if not opts.get('dry_run'):
2512 util.copyfile(target, bakname)
2512 util.copyfile(target, bakname)
2513 if ui.verbose or not exact:
2513 if ui.verbose or not exact:
2514 msg = xlist[1]
2514 msg = xlist[1]
2515 if not isinstance(msg, basestring):
2515 if not isinstance(msg, basestring):
2516 msg = msg(abs)
2516 msg = msg(abs)
2517 ui.status(msg % rel)
2517 ui.status(msg % rel)
2518 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2518 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2519 if abs not in table: continue
2519 if abs not in table: continue
2520 # file has changed in dirstate
2520 # file has changed in dirstate
2521 if mfentry:
2521 if mfentry:
2522 handle(hitlist, backuphit)
2522 handle(hitlist, backuphit)
2523 elif misslist is not None:
2523 elif misslist is not None:
2524 handle(misslist, backupmiss)
2524 handle(misslist, backupmiss)
2525 break
2525 break
2526 else:
2526 else:
2527 if abs not in repo.dirstate:
2527 if abs not in repo.dirstate:
2528 if mfentry:
2528 if mfentry:
2529 handle(add, True)
2529 handle(add, True)
2530 elif exact:
2530 elif exact:
2531 ui.warn(_('file not managed: %s\n') % rel)
2531 ui.warn(_('file not managed: %s\n') % rel)
2532 continue
2532 continue
2533 # file has not changed in dirstate
2533 # file has not changed in dirstate
2534 if node == parent:
2534 if node == parent:
2535 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2535 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2536 continue
2536 continue
2537 if pmf is None:
2537 if pmf is None:
2538 # only need parent manifest in this unlikely case,
2538 # only need parent manifest in this unlikely case,
2539 # so do not read by default
2539 # so do not read by default
2540 pmf = repo[parent].manifest()
2540 pmf = repo[parent].manifest()
2541 if abs in pmf:
2541 if abs in pmf:
2542 if mfentry:
2542 if mfentry:
2543 # if version of file is same in parent and target
2543 # if version of file is same in parent and target
2544 # manifests, do nothing
2544 # manifests, do nothing
2545 if (pmf[abs] != mfentry or
2545 if (pmf[abs] != mfentry or
2546 pmf.flags(abs) != mf.flags(abs)):
2546 pmf.flags(abs) != mf.flags(abs)):
2547 handle(revert, False)
2547 handle(revert, False)
2548 else:
2548 else:
2549 handle(remove, False)
2549 handle(remove, False)
2550
2550
2551 if not opts.get('dry_run'):
2551 if not opts.get('dry_run'):
2552 def checkout(f):
2552 def checkout(f):
2553 fc = ctx[f]
2553 fc = ctx[f]
2554 repo.wwrite(f, fc.data(), fc.flags())
2554 repo.wwrite(f, fc.data(), fc.flags())
2555
2555
2556 audit_path = util.path_auditor(repo.root)
2556 audit_path = util.path_auditor(repo.root)
2557 for f in remove[0]:
2557 for f in remove[0]:
2558 if repo.dirstate[f] == 'a':
2558 if repo.dirstate[f] == 'a':
2559 repo.dirstate.forget(f)
2559 repo.dirstate.forget(f)
2560 continue
2560 continue
2561 audit_path(f)
2561 audit_path(f)
2562 try:
2562 try:
2563 util.unlink(repo.wjoin(f))
2563 util.unlink(repo.wjoin(f))
2564 except OSError:
2564 except OSError:
2565 pass
2565 pass
2566 repo.dirstate.remove(f)
2566 repo.dirstate.remove(f)
2567
2567
2568 normal = None
2568 normal = None
2569 if node == parent:
2569 if node == parent:
2570 # We're reverting to our parent. If possible, we'd like status
2570 # We're reverting to our parent. If possible, we'd like status
2571 # to report the file as clean. We have to use normallookup for
2571 # to report the file as clean. We have to use normallookup for
2572 # merges to avoid losing information about merged/dirty files.
2572 # merges to avoid losing information about merged/dirty files.
2573 if p2 != nullid:
2573 if p2 != nullid:
2574 normal = repo.dirstate.normallookup
2574 normal = repo.dirstate.normallookup
2575 else:
2575 else:
2576 normal = repo.dirstate.normal
2576 normal = repo.dirstate.normal
2577 for f in revert[0]:
2577 for f in revert[0]:
2578 checkout(f)
2578 checkout(f)
2579 if normal:
2579 if normal:
2580 normal(f)
2580 normal(f)
2581
2581
2582 for f in add[0]:
2582 for f in add[0]:
2583 checkout(f)
2583 checkout(f)
2584 repo.dirstate.add(f)
2584 repo.dirstate.add(f)
2585
2585
2586 normal = repo.dirstate.normallookup
2586 normal = repo.dirstate.normallookup
2587 if node == parent and p2 == nullid:
2587 if node == parent and p2 == nullid:
2588 normal = repo.dirstate.normal
2588 normal = repo.dirstate.normal
2589 for f in undelete[0]:
2589 for f in undelete[0]:
2590 checkout(f)
2590 checkout(f)
2591 normal(f)
2591 normal(f)
2592
2592
2593 finally:
2593 finally:
2594 del wlock
2594 del wlock
2595
2595
2596 def rollback(ui, repo):
2596 def rollback(ui, repo):
2597 """roll back the last transaction
2597 """roll back the last transaction
2598
2598
2599 This command should be used with care. There is only one level of
2599 This command should be used with care. There is only one level of
2600 rollback, and there is no way to undo a rollback. It will also
2600 rollback, and there is no way to undo a rollback. It will also
2601 restore the dirstate at the time of the last transaction, losing
2601 restore the dirstate at the time of the last transaction, losing
2602 any dirstate changes since that time.
2602 any dirstate changes since that time.
2603
2603
2604 Transactions are used to encapsulate the effects of all commands
2604 Transactions are used to encapsulate the effects of all commands
2605 that create new changesets or propagate existing changesets into a
2605 that create new changesets or propagate existing changesets into a
2606 repository. For example, the following commands are transactional,
2606 repository. For example, the following commands are transactional,
2607 and their effects can be rolled back:
2607 and their effects can be rolled back:
2608
2608
2609 commit
2609 commit
2610 import
2610 import
2611 pull
2611 pull
2612 push (with this repository as destination)
2612 push (with this repository as destination)
2613 unbundle
2613 unbundle
2614
2614
2615 This command is not intended for use on public repositories. Once
2615 This command is not intended for use on public repositories. Once
2616 changes are visible for pull by other users, rolling a transaction
2616 changes are visible for pull by other users, rolling a transaction
2617 back locally is ineffective (someone else may already have pulled
2617 back locally is ineffective (someone else may already have pulled
2618 the changes). Furthermore, a race is possible with readers of the
2618 the changes). Furthermore, a race is possible with readers of the
2619 repository; for example an in-progress pull from the repository
2619 repository; for example an in-progress pull from the repository
2620 may fail if a rollback is performed.
2620 may fail if a rollback is performed.
2621 """
2621 """
2622 repo.rollback()
2622 repo.rollback()
2623
2623
2624 def root(ui, repo):
2624 def root(ui, repo):
2625 """print the root (top) of the current working dir
2625 """print the root (top) of the current working dir
2626
2626
2627 Print the root directory of the current repository.
2627 Print the root directory of the current repository.
2628 """
2628 """
2629 ui.write(repo.root + "\n")
2629 ui.write(repo.root + "\n")
2630
2630
2631 def serve(ui, repo, **opts):
2631 def serve(ui, repo, **opts):
2632 """export the repository via HTTP
2632 """export the repository via HTTP
2633
2633
2634 Start a local HTTP repository browser and pull server.
2634 Start a local HTTP repository browser and pull server.
2635
2635
2636 By default, the server logs accesses to stdout and errors to
2636 By default, the server logs accesses to stdout and errors to
2637 stderr. Use the "-A" and "-E" options to log to files.
2637 stderr. Use the "-A" and "-E" options to log to files.
2638 """
2638 """
2639
2639
2640 if opts["stdio"]:
2640 if opts["stdio"]:
2641 if repo is None:
2641 if repo is None:
2642 raise RepoError(_("There is no Mercurial repository here"
2642 raise RepoError(_("There is no Mercurial repository here"
2643 " (.hg not found)"))
2643 " (.hg not found)"))
2644 s = sshserver.sshserver(ui, repo)
2644 s = sshserver.sshserver(ui, repo)
2645 s.serve_forever()
2645 s.serve_forever()
2646
2646
2647 parentui = ui.parentui or ui
2647 parentui = ui.parentui or ui
2648 optlist = ("name templates style address port prefix ipv6"
2648 optlist = ("name templates style address port prefix ipv6"
2649 " accesslog errorlog webdir_conf certificate")
2649 " accesslog errorlog webdir_conf certificate")
2650 for o in optlist.split():
2650 for o in optlist.split():
2651 if opts[o]:
2651 if opts[o]:
2652 parentui.setconfig("web", o, str(opts[o]))
2652 parentui.setconfig("web", o, str(opts[o]))
2653 if (repo is not None) and (repo.ui != parentui):
2653 if (repo is not None) and (repo.ui != parentui):
2654 repo.ui.setconfig("web", o, str(opts[o]))
2654 repo.ui.setconfig("web", o, str(opts[o]))
2655
2655
2656 if repo is None and not ui.config("web", "webdir_conf"):
2656 if repo is None and not ui.config("web", "webdir_conf"):
2657 raise RepoError(_("There is no Mercurial repository here"
2657 raise RepoError(_("There is no Mercurial repository here"
2658 " (.hg not found)"))
2658 " (.hg not found)"))
2659
2659
2660 class service:
2660 class service:
2661 def init(self):
2661 def init(self):
2662 util.set_signal_handler()
2662 util.set_signal_handler()
2663 self.httpd = hgweb.server.create_server(parentui, repo)
2663 self.httpd = hgweb.server.create_server(parentui, repo)
2664
2664
2665 if not ui.verbose: return
2665 if not ui.verbose: return
2666
2666
2667 if self.httpd.prefix:
2667 if self.httpd.prefix:
2668 prefix = self.httpd.prefix.strip('/') + '/'
2668 prefix = self.httpd.prefix.strip('/') + '/'
2669 else:
2669 else:
2670 prefix = ''
2670 prefix = ''
2671
2671
2672 port = ':%d' % self.httpd.port
2672 port = ':%d' % self.httpd.port
2673 if port == ':80':
2673 if port == ':80':
2674 port = ''
2674 port = ''
2675
2675
2676 bindaddr = self.httpd.addr
2676 bindaddr = self.httpd.addr
2677 if bindaddr == '0.0.0.0':
2677 if bindaddr == '0.0.0.0':
2678 bindaddr = '*'
2678 bindaddr = '*'
2679 elif ':' in bindaddr: # IPv6
2679 elif ':' in bindaddr: # IPv6
2680 bindaddr = '[%s]' % bindaddr
2680 bindaddr = '[%s]' % bindaddr
2681
2681
2682 fqaddr = self.httpd.fqaddr
2682 fqaddr = self.httpd.fqaddr
2683 if ':' in fqaddr:
2683 if ':' in fqaddr:
2684 fqaddr = '[%s]' % fqaddr
2684 fqaddr = '[%s]' % fqaddr
2685 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2685 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2686 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2686 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2687
2687
2688 def run(self):
2688 def run(self):
2689 self.httpd.serve_forever()
2689 self.httpd.serve_forever()
2690
2690
2691 service = service()
2691 service = service()
2692
2692
2693 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2693 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2694
2694
2695 def status(ui, repo, *pats, **opts):
2695 def status(ui, repo, *pats, **opts):
2696 """show changed files in the working directory
2696 """show changed files in the working directory
2697
2697
2698 Show status of files in the repository. If names are given, only
2698 Show status of files in the repository. If names are given, only
2699 files that match are shown. Files that are clean or ignored or
2699 files that match are shown. Files that are clean or ignored or
2700 source of a copy/move operation, are not listed unless -c (clean),
2700 source of a copy/move operation, are not listed unless -c (clean),
2701 -i (ignored), -C (copies) or -A is given. Unless options described
2701 -i (ignored), -C (copies) or -A is given. Unless options described
2702 with "show only ..." are given, the options -mardu are used.
2702 with "show only ..." are given, the options -mardu are used.
2703
2703
2704 Option -q/--quiet hides untracked (unknown and ignored) files
2704 Option -q/--quiet hides untracked (unknown and ignored) files
2705 unless explicitly requested with -u/--unknown or -i/-ignored.
2705 unless explicitly requested with -u/--unknown or -i/-ignored.
2706
2706
2707 NOTE: status may appear to disagree with diff if permissions have
2707 NOTE: status may appear to disagree with diff if permissions have
2708 changed or a merge has occurred. The standard diff format does not
2708 changed or a merge has occurred. The standard diff format does not
2709 report permission changes and diff only reports changes relative
2709 report permission changes and diff only reports changes relative
2710 to one merge parent.
2710 to one merge parent.
2711
2711
2712 If one revision is given, it is used as the base revision.
2712 If one revision is given, it is used as the base revision.
2713 If two revisions are given, the difference between them is shown.
2713 If two revisions are given, the difference between them is shown.
2714
2714
2715 The codes used to show the status of files are:
2715 The codes used to show the status of files are:
2716 M = modified
2716 M = modified
2717 A = added
2717 A = added
2718 R = removed
2718 R = removed
2719 C = clean
2719 C = clean
2720 ! = deleted, but still tracked
2720 ! = deleted, but still tracked
2721 ? = not tracked
2721 ? = not tracked
2722 I = ignored
2722 I = ignored
2723 = the previous added file was copied from here
2723 = the previous added file was copied from here
2724 """
2724 """
2725
2725
2726 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2726 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2727 cwd = (pats and repo.getcwd()) or ''
2727 cwd = (pats and repo.getcwd()) or ''
2728 end = opts.get('print0') and '\0' or '\n'
2728 end = opts.get('print0') and '\0' or '\n'
2729 copy = {}
2729 copy = {}
2730 states = 'modified added removed deleted unknown ignored clean'.split()
2730 states = 'modified added removed deleted unknown ignored clean'.split()
2731 show = [k for k in states if opts[k]]
2731 show = [k for k in states if opts[k]]
2732 if opts.get('all'):
2732 if opts.get('all'):
2733 show += ui.quiet and (states[:4] + ['clean']) or states
2733 show += ui.quiet and (states[:4] + ['clean']) or states
2734 if not show:
2734 if not show:
2735 show = ui.quiet and states[:4] or states[:5]
2735 show = ui.quiet and states[:4] or states[:5]
2736
2736
2737 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2737 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
2738 'ignored' in show, 'clean' in show, 'unknown' in show)
2738 'ignored' in show, 'clean' in show, 'unknown' in show)
2739 changestates = zip(states, 'MAR!?IC', stat)
2739 changestates = zip(states, 'MAR!?IC', stat)
2740
2740
2741 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2741 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
2742 ctxn = repo[nullid]
2742 ctxn = repo[nullid]
2743 ctx1 = repo[node1]
2743 ctx1 = repo[node1]
2744 ctx2 = repo[node2]
2744 ctx2 = repo[node2]
2745 added = stat[1]
2745 added = stat[1]
2746 if node2 is None:
2746 if node2 is None:
2747 added = stat[0] + stat[1] # merged?
2747 added = stat[0] + stat[1] # merged?
2748
2748
2749 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2749 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].items():
2750 if k in added:
2750 if k in added:
2751 copy[k] = v
2751 copy[k] = v
2752 elif v in added:
2752 elif v in added:
2753 copy[v] = k
2753 copy[v] = k
2754
2754
2755 for state, char, files in changestates:
2755 for state, char, files in changestates:
2756 if state in show:
2756 if state in show:
2757 format = "%s %%s%s" % (char, end)
2757 format = "%s %%s%s" % (char, end)
2758 if opts.get('no_status'):
2758 if opts.get('no_status'):
2759 format = "%%s%s" % end
2759 format = "%%s%s" % end
2760
2760
2761 for f in files:
2761 for f in files:
2762 ui.write(format % repo.pathto(f, cwd))
2762 ui.write(format % repo.pathto(f, cwd))
2763 if f in copy:
2763 if f in copy:
2764 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2764 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2765
2765
2766 def tag(ui, repo, name1, *names, **opts):
2766 def tag(ui, repo, name1, *names, **opts):
2767 """add one or more tags for the current or given revision
2767 """add one or more tags for the current or given revision
2768
2768
2769 Name a particular revision using <name>.
2769 Name a particular revision using <name>.
2770
2770
2771 Tags are used to name particular revisions of the repository and are
2771 Tags are used to name particular revisions of the repository and are
2772 very useful to compare different revisions, to go back to significant
2772 very useful to compare different revisions, to go back to significant
2773 earlier versions or to mark branch points as releases, etc.
2773 earlier versions or to mark branch points as releases, etc.
2774
2774
2775 If no revision is given, the parent of the working directory is used,
2775 If no revision is given, the parent of the working directory is used,
2776 or tip if no revision is checked out.
2776 or tip if no revision is checked out.
2777
2777
2778 To facilitate version control, distribution, and merging of tags,
2778 To facilitate version control, distribution, and merging of tags,
2779 they are stored as a file named ".hgtags" which is managed
2779 they are stored as a file named ".hgtags" which is managed
2780 similarly to other project files and can be hand-edited if
2780 similarly to other project files and can be hand-edited if
2781 necessary. The file '.hg/localtags' is used for local tags (not
2781 necessary. The file '.hg/localtags' is used for local tags (not
2782 shared among repositories).
2782 shared among repositories).
2783
2783
2784 See 'hg help dates' for a list of formats valid for -d/--date.
2784 See 'hg help dates' for a list of formats valid for -d/--date.
2785 """
2785 """
2786
2786
2787 rev_ = "."
2787 rev_ = "."
2788 names = (name1,) + names
2788 names = (name1,) + names
2789 if len(names) != len(dict.fromkeys(names)):
2789 if len(names) != len(dict.fromkeys(names)):
2790 raise util.Abort(_('tag names must be unique'))
2790 raise util.Abort(_('tag names must be unique'))
2791 for n in names:
2791 for n in names:
2792 if n in ['tip', '.', 'null']:
2792 if n in ['tip', '.', 'null']:
2793 raise util.Abort(_('the name \'%s\' is reserved') % n)
2793 raise util.Abort(_('the name \'%s\' is reserved') % n)
2794 if opts.get('rev') and opts.get('remove'):
2794 if opts.get('rev') and opts.get('remove'):
2795 raise util.Abort(_("--rev and --remove are incompatible"))
2795 raise util.Abort(_("--rev and --remove are incompatible"))
2796 if opts.get('rev'):
2796 if opts.get('rev'):
2797 rev_ = opts['rev']
2797 rev_ = opts['rev']
2798 message = opts.get('message')
2798 message = opts.get('message')
2799 if opts.get('remove'):
2799 if opts.get('remove'):
2800 expectedtype = opts.get('local') and 'local' or 'global'
2800 expectedtype = opts.get('local') and 'local' or 'global'
2801 for n in names:
2801 for n in names:
2802 if not repo.tagtype(n):
2802 if not repo.tagtype(n):
2803 raise util.Abort(_('tag \'%s\' does not exist') % n)
2803 raise util.Abort(_('tag \'%s\' does not exist') % n)
2804 if repo.tagtype(n) != expectedtype:
2804 if repo.tagtype(n) != expectedtype:
2805 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2805 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2806 (n, expectedtype))
2806 (n, expectedtype))
2807 rev_ = nullid
2807 rev_ = nullid
2808 if not message:
2808 if not message:
2809 message = _('Removed tag %s') % ', '.join(names)
2809 message = _('Removed tag %s') % ', '.join(names)
2810 elif not opts.get('force'):
2810 elif not opts.get('force'):
2811 for n in names:
2811 for n in names:
2812 if n in repo.tags():
2812 if n in repo.tags():
2813 raise util.Abort(_('tag \'%s\' already exists '
2813 raise util.Abort(_('tag \'%s\' already exists '
2814 '(use -f to force)') % n)
2814 '(use -f to force)') % n)
2815 if not rev_ and repo.dirstate.parents()[1] != nullid:
2815 if not rev_ and repo.dirstate.parents()[1] != nullid:
2816 raise util.Abort(_('uncommitted merge - please provide a '
2816 raise util.Abort(_('uncommitted merge - please provide a '
2817 'specific revision'))
2817 'specific revision'))
2818 r = repo[rev_].node()
2818 r = repo[rev_].node()
2819
2819
2820 if not message:
2820 if not message:
2821 message = (_('Added tag %s for changeset %s') %
2821 message = (_('Added tag %s for changeset %s') %
2822 (', '.join(names), short(r)))
2822 (', '.join(names), short(r)))
2823
2823
2824 date = opts.get('date')
2824 date = opts.get('date')
2825 if date:
2825 if date:
2826 date = util.parsedate(date)
2826 date = util.parsedate(date)
2827
2827
2828 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2828 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
2829
2829
2830 def tags(ui, repo):
2830 def tags(ui, repo):
2831 """list repository tags
2831 """list repository tags
2832
2832
2833 This lists both regular and local tags. When the -v/--verbose switch
2833 This lists both regular and local tags. When the -v/--verbose switch
2834 is used, a third column "local" is printed for local tags.
2834 is used, a third column "local" is printed for local tags.
2835 """
2835 """
2836
2836
2837 l = repo.tagslist()
2837 l = repo.tagslist()
2838 l.reverse()
2838 l.reverse()
2839 hexfunc = ui.debugflag and hex or short
2839 hexfunc = ui.debugflag and hex or short
2840 tagtype = ""
2840 tagtype = ""
2841
2841
2842 for t, n in l:
2842 for t, n in l:
2843 if ui.quiet:
2843 if ui.quiet:
2844 ui.write("%s\n" % t)
2844 ui.write("%s\n" % t)
2845 continue
2845 continue
2846
2846
2847 try:
2847 try:
2848 hn = hexfunc(n)
2848 hn = hexfunc(n)
2849 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2849 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2850 except revlog.LookupError:
2850 except revlog.LookupError:
2851 r = " ?:%s" % hn
2851 r = " ?:%s" % hn
2852 else:
2852 else:
2853 spaces = " " * (30 - util.locallen(t))
2853 spaces = " " * (30 - util.locallen(t))
2854 if ui.verbose:
2854 if ui.verbose:
2855 if repo.tagtype(t) == 'local':
2855 if repo.tagtype(t) == 'local':
2856 tagtype = " local"
2856 tagtype = " local"
2857 else:
2857 else:
2858 tagtype = ""
2858 tagtype = ""
2859 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2859 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2860
2860
2861 def tip(ui, repo, **opts):
2861 def tip(ui, repo, **opts):
2862 """show the tip revision
2862 """show the tip revision
2863
2863
2864 The tip revision (usually just called the tip) is the most
2864 The tip revision (usually just called the tip) is the most
2865 recently added changeset in the repository, the most recently
2865 recently added changeset in the repository, the most recently
2866 changed head.
2866 changed head.
2867
2867
2868 If you have just made a commit, that commit will be the tip. If
2868 If you have just made a commit, that commit will be the tip. If
2869 you have just pulled changes from another repository, the tip of
2869 you have just pulled changes from another repository, the tip of
2870 that repository becomes the current tip. The "tip" tag is special
2870 that repository becomes the current tip. The "tip" tag is special
2871 and cannot be renamed or assigned to a different changeset.
2871 and cannot be renamed or assigned to a different changeset.
2872 """
2872 """
2873 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
2873 cmdutil.show_changeset(ui, repo, opts).show(repo[len(repo) - 1])
2874
2874
2875 def unbundle(ui, repo, fname1, *fnames, **opts):
2875 def unbundle(ui, repo, fname1, *fnames, **opts):
2876 """apply one or more changegroup files
2876 """apply one or more changegroup files
2877
2877
2878 Apply one or more compressed changegroup files generated by the
2878 Apply one or more compressed changegroup files generated by the
2879 bundle command.
2879 bundle command.
2880 """
2880 """
2881 fnames = (fname1,) + fnames
2881 fnames = (fname1,) + fnames
2882
2882
2883 lock = None
2883 lock = None
2884 try:
2884 try:
2885 lock = repo.lock()
2885 lock = repo.lock()
2886 for fname in fnames:
2886 for fname in fnames:
2887 f = url.open(ui, fname)
2887 f = url.open(ui, fname)
2888 gen = changegroup.readbundle(f, fname)
2888 gen = changegroup.readbundle(f, fname)
2889 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2889 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2890 finally:
2890 finally:
2891 del lock
2891 del lock
2892
2892
2893 return postincoming(ui, repo, modheads, opts.get('update'), None)
2893 return postincoming(ui, repo, modheads, opts.get('update'), None)
2894
2894
2895 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2895 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2896 """update working directory
2896 """update working directory
2897
2897
2898 Update the repository's working directory to the specified revision,
2898 Update the repository's working directory to the specified revision,
2899 or the tip of the current branch if none is specified. Use null as
2899 or the tip of the current branch if none is specified. Use null as
2900 the revision to remove the working copy (like 'hg clone -U').
2900 the revision to remove the working copy (like 'hg clone -U').
2901
2901
2902 When the working dir contains no uncommitted changes, it will be
2902 When the working dir contains no uncommitted changes, it will be
2903 replaced by the state of the requested revision from the repo. When
2903 replaced by the state of the requested revision from the repo. When
2904 the requested revision is on a different branch, the working dir
2904 the requested revision is on a different branch, the working dir
2905 will additionally be switched to that branch.
2905 will additionally be switched to that branch.
2906
2906
2907 When there are uncommitted changes, use option -C to discard them,
2907 When there are uncommitted changes, use option -C to discard them,
2908 forcibly replacing the state of the working dir with the requested
2908 forcibly replacing the state of the working dir with the requested
2909 revision.
2909 revision.
2910
2910
2911 When there are uncommitted changes and option -C is not used, and
2911 When there are uncommitted changes and option -C is not used, and
2912 the parent revision and requested revision are on the same branch,
2912 the parent revision and requested revision are on the same branch,
2913 and one of them is an ancestor of the other, then the new working
2913 and one of them is an ancestor of the other, then the new working
2914 directory will contain the requested revision merged with the
2914 directory will contain the requested revision merged with the
2915 uncommitted changes. Otherwise, the update will fail with a
2915 uncommitted changes. Otherwise, the update will fail with a
2916 suggestion to use 'merge' or 'update -C' instead.
2916 suggestion to use 'merge' or 'update -C' instead.
2917
2917
2918 If you want to update just one file to an older revision, use revert.
2918 If you want to update just one file to an older revision, use revert.
2919
2919
2920 See 'hg help dates' for a list of formats valid for --date.
2920 See 'hg help dates' for a list of formats valid for --date.
2921 """
2921 """
2922 if rev and node:
2922 if rev and node:
2923 raise util.Abort(_("please specify just one revision"))
2923 raise util.Abort(_("please specify just one revision"))
2924
2924
2925 if not rev:
2925 if not rev:
2926 rev = node
2926 rev = node
2927
2927
2928 if date:
2928 if date:
2929 if rev:
2929 if rev:
2930 raise util.Abort(_("you can't specify a revision and a date"))
2930 raise util.Abort(_("you can't specify a revision and a date"))
2931 rev = cmdutil.finddate(ui, repo, date)
2931 rev = cmdutil.finddate(ui, repo, date)
2932
2932
2933 if clean:
2933 if clean:
2934 return hg.clean(repo, rev)
2934 return hg.clean(repo, rev)
2935 else:
2935 else:
2936 return hg.update(repo, rev)
2936 return hg.update(repo, rev)
2937
2937
2938 def verify(ui, repo):
2938 def verify(ui, repo):
2939 """verify the integrity of the repository
2939 """verify the integrity of the repository
2940
2940
2941 Verify the integrity of the current repository.
2941 Verify the integrity of the current repository.
2942
2942
2943 This will perform an extensive check of the repository's
2943 This will perform an extensive check of the repository's
2944 integrity, validating the hashes and checksums of each entry in
2944 integrity, validating the hashes and checksums of each entry in
2945 the changelog, manifest, and tracked files, as well as the
2945 the changelog, manifest, and tracked files, as well as the
2946 integrity of their crosslinks and indices.
2946 integrity of their crosslinks and indices.
2947 """
2947 """
2948 return hg.verify(repo)
2948 return hg.verify(repo)
2949
2949
2950 def version_(ui):
2950 def version_(ui):
2951 """output version and copyright information"""
2951 """output version and copyright information"""
2952 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2952 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2953 % version.get_version())
2953 % version.get_version())
2954 ui.status(_(
2954 ui.status(_(
2955 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2955 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2956 "This is free software; see the source for copying conditions. "
2956 "This is free software; see the source for copying conditions. "
2957 "There is NO\nwarranty; "
2957 "There is NO\nwarranty; "
2958 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2958 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2959 ))
2959 ))
2960
2960
2961 # Command options and aliases are listed here, alphabetically
2961 # Command options and aliases are listed here, alphabetically
2962
2962
2963 globalopts = [
2963 globalopts = [
2964 ('R', 'repository', '',
2964 ('R', 'repository', '',
2965 _('repository root directory or symbolic path name')),
2965 _('repository root directory or symbolic path name')),
2966 ('', 'cwd', '', _('change working directory')),
2966 ('', 'cwd', '', _('change working directory')),
2967 ('y', 'noninteractive', None,
2967 ('y', 'noninteractive', None,
2968 _('do not prompt, assume \'yes\' for any required answers')),
2968 _('do not prompt, assume \'yes\' for any required answers')),
2969 ('q', 'quiet', None, _('suppress output')),
2969 ('q', 'quiet', None, _('suppress output')),
2970 ('v', 'verbose', None, _('enable additional output')),
2970 ('v', 'verbose', None, _('enable additional output')),
2971 ('', 'config', [], _('set/override config option')),
2971 ('', 'config', [], _('set/override config option')),
2972 ('', 'debug', None, _('enable debugging output')),
2972 ('', 'debug', None, _('enable debugging output')),
2973 ('', 'debugger', None, _('start debugger')),
2973 ('', 'debugger', None, _('start debugger')),
2974 ('', 'encoding', util._encoding, _('set the charset encoding')),
2974 ('', 'encoding', util._encoding, _('set the charset encoding')),
2975 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2975 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2976 ('', 'lsprof', None, _('print improved command execution profile')),
2976 ('', 'lsprof', None, _('print improved command execution profile')),
2977 ('', 'traceback', None, _('print traceback on exception')),
2977 ('', 'traceback', None, _('print traceback on exception')),
2978 ('', 'time', None, _('time how long the command takes')),
2978 ('', 'time', None, _('time how long the command takes')),
2979 ('', 'profile', None, _('print command execution profile')),
2979 ('', 'profile', None, _('print command execution profile')),
2980 ('', 'version', None, _('output version information and exit')),
2980 ('', 'version', None, _('output version information and exit')),
2981 ('h', 'help', None, _('display help and exit')),
2981 ('h', 'help', None, _('display help and exit')),
2982 ]
2982 ]
2983
2983
2984 dryrunopts = [('n', 'dry-run', None,
2984 dryrunopts = [('n', 'dry-run', None,
2985 _('do not perform actions, just print output'))]
2985 _('do not perform actions, just print output'))]
2986
2986
2987 remoteopts = [
2987 remoteopts = [
2988 ('e', 'ssh', '', _('specify ssh command to use')),
2988 ('e', 'ssh', '', _('specify ssh command to use')),
2989 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2989 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2990 ]
2990 ]
2991
2991
2992 walkopts = [
2992 walkopts = [
2993 ('I', 'include', [], _('include names matching the given patterns')),
2993 ('I', 'include', [], _('include names matching the given patterns')),
2994 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2994 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2995 ]
2995 ]
2996
2996
2997 commitopts = [
2997 commitopts = [
2998 ('m', 'message', '', _('use <text> as commit message')),
2998 ('m', 'message', '', _('use <text> as commit message')),
2999 ('l', 'logfile', '', _('read commit message from <file>')),
2999 ('l', 'logfile', '', _('read commit message from <file>')),
3000 ]
3000 ]
3001
3001
3002 commitopts2 = [
3002 commitopts2 = [
3003 ('d', 'date', '', _('record datecode as commit date')),
3003 ('d', 'date', '', _('record datecode as commit date')),
3004 ('u', 'user', '', _('record user as committer')),
3004 ('u', 'user', '', _('record user as committer')),
3005 ]
3005 ]
3006
3006
3007 templateopts = [
3007 templateopts = [
3008 ('', 'style', '', _('display using template map file')),
3008 ('', 'style', '', _('display using template map file')),
3009 ('', 'template', '', _('display with template')),
3009 ('', 'template', '', _('display with template')),
3010 ]
3010 ]
3011
3011
3012 logopts = [
3012 logopts = [
3013 ('p', 'patch', None, _('show patch')),
3013 ('p', 'patch', None, _('show patch')),
3014 ('l', 'limit', '', _('limit number of changes displayed')),
3014 ('l', 'limit', '', _('limit number of changes displayed')),
3015 ('M', 'no-merges', None, _('do not show merges')),
3015 ('M', 'no-merges', None, _('do not show merges')),
3016 ] + templateopts
3016 ] + templateopts
3017
3017
3018 diffopts = [
3018 diffopts = [
3019 ('a', 'text', None, _('treat all files as text')),
3019 ('a', 'text', None, _('treat all files as text')),
3020 ('g', 'git', None, _('use git extended diff format')),
3020 ('g', 'git', None, _('use git extended diff format')),
3021 ('', 'nodates', None, _("don't include dates in diff headers"))
3021 ('', 'nodates', None, _("don't include dates in diff headers"))
3022 ]
3022 ]
3023
3023
3024 diffopts2 = [
3024 diffopts2 = [
3025 ('p', 'show-function', None, _('show which function each change is in')),
3025 ('p', 'show-function', None, _('show which function each change is in')),
3026 ('w', 'ignore-all-space', None,
3026 ('w', 'ignore-all-space', None,
3027 _('ignore white space when comparing lines')),
3027 _('ignore white space when comparing lines')),
3028 ('b', 'ignore-space-change', None,
3028 ('b', 'ignore-space-change', None,
3029 _('ignore changes in the amount of white space')),
3029 _('ignore changes in the amount of white space')),
3030 ('B', 'ignore-blank-lines', None,
3030 ('B', 'ignore-blank-lines', None,
3031 _('ignore changes whose lines are all blank')),
3031 _('ignore changes whose lines are all blank')),
3032 ('U', 'unified', '', _('number of lines of context to show'))
3032 ('U', 'unified', '', _('number of lines of context to show'))
3033 ]
3033 ]
3034
3034
3035 similarityopts = [
3035 similarityopts = [
3036 ('s', 'similarity', '',
3036 ('s', 'similarity', '',
3037 _('guess renamed files by similarity (0<=s<=100)'))
3037 _('guess renamed files by similarity (0<=s<=100)'))
3038 ]
3038 ]
3039
3039
3040 table = {
3040 table = {
3041 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3041 "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
3042 "addremove":
3042 "addremove":
3043 (addremove, similarityopts + walkopts + dryrunopts,
3043 (addremove, similarityopts + walkopts + dryrunopts,
3044 _('[OPTION]... [FILE]...')),
3044 _('[OPTION]... [FILE]...')),
3045 "^annotate|blame":
3045 "^annotate|blame":
3046 (annotate,
3046 (annotate,
3047 [('r', 'rev', '', _('annotate the specified revision')),
3047 [('r', 'rev', '', _('annotate the specified revision')),
3048 ('f', 'follow', None, _('follow file copies and renames')),
3048 ('f', 'follow', None, _('follow file copies and renames')),
3049 ('a', 'text', None, _('treat all files as text')),
3049 ('a', 'text', None, _('treat all files as text')),
3050 ('u', 'user', None, _('list the author (long with -v)')),
3050 ('u', 'user', None, _('list the author (long with -v)')),
3051 ('d', 'date', None, _('list the date (short with -q)')),
3051 ('d', 'date', None, _('list the date (short with -q)')),
3052 ('n', 'number', None, _('list the revision number (default)')),
3052 ('n', 'number', None, _('list the revision number (default)')),
3053 ('c', 'changeset', None, _('list the changeset')),
3053 ('c', 'changeset', None, _('list the changeset')),
3054 ('l', 'line-number', None,
3054 ('l', 'line-number', None,
3055 _('show line number at the first appearance'))
3055 _('show line number at the first appearance'))
3056 ] + walkopts,
3056 ] + walkopts,
3057 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3057 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
3058 "archive":
3058 "archive":
3059 (archive,
3059 (archive,
3060 [('', 'no-decode', None, _('do not pass files through decoders')),
3060 [('', 'no-decode', None, _('do not pass files through decoders')),
3061 ('p', 'prefix', '', _('directory prefix for files in archive')),
3061 ('p', 'prefix', '', _('directory prefix for files in archive')),
3062 ('r', 'rev', '', _('revision to distribute')),
3062 ('r', 'rev', '', _('revision to distribute')),
3063 ('t', 'type', '', _('type of distribution to create')),
3063 ('t', 'type', '', _('type of distribution to create')),
3064 ] + walkopts,
3064 ] + walkopts,
3065 _('[OPTION]... DEST')),
3065 _('[OPTION]... DEST')),
3066 "backout":
3066 "backout":
3067 (backout,
3067 (backout,
3068 [('', 'merge', None,
3068 [('', 'merge', None,
3069 _('merge with old dirstate parent after backout')),
3069 _('merge with old dirstate parent after backout')),
3070 ('', 'parent', '', _('parent to choose when backing out merge')),
3070 ('', 'parent', '', _('parent to choose when backing out merge')),
3071 ('r', 'rev', '', _('revision to backout')),
3071 ('r', 'rev', '', _('revision to backout')),
3072 ] + walkopts + commitopts + commitopts2,
3072 ] + walkopts + commitopts + commitopts2,
3073 _('[OPTION]... [-r] REV')),
3073 _('[OPTION]... [-r] REV')),
3074 "bisect":
3074 "bisect":
3075 (bisect,
3075 (bisect,
3076 [('r', 'reset', False, _('reset bisect state')),
3076 [('r', 'reset', False, _('reset bisect state')),
3077 ('g', 'good', False, _('mark changeset good')),
3077 ('g', 'good', False, _('mark changeset good')),
3078 ('b', 'bad', False, _('mark changeset bad')),
3078 ('b', 'bad', False, _('mark changeset bad')),
3079 ('s', 'skip', False, _('skip testing changeset')),
3079 ('s', 'skip', False, _('skip testing changeset')),
3080 ('c', 'command', '', _('Use command to check changeset state')),
3080 ('c', 'command', '', _('use command to check changeset state')),
3081 ('U', 'noupdate', False, _('do not update to target'))],
3081 ('U', 'noupdate', False, _('do not update to target'))],
3082 _("[-gbsr] [-c CMD] [REV]")),
3082 _("[-gbsr] [-c CMD] [REV]")),
3083 "branch":
3083 "branch":
3084 (branch,
3084 (branch,
3085 [('f', 'force', None,
3085 [('f', 'force', None,
3086 _('set branch name even if it shadows an existing branch')),
3086 _('set branch name even if it shadows an existing branch')),
3087 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3087 ('C', 'clean', None, _('reset branch name to parent branch name'))],
3088 _('[-fC] [NAME]')),
3088 _('[-fC] [NAME]')),
3089 "branches":
3089 "branches":
3090 (branches,
3090 (branches,
3091 [('a', 'active', False,
3091 [('a', 'active', False,
3092 _('show only branches that have unmerged heads'))],
3092 _('show only branches that have unmerged heads'))],
3093 _('[-a]')),
3093 _('[-a]')),
3094 "bundle":
3094 "bundle":
3095 (bundle,
3095 (bundle,
3096 [('f', 'force', None,
3096 [('f', 'force', None,
3097 _('run even when remote repository is unrelated')),
3097 _('run even when remote repository is unrelated')),
3098 ('r', 'rev', [],
3098 ('r', 'rev', [],
3099 _('a changeset up to which you would like to bundle')),
3099 _('a changeset up to which you would like to bundle')),
3100 ('', 'base', [],
3100 ('', 'base', [],
3101 _('a base changeset to specify instead of a destination')),
3101 _('a base changeset to specify instead of a destination')),
3102 ('a', 'all', None, _('bundle all changesets in the repository')),
3102 ('a', 'all', None, _('bundle all changesets in the repository')),
3103 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3103 ('t', 'type', 'bzip2', _('bundle compression type to use')),
3104 ] + remoteopts,
3104 ] + remoteopts,
3105 _('[-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3105 _('[-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3106 "cat":
3106 "cat":
3107 (cat,
3107 (cat,
3108 [('o', 'output', '', _('print output to file with formatted name')),
3108 [('o', 'output', '', _('print output to file with formatted name')),
3109 ('r', 'rev', '', _('print the given revision')),
3109 ('r', 'rev', '', _('print the given revision')),
3110 ('', 'decode', None, _('apply any matching decode filter')),
3110 ('', 'decode', None, _('apply any matching decode filter')),
3111 ] + walkopts,
3111 ] + walkopts,
3112 _('[OPTION]... FILE...')),
3112 _('[OPTION]... FILE...')),
3113 "^clone":
3113 "^clone":
3114 (clone,
3114 (clone,
3115 [('U', 'noupdate', None,
3115 [('U', 'noupdate', None,
3116 _('the clone will only contain a repository (no working copy)')),
3116 _('the clone will only contain a repository (no working copy)')),
3117 ('r', 'rev', [],
3117 ('r', 'rev', [],
3118 _('a changeset you would like to have after cloning')),
3118 _('a changeset you would like to have after cloning')),
3119 ('', 'pull', None, _('use pull protocol to copy metadata')),
3119 ('', 'pull', None, _('use pull protocol to copy metadata')),
3120 ('', 'uncompressed', None,
3120 ('', 'uncompressed', None,
3121 _('use uncompressed transfer (fast over LAN)')),
3121 _('use uncompressed transfer (fast over LAN)')),
3122 ] + remoteopts,
3122 ] + remoteopts,
3123 _('[OPTION]... SOURCE [DEST]')),
3123 _('[OPTION]... SOURCE [DEST]')),
3124 "^commit|ci":
3124 "^commit|ci":
3125 (commit,
3125 (commit,
3126 [('A', 'addremove', None,
3126 [('A', 'addremove', None,
3127 _('mark new/missing files as added/removed before committing')),
3127 _('mark new/missing files as added/removed before committing')),
3128 ] + walkopts + commitopts + commitopts2,
3128 ] + walkopts + commitopts + commitopts2,
3129 _('[OPTION]... [FILE]...')),
3129 _('[OPTION]... [FILE]...')),
3130 "copy|cp":
3130 "copy|cp":
3131 (copy,
3131 (copy,
3132 [('A', 'after', None, _('record a copy that has already occurred')),
3132 [('A', 'after', None, _('record a copy that has already occurred')),
3133 ('f', 'force', None,
3133 ('f', 'force', None,
3134 _('forcibly copy over an existing managed file')),
3134 _('forcibly copy over an existing managed file')),
3135 ] + walkopts + dryrunopts,
3135 ] + walkopts + dryrunopts,
3136 _('[OPTION]... [SOURCE]... DEST')),
3136 _('[OPTION]... [SOURCE]... DEST')),
3137 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3137 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
3138 "debugcheckstate": (debugcheckstate, []),
3138 "debugcheckstate": (debugcheckstate, []),
3139 "debugcomplete":
3139 "debugcomplete":
3140 (debugcomplete,
3140 (debugcomplete,
3141 [('o', 'options', None, _('show the command options'))],
3141 [('o', 'options', None, _('show the command options'))],
3142 _('[-o] CMD')),
3142 _('[-o] CMD')),
3143 "debugdate":
3143 "debugdate":
3144 (debugdate,
3144 (debugdate,
3145 [('e', 'extended', None, _('try extended date formats'))],
3145 [('e', 'extended', None, _('try extended date formats'))],
3146 _('[-e] DATE [RANGE]')),
3146 _('[-e] DATE [RANGE]')),
3147 "debugdata": (debugdata, [], _('FILE REV')),
3147 "debugdata": (debugdata, [], _('FILE REV')),
3148 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3148 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
3149 "debugindex": (debugindex, [], _('FILE')),
3149 "debugindex": (debugindex, [], _('FILE')),
3150 "debugindexdot": (debugindexdot, [], _('FILE')),
3150 "debugindexdot": (debugindexdot, [], _('FILE')),
3151 "debuginstall": (debuginstall, []),
3151 "debuginstall": (debuginstall, []),
3152 "debugrawcommit|rawcommit":
3152 "debugrawcommit|rawcommit":
3153 (rawcommit,
3153 (rawcommit,
3154 [('p', 'parent', [], _('parent')),
3154 [('p', 'parent', [], _('parent')),
3155 ('F', 'files', '', _('file list'))
3155 ('F', 'files', '', _('file list'))
3156 ] + commitopts + commitopts2,
3156 ] + commitopts + commitopts2,
3157 _('[OPTION]... [FILE]...')),
3157 _('[OPTION]... [FILE]...')),
3158 "debugrebuildstate":
3158 "debugrebuildstate":
3159 (debugrebuildstate,
3159 (debugrebuildstate,
3160 [('r', 'rev', '', _('revision to rebuild to'))],
3160 [('r', 'rev', '', _('revision to rebuild to'))],
3161 _('[-r REV] [REV]')),
3161 _('[-r REV] [REV]')),
3162 "debugrename":
3162 "debugrename":
3163 (debugrename,
3163 (debugrename,
3164 [('r', 'rev', '', _('revision to debug'))],
3164 [('r', 'rev', '', _('revision to debug'))],
3165 _('[-r REV] FILE')),
3165 _('[-r REV] FILE')),
3166 "debugsetparents":
3166 "debugsetparents":
3167 (debugsetparents, [], _('REV1 [REV2]')),
3167 (debugsetparents, [], _('REV1 [REV2]')),
3168 "debugstate":
3168 "debugstate":
3169 (debugstate,
3169 (debugstate,
3170 [('', 'nodates', None, _('do not display the saved mtime'))],
3170 [('', 'nodates', None, _('do not display the saved mtime'))],
3171 _('[OPTION]...')),
3171 _('[OPTION]...')),
3172 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3172 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
3173 "^diff":
3173 "^diff":
3174 (diff,
3174 (diff,
3175 [('r', 'rev', [], _('revision'))
3175 [('r', 'rev', [], _('revision'))
3176 ] + diffopts + diffopts2 + walkopts,
3176 ] + diffopts + diffopts2 + walkopts,
3177 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3177 _('[OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3178 "^export":
3178 "^export":
3179 (export,
3179 (export,
3180 [('o', 'output', '', _('print output to file with formatted name')),
3180 [('o', 'output', '', _('print output to file with formatted name')),
3181 ('', 'switch-parent', None, _('diff against the second parent'))
3181 ('', 'switch-parent', None, _('diff against the second parent'))
3182 ] + diffopts,
3182 ] + diffopts,
3183 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3183 _('[OPTION]... [-o OUTFILESPEC] REV...')),
3184 "grep":
3184 "grep":
3185 (grep,
3185 (grep,
3186 [('0', 'print0', None, _('end fields with NUL')),
3186 [('0', 'print0', None, _('end fields with NUL')),
3187 ('', 'all', None, _('print all revisions that match')),
3187 ('', 'all', None, _('print all revisions that match')),
3188 ('f', 'follow', None,
3188 ('f', 'follow', None,
3189 _('follow changeset history, or file history across copies and renames')),
3189 _('follow changeset history, or file history across copies and renames')),
3190 ('i', 'ignore-case', None, _('ignore case when matching')),
3190 ('i', 'ignore-case', None, _('ignore case when matching')),
3191 ('l', 'files-with-matches', None,
3191 ('l', 'files-with-matches', None,
3192 _('print only filenames and revs that match')),
3192 _('print only filenames and revs that match')),
3193 ('n', 'line-number', None, _('print matching line numbers')),
3193 ('n', 'line-number', None, _('print matching line numbers')),
3194 ('r', 'rev', [], _('search in given revision range')),
3194 ('r', 'rev', [], _('search in given revision range')),
3195 ('u', 'user', None, _('list the author (long with -v)')),
3195 ('u', 'user', None, _('list the author (long with -v)')),
3196 ('d', 'date', None, _('list the date (short with -q)')),
3196 ('d', 'date', None, _('list the date (short with -q)')),
3197 ] + walkopts,
3197 ] + walkopts,
3198 _('[OPTION]... PATTERN [FILE]...')),
3198 _('[OPTION]... PATTERN [FILE]...')),
3199 "heads":
3199 "heads":
3200 (heads,
3200 (heads,
3201 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3201 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3202 ] + templateopts,
3202 ] + templateopts,
3203 _('[-r REV] [REV]...')),
3203 _('[-r REV] [REV]...')),
3204 "help": (help_, [], _('[TOPIC]')),
3204 "help": (help_, [], _('[TOPIC]')),
3205 "identify|id":
3205 "identify|id":
3206 (identify,
3206 (identify,
3207 [('r', 'rev', '', _('identify the specified rev')),
3207 [('r', 'rev', '', _('identify the specified rev')),
3208 ('n', 'num', None, _('show local revision number')),
3208 ('n', 'num', None, _('show local revision number')),
3209 ('i', 'id', None, _('show global revision id')),
3209 ('i', 'id', None, _('show global revision id')),
3210 ('b', 'branch', None, _('show branch')),
3210 ('b', 'branch', None, _('show branch')),
3211 ('t', 'tags', None, _('show tags'))],
3211 ('t', 'tags', None, _('show tags'))],
3212 _('[-nibt] [-r REV] [SOURCE]')),
3212 _('[-nibt] [-r REV] [SOURCE]')),
3213 "import|patch":
3213 "import|patch":
3214 (import_,
3214 (import_,
3215 [('p', 'strip', 1,
3215 [('p', 'strip', 1,
3216 _('directory strip option for patch. This has the same\n'
3216 _('directory strip option for patch. This has the same\n'
3217 'meaning as the corresponding patch option')),
3217 'meaning as the corresponding patch option')),
3218 ('b', 'base', '', _('base path')),
3218 ('b', 'base', '', _('base path')),
3219 ('f', 'force', None,
3219 ('f', 'force', None,
3220 _('skip check for outstanding uncommitted changes')),
3220 _('skip check for outstanding uncommitted changes')),
3221 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3221 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3222 ('', 'exact', None,
3222 ('', 'exact', None,
3223 _('apply patch to the nodes from which it was generated')),
3223 _('apply patch to the nodes from which it was generated')),
3224 ('', 'import-branch', None,
3224 ('', 'import-branch', None,
3225 _('Use any branch information in patch (implied by --exact)'))] +
3225 _('Use any branch information in patch (implied by --exact)'))] +
3226 commitopts + commitopts2 + similarityopts,
3226 commitopts + commitopts2 + similarityopts,
3227 _('[OPTION]... PATCH...')),
3227 _('[OPTION]... PATCH...')),
3228 "incoming|in":
3228 "incoming|in":
3229 (incoming,
3229 (incoming,
3230 [('f', 'force', None,
3230 [('f', 'force', None,
3231 _('run even when remote repository is unrelated')),
3231 _('run even when remote repository is unrelated')),
3232 ('n', 'newest-first', None, _('show newest record first')),
3232 ('n', 'newest-first', None, _('show newest record first')),
3233 ('', 'bundle', '', _('file to store the bundles into')),
3233 ('', 'bundle', '', _('file to store the bundles into')),
3234 ('r', 'rev', [],
3234 ('r', 'rev', [],
3235 _('a specific revision up to which you would like to pull')),
3235 _('a specific revision up to which you would like to pull')),
3236 ] + logopts + remoteopts,
3236 ] + logopts + remoteopts,
3237 _('[-p] [-n] [-M] [-f] [-r REV]...'
3237 _('[-p] [-n] [-M] [-f] [-r REV]...'
3238 ' [--bundle FILENAME] [SOURCE]')),
3238 ' [--bundle FILENAME] [SOURCE]')),
3239 "^init":
3239 "^init":
3240 (init,
3240 (init,
3241 remoteopts,
3241 remoteopts,
3242 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3242 _('[-e CMD] [--remotecmd CMD] [DEST]')),
3243 "locate":
3243 "locate":
3244 (locate,
3244 (locate,
3245 [('r', 'rev', '', _('search the repository as it stood at rev')),
3245 [('r', 'rev', '', _('search the repository as it stood at rev')),
3246 ('0', 'print0', None,
3246 ('0', 'print0', None,
3247 _('end filenames with NUL, for use with xargs')),
3247 _('end filenames with NUL, for use with xargs')),
3248 ('f', 'fullpath', None,
3248 ('f', 'fullpath', None,
3249 _('print complete paths from the filesystem root')),
3249 _('print complete paths from the filesystem root')),
3250 ] + walkopts,
3250 ] + walkopts,
3251 _('[OPTION]... [PATTERN]...')),
3251 _('[OPTION]... [PATTERN]...')),
3252 "^log|history":
3252 "^log|history":
3253 (log,
3253 (log,
3254 [('f', 'follow', None,
3254 [('f', 'follow', None,
3255 _('follow changeset history, or file history across copies and renames')),
3255 _('follow changeset history, or file history across copies and renames')),
3256 ('', 'follow-first', None,
3256 ('', 'follow-first', None,
3257 _('only follow the first parent of merge changesets')),
3257 _('only follow the first parent of merge changesets')),
3258 ('d', 'date', '', _('show revs matching date spec')),
3258 ('d', 'date', '', _('show revs matching date spec')),
3259 ('C', 'copies', None, _('show copied files')),
3259 ('C', 'copies', None, _('show copied files')),
3260 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3260 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3261 ('r', 'rev', [], _('show the specified revision or range')),
3261 ('r', 'rev', [], _('show the specified revision or range')),
3262 ('', 'removed', None, _('include revs where files were removed')),
3262 ('', 'removed', None, _('include revs where files were removed')),
3263 ('m', 'only-merges', None, _('show only merges')),
3263 ('m', 'only-merges', None, _('show only merges')),
3264 ('u', 'user', [], _('revs committed by user')),
3264 ('u', 'user', [], _('revs committed by user')),
3265 ('b', 'only-branch', [],
3265 ('b', 'only-branch', [],
3266 _('show only changesets within the given named branch')),
3266 _('show only changesets within the given named branch')),
3267 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3267 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3268 ] + logopts + walkopts,
3268 ] + logopts + walkopts,
3269 _('[OPTION]... [FILE]')),
3269 _('[OPTION]... [FILE]')),
3270 "manifest":
3270 "manifest":
3271 (manifest,
3271 (manifest,
3272 [('r', 'rev', '', _('revision to display'))],
3272 [('r', 'rev', '', _('revision to display'))],
3273 _('[-r REV]')),
3273 _('[-r REV]')),
3274 "^merge":
3274 "^merge":
3275 (merge,
3275 (merge,
3276 [('f', 'force', None, _('force a merge with outstanding changes')),
3276 [('f', 'force', None, _('force a merge with outstanding changes')),
3277 ('r', 'rev', '', _('revision to merge')),
3277 ('r', 'rev', '', _('revision to merge')),
3278 ],
3278 ],
3279 _('[-f] [[-r] REV]')),
3279 _('[-f] [[-r] REV]')),
3280 "outgoing|out":
3280 "outgoing|out":
3281 (outgoing,
3281 (outgoing,
3282 [('f', 'force', None,
3282 [('f', 'force', None,
3283 _('run even when remote repository is unrelated')),
3283 _('run even when remote repository is unrelated')),
3284 ('r', 'rev', [],
3284 ('r', 'rev', [],
3285 _('a specific revision up to which you would like to push')),
3285 _('a specific revision up to which you would like to push')),
3286 ('n', 'newest-first', None, _('show newest record first')),
3286 ('n', 'newest-first', None, _('show newest record first')),
3287 ] + logopts + remoteopts,
3287 ] + logopts + remoteopts,
3288 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3288 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3289 "^parents":
3289 "^parents":
3290 (parents,
3290 (parents,
3291 [('r', 'rev', '', _('show parents from the specified rev')),
3291 [('r', 'rev', '', _('show parents from the specified rev')),
3292 ] + templateopts,
3292 ] + templateopts,
3293 _('hg parents [-r REV] [FILE]')),
3293 _('hg parents [-r REV] [FILE]')),
3294 "paths": (paths, [], _('[NAME]')),
3294 "paths": (paths, [], _('[NAME]')),
3295 "^pull":
3295 "^pull":
3296 (pull,
3296 (pull,
3297 [('u', 'update', None,
3297 [('u', 'update', None,
3298 _('update to new tip if changesets were pulled')),
3298 _('update to new tip if changesets were pulled')),
3299 ('f', 'force', None,
3299 ('f', 'force', None,
3300 _('run even when remote repository is unrelated')),
3300 _('run even when remote repository is unrelated')),
3301 ('r', 'rev', [],
3301 ('r', 'rev', [],
3302 _('a specific revision up to which you would like to pull')),
3302 _('a specific revision up to which you would like to pull')),
3303 ] + remoteopts,
3303 ] + remoteopts,
3304 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3304 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3305 "^push":
3305 "^push":
3306 (push,
3306 (push,
3307 [('f', 'force', None, _('force push')),
3307 [('f', 'force', None, _('force push')),
3308 ('r', 'rev', [],
3308 ('r', 'rev', [],
3309 _('a specific revision up to which you would like to push')),
3309 _('a specific revision up to which you would like to push')),
3310 ] + remoteopts,
3310 ] + remoteopts,
3311 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3311 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3312 "recover": (recover, []),
3312 "recover": (recover, []),
3313 "^remove|rm":
3313 "^remove|rm":
3314 (remove,
3314 (remove,
3315 [('A', 'after', None, _('record delete for missing files')),
3315 [('A', 'after', None, _('record delete for missing files')),
3316 ('f', 'force', None,
3316 ('f', 'force', None,
3317 _('remove (and delete) file even if added or modified')),
3317 _('remove (and delete) file even if added or modified')),
3318 ] + walkopts,
3318 ] + walkopts,
3319 _('[OPTION]... FILE...')),
3319 _('[OPTION]... FILE...')),
3320 "rename|mv":
3320 "rename|mv":
3321 (rename,
3321 (rename,
3322 [('A', 'after', None, _('record a rename that has already occurred')),
3322 [('A', 'after', None, _('record a rename that has already occurred')),
3323 ('f', 'force', None,
3323 ('f', 'force', None,
3324 _('forcibly copy over an existing managed file')),
3324 _('forcibly copy over an existing managed file')),
3325 ] + walkopts + dryrunopts,
3325 ] + walkopts + dryrunopts,
3326 _('[OPTION]... SOURCE... DEST')),
3326 _('[OPTION]... SOURCE... DEST')),
3327 "resolve":
3327 "resolve":
3328 (resolve,
3328 (resolve,
3329 [('a', 'all', None, _('remerge all unresolved files')),
3329 [('a', 'all', None, _('remerge all unresolved files')),
3330 ('l', 'list', None, _('list state of files needing merge')),
3330 ('l', 'list', None, _('list state of files needing merge')),
3331 ('m', 'mark', None, _('mark files as resolved')),
3331 ('m', 'mark', None, _('mark files as resolved')),
3332 ('u', 'unmark', None, _('unmark files as resolved'))],
3332 ('u', 'unmark', None, _('unmark files as resolved'))],
3333 _('[OPTION]... [FILE]...')),
3333 _('[OPTION]... [FILE]...')),
3334 "revert":
3334 "revert":
3335 (revert,
3335 (revert,
3336 [('a', 'all', None, _('revert all changes when no arguments given')),
3336 [('a', 'all', None, _('revert all changes when no arguments given')),
3337 ('d', 'date', '', _('tipmost revision matching date')),
3337 ('d', 'date', '', _('tipmost revision matching date')),
3338 ('r', 'rev', '', _('revision to revert to')),
3338 ('r', 'rev', '', _('revision to revert to')),
3339 ('', 'no-backup', None, _('do not save backup copies of files')),
3339 ('', 'no-backup', None, _('do not save backup copies of files')),
3340 ] + walkopts + dryrunopts,
3340 ] + walkopts + dryrunopts,
3341 _('[OPTION]... [-r REV] [NAME]...')),
3341 _('[OPTION]... [-r REV] [NAME]...')),
3342 "rollback": (rollback, []),
3342 "rollback": (rollback, []),
3343 "root": (root, []),
3343 "root": (root, []),
3344 "^serve":
3344 "^serve":
3345 (serve,
3345 (serve,
3346 [('A', 'accesslog', '', _('name of access log file to write to')),
3346 [('A', 'accesslog', '', _('name of access log file to write to')),
3347 ('d', 'daemon', None, _('run server in background')),
3347 ('d', 'daemon', None, _('run server in background')),
3348 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3348 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3349 ('E', 'errorlog', '', _('name of error log file to write to')),
3349 ('E', 'errorlog', '', _('name of error log file to write to')),
3350 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3350 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3351 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3351 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3352 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3352 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3353 ('n', 'name', '',
3353 ('n', 'name', '',
3354 _('name to show in web pages (default: working dir)')),
3354 _('name to show in web pages (default: working dir)')),
3355 ('', 'webdir-conf', '', _('name of the webdir config file'
3355 ('', 'webdir-conf', '', _('name of the webdir config file'
3356 ' (serve more than one repo)')),
3356 ' (serve more than one repo)')),
3357 ('', 'pid-file', '', _('name of file to write process ID to')),
3357 ('', 'pid-file', '', _('name of file to write process ID to')),
3358 ('', 'stdio', None, _('for remote clients')),
3358 ('', 'stdio', None, _('for remote clients')),
3359 ('t', 'templates', '', _('web templates to use')),
3359 ('t', 'templates', '', _('web templates to use')),
3360 ('', 'style', '', _('template style to use')),
3360 ('', 'style', '', _('template style to use')),
3361 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3361 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3362 ('', 'certificate', '', _('SSL certificate file'))],
3362 ('', 'certificate', '', _('SSL certificate file'))],
3363 _('[OPTION]...')),
3363 _('[OPTION]...')),
3364 "showconfig|debugconfig":
3364 "showconfig|debugconfig":
3365 (showconfig,
3365 (showconfig,
3366 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3366 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3367 _('[-u] [NAME]...')),
3367 _('[-u] [NAME]...')),
3368 "^status|st":
3368 "^status|st":
3369 (status,
3369 (status,
3370 [('A', 'all', None, _('show status of all files')),
3370 [('A', 'all', None, _('show status of all files')),
3371 ('m', 'modified', None, _('show only modified files')),
3371 ('m', 'modified', None, _('show only modified files')),
3372 ('a', 'added', None, _('show only added files')),
3372 ('a', 'added', None, _('show only added files')),
3373 ('r', 'removed', None, _('show only removed files')),
3373 ('r', 'removed', None, _('show only removed files')),
3374 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3374 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3375 ('c', 'clean', None, _('show only files without changes')),
3375 ('c', 'clean', None, _('show only files without changes')),
3376 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3376 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3377 ('i', 'ignored', None, _('show only ignored files')),
3377 ('i', 'ignored', None, _('show only ignored files')),
3378 ('n', 'no-status', None, _('hide status prefix')),
3378 ('n', 'no-status', None, _('hide status prefix')),
3379 ('C', 'copies', None, _('show source of copied files')),
3379 ('C', 'copies', None, _('show source of copied files')),
3380 ('0', 'print0', None,
3380 ('0', 'print0', None,
3381 _('end filenames with NUL, for use with xargs')),
3381 _('end filenames with NUL, for use with xargs')),
3382 ('', 'rev', [], _('show difference from revision')),
3382 ('', 'rev', [], _('show difference from revision')),
3383 ] + walkopts,
3383 ] + walkopts,
3384 _('[OPTION]... [FILE]...')),
3384 _('[OPTION]... [FILE]...')),
3385 "tag":
3385 "tag":
3386 (tag,
3386 (tag,
3387 [('f', 'force', None, _('replace existing tag')),
3387 [('f', 'force', None, _('replace existing tag')),
3388 ('l', 'local', None, _('make the tag local')),
3388 ('l', 'local', None, _('make the tag local')),
3389 ('r', 'rev', '', _('revision to tag')),
3389 ('r', 'rev', '', _('revision to tag')),
3390 ('', 'remove', None, _('remove a tag')),
3390 ('', 'remove', None, _('remove a tag')),
3391 # -l/--local is already there, commitopts cannot be used
3391 # -l/--local is already there, commitopts cannot be used
3392 ('m', 'message', '', _('use <text> as commit message')),
3392 ('m', 'message', '', _('use <text> as commit message')),
3393 ] + commitopts2,
3393 ] + commitopts2,
3394 _('[-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3394 _('[-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3395 "tags": (tags, []),
3395 "tags": (tags, []),
3396 "tip":
3396 "tip":
3397 (tip,
3397 (tip,
3398 [('p', 'patch', None, _('show patch')),
3398 [('p', 'patch', None, _('show patch')),
3399 ] + templateopts,
3399 ] + templateopts,
3400 _('[-p]')),
3400 _('[-p]')),
3401 "unbundle":
3401 "unbundle":
3402 (unbundle,
3402 (unbundle,
3403 [('u', 'update', None,
3403 [('u', 'update', None,
3404 _('update to new tip if changesets were unbundled'))],
3404 _('update to new tip if changesets were unbundled'))],
3405 _('[-u] FILE...')),
3405 _('[-u] FILE...')),
3406 "^update|up|checkout|co":
3406 "^update|up|checkout|co":
3407 (update,
3407 (update,
3408 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3408 [('C', 'clean', None, _('overwrite locally modified files (no backup)')),
3409 ('d', 'date', '', _('tipmost revision matching date')),
3409 ('d', 'date', '', _('tipmost revision matching date')),
3410 ('r', 'rev', '', _('revision'))],
3410 ('r', 'rev', '', _('revision'))],
3411 _('[-C] [-d DATE] [[-r] REV]')),
3411 _('[-C] [-d DATE] [[-r] REV]')),
3412 "verify": (verify, []),
3412 "verify": (verify, []),
3413 "version": (version_, []),
3413 "version": (version_, []),
3414 }
3414 }
3415
3415
3416 norepo = ("clone init version help debugcomplete debugdata"
3416 norepo = ("clone init version help debugcomplete debugdata"
3417 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3417 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3418 optionalrepo = ("identify paths serve showconfig debugancestor")
3418 optionalrepo = ("identify paths serve showconfig debugancestor")
@@ -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
@@ -1,540 +1,540 b''
1 % help
1 % help
2 mq extension - patch management and development
2 mq extension - patch management and development
3
3
4 This extension lets you work with a stack of patches in a Mercurial
4 This extension lets you work with a stack of patches in a Mercurial
5 repository. It manages two stacks of patches - all known patches, and
5 repository. It manages two stacks of patches - all known patches, and
6 applied patches (subset of known patches).
6 applied patches (subset of known patches).
7
7
8 Known patches are represented as patch files in the .hg/patches
8 Known patches are represented as patch files in the .hg/patches
9 directory. Applied patches are both patch files and changesets.
9 directory. Applied patches are both patch files and changesets.
10
10
11 Common tasks (use "hg help command" for more details):
11 Common tasks (use "hg help command" for more details):
12
12
13 prepare repository to work with patches qinit
13 prepare repository to work with patches qinit
14 create new patch qnew
14 create new patch qnew
15 import existing patch qimport
15 import existing patch qimport
16
16
17 print patch series qseries
17 print patch series qseries
18 print applied patches qapplied
18 print applied patches qapplied
19 print name of top applied patch qtop
19 print name of top applied patch qtop
20
20
21 add known patch to applied stack qpush
21 add known patch to applied stack qpush
22 remove patch from applied stack qpop
22 remove patch from applied stack qpop
23 refresh contents of top applied patch qrefresh
23 refresh contents of top applied patch qrefresh
24
24
25 list of commands:
25 list of commands:
26
26
27 qapplied print the patches already applied
27 qapplied print the patches already applied
28 qclone clone main and patch repository at same time
28 qclone clone main and patch repository at same time
29 qcommit commit changes in the queue repository
29 qcommit commit changes in the queue repository
30 qdelete remove patches from queue
30 qdelete remove patches from queue
31 qdiff diff of the current patch and subsequent modifications
31 qdiff diff of the current patch and subsequent modifications
32 qfinish move applied patches into repository history
32 qfinish move applied patches into repository history
33 qfold fold the named patches into the current patch
33 qfold fold the named patches into the current patch
34 qgoto push or pop patches until named patch is at top of stack
34 qgoto push or pop patches until named patch is at top of stack
35 qguard set or print guards for a patch
35 qguard set or print guards for a patch
36 qheader Print the header of the topmost or specified patch
36 qheader print the header of the topmost or specified patch
37 qimport import a patch
37 qimport import a patch
38 qinit init a new queue repository
38 qinit init a new queue repository
39 qnew create a new patch
39 qnew create a new patch
40 qnext print the name of the next patch
40 qnext print the name of the next patch
41 qpop pop the current patch off the stack
41 qpop pop the current patch off the stack
42 qprev print the name of the previous patch
42 qprev print the name of the previous patch
43 qpush push the next patch onto the stack
43 qpush push the next patch onto the stack
44 qrefresh update the current patch
44 qrefresh update the current patch
45 qrename rename a patch
45 qrename rename a patch
46 qrestore restore the queue state saved by a rev
46 qrestore restore the queue state saved by a rev
47 qsave save current queue state
47 qsave save current queue state
48 qselect set or print guarded patches to push
48 qselect set or print guarded patches to push
49 qseries print the entire series file
49 qseries print the entire series file
50 qtop print the name of the current patch
50 qtop print the name of the current patch
51 qunapplied print the patches not yet applied
51 qunapplied print the patches not yet applied
52 strip strip a revision and all its descendants from the repository
52 strip strip a revision and all its descendants from the repository
53
53
54 enabled extensions:
54 enabled extensions:
55
55
56 mq patch management and development
56 mq patch management and development
57
57
58 use "hg -v help mq" to show aliases and global options
58 use "hg -v help mq" to show aliases and global options
59 adding a
59 adding a
60 updating working directory
60 updating working directory
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 adding b/z
62 adding b/z
63 % qinit
63 % qinit
64 % -R qinit
64 % -R qinit
65 % qinit -c
65 % qinit -c
66 A .hgignore
66 A .hgignore
67 A series
67 A series
68 % qinit; qinit -c
68 % qinit; qinit -c
69 .hgignore:
69 .hgignore:
70 ^\.hg
70 ^\.hg
71 ^\.mq
71 ^\.mq
72 syntax: glob
72 syntax: glob
73 status
73 status
74 guards
74 guards
75 series:
75 series:
76 abort: repository already exists!
76 abort: repository already exists!
77 % qinit; <stuff>; qinit -c
77 % qinit; <stuff>; qinit -c
78 adding .hg/patches/A
78 adding .hg/patches/A
79 adding .hg/patches/B
79 adding .hg/patches/B
80 A .hgignore
80 A .hgignore
81 A A
81 A A
82 A B
82 A B
83 A series
83 A series
84 .hgignore:
84 .hgignore:
85 status
85 status
86 bleh
86 bleh
87 series:
87 series:
88 A
88 A
89 B
89 B
90 % qrefresh
90 % qrefresh
91 foo bar
91 foo bar
92
92
93 diff -r xa
93 diff -r xa
94 --- a/a
94 --- a/a
95 +++ b/a
95 +++ b/a
96 @@ -1,1 +1,2 @@
96 @@ -1,1 +1,2 @@
97 a
97 a
98 +a
98 +a
99 % empty qrefresh
99 % empty qrefresh
100 revision:
100 revision:
101 patch:
101 patch:
102 foo bar
102 foo bar
103
103
104 working dir diff:
104 working dir diff:
105 --- a/a
105 --- a/a
106 +++ b/a
106 +++ b/a
107 @@ -1,1 +1,2 @@
107 @@ -1,1 +1,2 @@
108 a
108 a
109 +a
109 +a
110 % qpop
110 % qpop
111 Patch queue now empty
111 Patch queue now empty
112 % qpush
112 % qpush
113 applying test.patch
113 applying test.patch
114 Now at: test.patch
114 Now at: test.patch
115 % pop/push outside repo
115 % pop/push outside repo
116 Patch queue now empty
116 Patch queue now empty
117 applying test.patch
117 applying test.patch
118 Now at: test.patch
118 Now at: test.patch
119 % qrefresh in subdir
119 % qrefresh in subdir
120 % pop/push -a in subdir
120 % pop/push -a in subdir
121 Patch queue now empty
121 Patch queue now empty
122 applying test.patch
122 applying test.patch
123 applying test2.patch
123 applying test2.patch
124 Now at: test2.patch
124 Now at: test2.patch
125 % qseries
125 % qseries
126 test.patch
126 test.patch
127 test2.patch
127 test2.patch
128 Now at: test.patch
128 Now at: test.patch
129 0 A test.patch: foo bar
129 0 A test.patch: foo bar
130 1 U test2.patch:
130 1 U test2.patch:
131 applying test2.patch
131 applying test2.patch
132 Now at: test2.patch
132 Now at: test2.patch
133 % qapplied
133 % qapplied
134 test.patch
134 test.patch
135 test2.patch
135 test2.patch
136 % qtop
136 % qtop
137 test2.patch
137 test2.patch
138 % qprev
138 % qprev
139 test.patch
139 test.patch
140 % qnext
140 % qnext
141 All patches applied
141 All patches applied
142 % pop, qnext, qprev, qapplied
142 % pop, qnext, qprev, qapplied
143 Now at: test.patch
143 Now at: test.patch
144 test2.patch
144 test2.patch
145 Only one patch applied
145 Only one patch applied
146 test.patch
146 test.patch
147 % commit should fail
147 % commit should fail
148 abort: cannot commit over an applied mq patch
148 abort: cannot commit over an applied mq patch
149 % push should fail
149 % push should fail
150 pushing to ../../k
150 pushing to ../../k
151 abort: source has mq patches applied
151 abort: source has mq patches applied
152 % import should fail
152 % import should fail
153 abort: cannot import over an applied patch
153 abort: cannot import over an applied patch
154 % qunapplied
154 % qunapplied
155 test2.patch
155 test2.patch
156 % qpush/qpop with index
156 % qpush/qpop with index
157 applying test2.patch
157 applying test2.patch
158 Now at: test2.patch
158 Now at: test2.patch
159 Now at: test.patch
159 Now at: test.patch
160 applying test1b.patch
160 applying test1b.patch
161 Now at: test1b.patch
161 Now at: test1b.patch
162 applying test2.patch
162 applying test2.patch
163 Now at: test2.patch
163 Now at: test2.patch
164 Now at: test1b.patch
164 Now at: test1b.patch
165 Now at: test.patch
165 Now at: test.patch
166 applying test1b.patch
166 applying test1b.patch
167 applying test2.patch
167 applying test2.patch
168 Now at: test2.patch
168 Now at: test2.patch
169 % push should succeed
169 % push should succeed
170 Patch queue now empty
170 Patch queue now empty
171 pushing to ../../k
171 pushing to ../../k
172 searching for changes
172 searching for changes
173 adding changesets
173 adding changesets
174 adding manifests
174 adding manifests
175 adding file changes
175 adding file changes
176 added 1 changesets with 1 changes to 1 files
176 added 1 changesets with 1 changes to 1 files
177 % qpush/qpop error codes
177 % qpush/qpop error codes
178 applying test.patch
178 applying test.patch
179 applying test1b.patch
179 applying test1b.patch
180 applying test2.patch
180 applying test2.patch
181 Now at: test2.patch
181 Now at: test2.patch
182 % pops all patches and succeeds
182 % pops all patches and succeeds
183 Patch queue now empty
183 Patch queue now empty
184 qpop -a succeeds
184 qpop -a succeeds
185 % does nothing and succeeds
185 % does nothing and succeeds
186 no patches applied
186 no patches applied
187 qpop -a succeeds
187 qpop -a succeeds
188 % fails - nothing else to pop
188 % fails - nothing else to pop
189 no patches applied
189 no patches applied
190 qpop fails
190 qpop fails
191 % pushes a patch and succeeds
191 % pushes a patch and succeeds
192 applying test.patch
192 applying test.patch
193 Now at: test.patch
193 Now at: test.patch
194 qpush succeeds
194 qpush succeeds
195 % pops a patch and succeeds
195 % pops a patch and succeeds
196 Patch queue now empty
196 Patch queue now empty
197 qpop succeeds
197 qpop succeeds
198 % pushes up to test1b.patch and succeeds
198 % pushes up to test1b.patch and succeeds
199 applying test.patch
199 applying test.patch
200 applying test1b.patch
200 applying test1b.patch
201 Now at: test1b.patch
201 Now at: test1b.patch
202 qpush test1b.patch succeeds
202 qpush test1b.patch succeeds
203 % does nothing and succeeds
203 % does nothing and succeeds
204 qpush: test1b.patch is already at the top
204 qpush: test1b.patch is already at the top
205 qpush test1b.patch succeeds
205 qpush test1b.patch succeeds
206 % does nothing and succeeds
206 % does nothing and succeeds
207 qpop: test1b.patch is already at the top
207 qpop: test1b.patch is already at the top
208 qpop test1b.patch succeeds
208 qpop test1b.patch succeeds
209 % fails - can't push to this patch
209 % fails - can't push to this patch
210 abort: cannot push to a previous patch: test.patch
210 abort: cannot push to a previous patch: test.patch
211 qpush test.patch fails
211 qpush test.patch fails
212 % fails - can't pop to this patch
212 % fails - can't pop to this patch
213 abort: patch test2.patch is not applied
213 abort: patch test2.patch is not applied
214 qpop test2.patch fails
214 qpop test2.patch fails
215 % pops up to test.patch and succeeds
215 % pops up to test.patch and succeeds
216 Now at: test.patch
216 Now at: test.patch
217 qpop test.patch succeeds
217 qpop test.patch succeeds
218 % pushes all patches and succeeds
218 % pushes all patches and succeeds
219 applying test1b.patch
219 applying test1b.patch
220 applying test2.patch
220 applying test2.patch
221 Now at: test2.patch
221 Now at: test2.patch
222 qpush -a succeeds
222 qpush -a succeeds
223 % does nothing and succeeds
223 % does nothing and succeeds
224 all patches are currently applied
224 all patches are currently applied
225 qpush -a succeeds
225 qpush -a succeeds
226 % fails - nothing else to push
226 % fails - nothing else to push
227 patch series already fully applied
227 patch series already fully applied
228 qpush fails
228 qpush fails
229 % does nothing and succeeds
229 % does nothing and succeeds
230 qpush: test2.patch is already at the top
230 qpush: test2.patch is already at the top
231 qpush test2.patch succeeds
231 qpush test2.patch succeeds
232 % strip
232 % strip
233 adding x
233 adding x
234 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
234 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
235 saving bundle to
235 saving bundle to
236 adding changesets
236 adding changesets
237 adding manifests
237 adding manifests
238 adding file changes
238 adding file changes
239 added 1 changesets with 1 changes to 1 files
239 added 1 changesets with 1 changes to 1 files
240 (run 'hg update' to get a working copy)
240 (run 'hg update' to get a working copy)
241 % strip with local changes, should complain
241 % strip with local changes, should complain
242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 abort: local changes found
243 abort: local changes found
244 % --force strip with local changes
244 % --force strip with local changes
245 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
245 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
246 saving bundle to
246 saving bundle to
247 % cd b; hg qrefresh
247 % cd b; hg qrefresh
248 adding a
248 adding a
249 foo
249 foo
250
250
251 diff -r cb9a9f314b8b a
251 diff -r cb9a9f314b8b a
252 --- a/a
252 --- a/a
253 +++ b/a
253 +++ b/a
254 @@ -1,1 +1,2 @@
254 @@ -1,1 +1,2 @@
255 a
255 a
256 +a
256 +a
257 diff -r cb9a9f314b8b b/f
257 diff -r cb9a9f314b8b b/f
258 --- /dev/null
258 --- /dev/null
259 +++ b/b/f
259 +++ b/b/f
260 @@ -0,0 +1,1 @@
260 @@ -0,0 +1,1 @@
261 +f
261 +f
262 % hg qrefresh .
262 % hg qrefresh .
263 foo
263 foo
264
264
265 diff -r cb9a9f314b8b b/f
265 diff -r cb9a9f314b8b b/f
266 --- /dev/null
266 --- /dev/null
267 +++ b/b/f
267 +++ b/b/f
268 @@ -0,0 +1,1 @@
268 @@ -0,0 +1,1 @@
269 +f
269 +f
270 M a
270 M a
271 % qpush failure
271 % qpush failure
272 Patch queue now empty
272 Patch queue now empty
273 applying foo
273 applying foo
274 applying bar
274 applying bar
275 file foo already exists
275 file foo already exists
276 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
276 1 out of 1 hunks FAILED -- saving rejects to file foo.rej
277 patch failed, unable to continue (try -v)
277 patch failed, unable to continue (try -v)
278 patch failed, rejects left in working dir
278 patch failed, rejects left in working dir
279 Errors during apply, please fix and refresh bar
279 Errors during apply, please fix and refresh bar
280 ? foo
280 ? foo
281 ? foo.rej
281 ? foo.rej
282 % mq tags
282 % mq tags
283 0 qparent
283 0 qparent
284 1 qbase foo
284 1 qbase foo
285 2 qtip bar tip
285 2 qtip bar tip
286 % bad node in status
286 % bad node in status
287 Now at: foo
287 Now at: foo
288 changeset: 0:cb9a9f314b8b
288 changeset: 0:cb9a9f314b8b
289 mq status file refers to unknown node
289 mq status file refers to unknown node
290 tag: tip
290 tag: tip
291 user: test
291 user: test
292 date: Thu Jan 01 00:00:00 1970 +0000
292 date: Thu Jan 01 00:00:00 1970 +0000
293 summary: a
293 summary: a
294
294
295 mq status file refers to unknown node
295 mq status file refers to unknown node
296 default 0:cb9a9f314b8b
296 default 0:cb9a9f314b8b
297 abort: working directory revision is not qtip
297 abort: working directory revision is not qtip
298 new file
298 new file
299
299
300 diff --git a/new b/new
300 diff --git a/new b/new
301 new file mode 100755
301 new file mode 100755
302 --- /dev/null
302 --- /dev/null
303 +++ b/new
303 +++ b/new
304 @@ -0,0 +1,1 @@
304 @@ -0,0 +1,1 @@
305 +foo
305 +foo
306 copy file
306 copy file
307
307
308 diff --git a/new b/copy
308 diff --git a/new b/copy
309 copy from new
309 copy from new
310 copy to copy
310 copy to copy
311 Now at: new
311 Now at: new
312 applying copy
312 applying copy
313 Now at: copy
313 Now at: copy
314 diff --git a/new b/copy
314 diff --git a/new b/copy
315 copy from new
315 copy from new
316 copy to copy
316 copy to copy
317 diff --git a/new b/copy
317 diff --git a/new b/copy
318 copy from new
318 copy from new
319 copy to copy
319 copy to copy
320 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
320 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
321 created new head
321 created new head
322 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
322 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
323 adding branch
323 adding branch
324 adding changesets
324 adding changesets
325 adding manifests
325 adding manifests
326 adding file changes
326 adding file changes
327 added 1 changesets with 1 changes to 1 files
327 added 1 changesets with 1 changes to 1 files
328 Patch queue now empty
328 Patch queue now empty
329 (working directory not at tip)
329 (working directory not at tip)
330 applying bar
330 applying bar
331 Now at: bar
331 Now at: bar
332 diff --git a/bar b/bar
332 diff --git a/bar b/bar
333 new file mode 100644
333 new file mode 100644
334 --- /dev/null
334 --- /dev/null
335 +++ b/bar
335 +++ b/bar
336 @@ -0,0 +1,1 @@
336 @@ -0,0 +1,1 @@
337 +bar
337 +bar
338 diff --git a/foo b/baz
338 diff --git a/foo b/baz
339 rename from foo
339 rename from foo
340 rename to baz
340 rename to baz
341 2 baz (foo)
341 2 baz (foo)
342 diff --git a/bar b/bar
342 diff --git a/bar b/bar
343 new file mode 100644
343 new file mode 100644
344 --- /dev/null
344 --- /dev/null
345 +++ b/bar
345 +++ b/bar
346 @@ -0,0 +1,1 @@
346 @@ -0,0 +1,1 @@
347 +bar
347 +bar
348 diff --git a/foo b/baz
348 diff --git a/foo b/baz
349 rename from foo
349 rename from foo
350 rename to baz
350 rename to baz
351 2 baz (foo)
351 2 baz (foo)
352 diff --git a/bar b/bar
352 diff --git a/bar b/bar
353 diff --git a/foo b/baz
353 diff --git a/foo b/baz
354
354
355 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
355 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
356 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
356 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
357 adding branch
357 adding branch
358 adding changesets
358 adding changesets
359 adding manifests
359 adding manifests
360 adding file changes
360 adding file changes
361 added 1 changesets with 1 changes to 1 files
361 added 1 changesets with 1 changes to 1 files
362 Patch queue now empty
362 Patch queue now empty
363 (working directory not at tip)
363 (working directory not at tip)
364 applying bar
364 applying bar
365 Now at: bar
365 Now at: bar
366 diff --git a/foo b/bleh
366 diff --git a/foo b/bleh
367 rename from foo
367 rename from foo
368 rename to bleh
368 rename to bleh
369 diff --git a/quux b/quux
369 diff --git a/quux b/quux
370 new file mode 100644
370 new file mode 100644
371 --- /dev/null
371 --- /dev/null
372 +++ b/quux
372 +++ b/quux
373 @@ -0,0 +1,1 @@
373 @@ -0,0 +1,1 @@
374 +bar
374 +bar
375 3 bleh (foo)
375 3 bleh (foo)
376 diff --git a/foo b/barney
376 diff --git a/foo b/barney
377 rename from foo
377 rename from foo
378 rename to barney
378 rename to barney
379 diff --git a/fred b/fred
379 diff --git a/fred b/fred
380 new file mode 100644
380 new file mode 100644
381 --- /dev/null
381 --- /dev/null
382 +++ b/fred
382 +++ b/fred
383 @@ -0,0 +1,1 @@
383 @@ -0,0 +1,1 @@
384 +bar
384 +bar
385 3 barney (foo)
385 3 barney (foo)
386 % refresh omitting an added file
386 % refresh omitting an added file
387 C newfile
387 C newfile
388 A newfile
388 A newfile
389 Now at: bar
389 Now at: bar
390 % create a git patch
390 % create a git patch
391 diff --git a/alexander b/alexander
391 diff --git a/alexander b/alexander
392 % create a git binary patch
392 % create a git binary patch
393 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
393 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
394 diff --git a/bucephalus b/bucephalus
394 diff --git a/bucephalus b/bucephalus
395 % check binary patches can be popped and pushed
395 % check binary patches can be popped and pushed
396 Now at: addalexander
396 Now at: addalexander
397 applying addbucephalus
397 applying addbucephalus
398 Now at: addbucephalus
398 Now at: addbucephalus
399 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
399 8ba2a2f3e77b55d03051ff9c24ad65e7 bucephalus
400 % strip again
400 % strip again
401 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
401 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 created new head
402 created new head
403 merging foo
403 merging foo
404 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
404 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
405 (branch merge, don't forget to commit)
405 (branch merge, don't forget to commit)
406 changeset: 3:99615015637b
406 changeset: 3:99615015637b
407 tag: tip
407 tag: tip
408 parent: 2:20cbbe65cff7
408 parent: 2:20cbbe65cff7
409 parent: 1:d2871fc282d4
409 parent: 1:d2871fc282d4
410 user: test
410 user: test
411 date: Thu Jan 01 00:00:00 1970 +0000
411 date: Thu Jan 01 00:00:00 1970 +0000
412 summary: merge
412 summary: merge
413
413
414 changeset: 2:20cbbe65cff7
414 changeset: 2:20cbbe65cff7
415 parent: 0:53245c60e682
415 parent: 0:53245c60e682
416 user: test
416 user: test
417 date: Thu Jan 01 00:00:00 1970 +0000
417 date: Thu Jan 01 00:00:00 1970 +0000
418 summary: change foo 2
418 summary: change foo 2
419
419
420 changeset: 1:d2871fc282d4
420 changeset: 1:d2871fc282d4
421 user: test
421 user: test
422 date: Thu Jan 01 00:00:00 1970 +0000
422 date: Thu Jan 01 00:00:00 1970 +0000
423 summary: change foo 1
423 summary: change foo 1
424
424
425 changeset: 0:53245c60e682
425 changeset: 0:53245c60e682
426 user: test
426 user: test
427 date: Thu Jan 01 00:00:00 1970 +0000
427 date: Thu Jan 01 00:00:00 1970 +0000
428 summary: add foo
428 summary: add foo
429
429
430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 saving bundle to
431 saving bundle to
432 saving bundle to
432 saving bundle to
433 adding branch
433 adding branch
434 adding changesets
434 adding changesets
435 adding manifests
435 adding manifests
436 adding file changes
436 adding file changes
437 added 1 changesets with 1 changes to 1 files
437 added 1 changesets with 1 changes to 1 files
438 changeset: 1:20cbbe65cff7
438 changeset: 1:20cbbe65cff7
439 tag: tip
439 tag: tip
440 user: test
440 user: test
441 date: Thu Jan 01 00:00:00 1970 +0000
441 date: Thu Jan 01 00:00:00 1970 +0000
442 summary: change foo 2
442 summary: change foo 2
443
443
444 changeset: 0:53245c60e682
444 changeset: 0:53245c60e682
445 user: test
445 user: test
446 date: Thu Jan 01 00:00:00 1970 +0000
446 date: Thu Jan 01 00:00:00 1970 +0000
447 summary: add foo
447 summary: add foo
448
448
449 % qclone
449 % qclone
450 abort: versioned patch repository not found (see qinit -c)
450 abort: versioned patch repository not found (see qinit -c)
451 adding .hg/patches/patch1
451 adding .hg/patches/patch1
452 main repo:
452 main repo:
453 rev 1: change foo
453 rev 1: change foo
454 rev 0: add foo
454 rev 0: add foo
455 patch repo:
455 patch repo:
456 rev 0: checkpoint
456 rev 0: checkpoint
457 updating working directory
457 updating working directory
458 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
458 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
459 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
459 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
460 main repo:
460 main repo:
461 rev 0: add foo
461 rev 0: add foo
462 patch repo:
462 patch repo:
463 rev 0: checkpoint
463 rev 0: checkpoint
464 Patch queue now empty
464 Patch queue now empty
465 main repo:
465 main repo:
466 rev 0: add foo
466 rev 0: add foo
467 patch repo:
467 patch repo:
468 rev 0: checkpoint
468 rev 0: checkpoint
469 updating working directory
469 updating working directory
470 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 main repo:
472 main repo:
473 rev 0: add foo
473 rev 0: add foo
474 patch repo:
474 patch repo:
475 rev 0: checkpoint
475 rev 0: checkpoint
476 % test applying on an empty file (issue 1033)
476 % test applying on an empty file (issue 1033)
477 adding a
477 adding a
478 Patch queue now empty
478 Patch queue now empty
479 applying changea
479 applying changea
480 Now at: changea
480 Now at: changea
481 % test qpush with --force, issue1087
481 % test qpush with --force, issue1087
482 adding bye.txt
482 adding bye.txt
483 adding hello.txt
483 adding hello.txt
484 Patch queue now empty
484 Patch queue now empty
485 % qpush should fail, local changes
485 % qpush should fail, local changes
486 abort: local changes found, refresh first
486 abort: local changes found, refresh first
487 % apply force, should not discard changes with empty patch
487 % apply force, should not discard changes with empty patch
488 applying empty
488 applying empty
489 patch: **** Only garbage was found in the patch input.
489 patch: **** Only garbage was found in the patch input.
490 patch failed, unable to continue (try -v)
490 patch failed, unable to continue (try -v)
491 patch empty is empty
491 patch empty is empty
492 Now at: empty
492 Now at: empty
493 diff -r bf5fc3f07a0a hello.txt
493 diff -r bf5fc3f07a0a hello.txt
494 --- a/hello.txt
494 --- a/hello.txt
495 +++ b/hello.txt
495 +++ b/hello.txt
496 @@ -1,1 +1,2 @@
496 @@ -1,1 +1,2 @@
497 hello
497 hello
498 +world
498 +world
499 diff -r 9ecee4f634e3 hello.txt
499 diff -r 9ecee4f634e3 hello.txt
500 --- a/hello.txt
500 --- a/hello.txt
501 +++ b/hello.txt
501 +++ b/hello.txt
502 @@ -1,1 +1,2 @@
502 @@ -1,1 +1,2 @@
503 hello
503 hello
504 +world
504 +world
505 changeset: 1:bf5fc3f07a0a
505 changeset: 1:bf5fc3f07a0a
506 tag: qtip
506 tag: qtip
507 tag: tip
507 tag: tip
508 tag: empty
508 tag: empty
509 tag: qbase
509 tag: qbase
510 user: test
510 user: test
511 date: Thu Jan 01 00:00:00 1970 +0000
511 date: Thu Jan 01 00:00:00 1970 +0000
512 summary: imported patch empty
512 summary: imported patch empty
513
513
514
514
515 Patch queue now empty
515 Patch queue now empty
516 % qpush should fail, local changes
516 % qpush should fail, local changes
517 abort: local changes found, refresh first
517 abort: local changes found, refresh first
518 % apply force, should discard changes in hello, but not bye
518 % apply force, should discard changes in hello, but not bye
519 applying empty
519 applying empty
520 Now at: empty
520 Now at: empty
521 M bye.txt
521 M bye.txt
522 diff -r ba252371dbc1 bye.txt
522 diff -r ba252371dbc1 bye.txt
523 --- a/bye.txt
523 --- a/bye.txt
524 +++ b/bye.txt
524 +++ b/bye.txt
525 @@ -1,1 +1,2 @@
525 @@ -1,1 +1,2 @@
526 bye
526 bye
527 +universe
527 +universe
528 diff -r 9ecee4f634e3 bye.txt
528 diff -r 9ecee4f634e3 bye.txt
529 --- a/bye.txt
529 --- a/bye.txt
530 +++ b/bye.txt
530 +++ b/bye.txt
531 @@ -1,1 +1,2 @@
531 @@ -1,1 +1,2 @@
532 bye
532 bye
533 +universe
533 +universe
534 diff -r 9ecee4f634e3 hello.txt
534 diff -r 9ecee4f634e3 hello.txt
535 --- a/hello.txt
535 --- a/hello.txt
536 +++ b/hello.txt
536 +++ b/hello.txt
537 @@ -1,1 +1,3 @@
537 @@ -1,1 +1,3 @@
538 hello
538 hello
539 +world
539 +world
540 +universe
540 +universe
General Comments 0
You need to be logged in to leave comments. Login now