##// END OF EJS Templates
rewriteutil: use precheck() in uncommit and amend commands...
Pulkit Goyal -
r35244:98f97eb2 default
parent child Browse files
Show More
@@ -1,270 +1,261 b''
1 # uncommit - undo the actions of a commit
1 # uncommit - undo the actions of a commit
2 #
2 #
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
3 # Copyright 2011 Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
5 # Pierre-Yves David <pierre-yves.david@ens-lyon.org>
6 # Patrick Mezard <patrick@mezard.eu>
6 # Patrick Mezard <patrick@mezard.eu>
7 # Copyright 2016 Facebook, Inc.
7 # Copyright 2016 Facebook, Inc.
8 #
8 #
9 # This software may be used and distributed according to the terms of the
9 # This software may be used and distributed according to the terms of the
10 # GNU General Public License version 2 or any later version.
10 # GNU General Public License version 2 or any later version.
11
11
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
12 """uncommit part or all of a local changeset (EXPERIMENTAL)
13
13
14 This command undoes the effect of a local commit, returning the affected
14 This command undoes the effect of a local commit, returning the affected
15 files to their uncommitted state. This means that files modified, added or
15 files to their uncommitted state. This means that files modified, added or
16 removed in the changeset will be left unchanged, and so will remain modified,
16 removed in the changeset will be left unchanged, and so will remain modified,
17 added and removed in the working directory.
17 added and removed in the working directory.
18 """
18 """
19
19
20 from __future__ import absolute_import
20 from __future__ import absolute_import
21
21
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23
23
24 from mercurial import (
24 from mercurial import (
25 cmdutil,
25 cmdutil,
26 commands,
26 commands,
27 context,
27 context,
28 copies,
28 copies,
29 error,
29 error,
30 node,
30 node,
31 obsolete,
32 obsutil,
31 obsutil,
33 pycompat,
32 pycompat,
34 registrar,
33 registrar,
34 rewriteutil,
35 scmutil,
35 scmutil,
36 )
36 )
37
37
38 cmdtable = {}
38 cmdtable = {}
39 command = registrar.command(cmdtable)
39 command = registrar.command(cmdtable)
40
40
41 configtable = {}
41 configtable = {}
42 configitem = registrar.configitem(configtable)
42 configitem = registrar.configitem(configtable)
43
43
44 configitem('experimental', 'uncommitondirtywdir',
44 configitem('experimental', 'uncommitondirtywdir',
45 default=False,
45 default=False,
46 )
46 )
47
47
48 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
48 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
49 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
49 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
50 # be specifying the version(s) of Mercurial they are tested with, or
50 # be specifying the version(s) of Mercurial they are tested with, or
51 # leave the attribute unspecified.
51 # leave the attribute unspecified.
52 testedwith = 'ships-with-hg-core'
52 testedwith = 'ships-with-hg-core'
53
53
54 def _commitfiltered(repo, ctx, match, allowempty):
54 def _commitfiltered(repo, ctx, match, allowempty):
55 """Recommit ctx with changed files not in match. Return the new
55 """Recommit ctx with changed files not in match. Return the new
56 node identifier, or None if nothing changed.
56 node identifier, or None if nothing changed.
57 """
57 """
58 base = ctx.p1()
58 base = ctx.p1()
59 # ctx
59 # ctx
60 initialfiles = set(ctx.files())
60 initialfiles = set(ctx.files())
61 exclude = set(f for f in initialfiles if match(f))
61 exclude = set(f for f in initialfiles if match(f))
62
62
63 # No files matched commit, so nothing excluded
63 # No files matched commit, so nothing excluded
64 if not exclude:
64 if not exclude:
65 return None
65 return None
66
66
67 files = (initialfiles - exclude)
67 files = (initialfiles - exclude)
68 # return the p1 so that we don't create an obsmarker later
68 # return the p1 so that we don't create an obsmarker later
69 if not files and not allowempty:
69 if not files and not allowempty:
70 return ctx.parents()[0].node()
70 return ctx.parents()[0].node()
71
71
72 # Filter copies
72 # Filter copies
73 copied = copies.pathcopies(base, ctx)
73 copied = copies.pathcopies(base, ctx)
74 copied = dict((dst, src) for dst, src in copied.iteritems()
74 copied = dict((dst, src) for dst, src in copied.iteritems()
75 if dst in files)
75 if dst in files)
76 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
76 def filectxfn(repo, memctx, path, contentctx=ctx, redirect=()):
77 if path not in contentctx:
77 if path not in contentctx:
78 return None
78 return None
79 fctx = contentctx[path]
79 fctx = contentctx[path]
80 mctx = context.memfilectx(repo, fctx.path(), fctx.data(),
80 mctx = context.memfilectx(repo, fctx.path(), fctx.data(),
81 fctx.islink(),
81 fctx.islink(),
82 fctx.isexec(),
82 fctx.isexec(),
83 copied=copied.get(path))
83 copied=copied.get(path))
84 return mctx
84 return mctx
85
85
86 new = context.memctx(repo,
86 new = context.memctx(repo,
87 parents=[base.node(), node.nullid],
87 parents=[base.node(), node.nullid],
88 text=ctx.description(),
88 text=ctx.description(),
89 files=files,
89 files=files,
90 filectxfn=filectxfn,
90 filectxfn=filectxfn,
91 user=ctx.user(),
91 user=ctx.user(),
92 date=ctx.date(),
92 date=ctx.date(),
93 extra=ctx.extra())
93 extra=ctx.extra())
94 # phase handling
94 # phase handling
95 commitphase = ctx.phase()
95 commitphase = ctx.phase()
96 overrides = {('phases', 'new-commit'): commitphase}
96 overrides = {('phases', 'new-commit'): commitphase}
97 with repo.ui.configoverride(overrides, 'uncommit'):
97 with repo.ui.configoverride(overrides, 'uncommit'):
98 newid = repo.commitctx(new)
98 newid = repo.commitctx(new)
99 return newid
99 return newid
100
100
101 def _fixdirstate(repo, oldctx, newctx, status):
101 def _fixdirstate(repo, oldctx, newctx, status):
102 """ fix the dirstate after switching the working directory from oldctx to
102 """ fix the dirstate after switching the working directory from oldctx to
103 newctx which can be result of either unamend or uncommit.
103 newctx which can be result of either unamend or uncommit.
104 """
104 """
105 ds = repo.dirstate
105 ds = repo.dirstate
106 copies = dict(ds.copies())
106 copies = dict(ds.copies())
107 s = status
107 s = status
108 for f in s.modified:
108 for f in s.modified:
109 if ds[f] == 'r':
109 if ds[f] == 'r':
110 # modified + removed -> removed
110 # modified + removed -> removed
111 continue
111 continue
112 ds.normallookup(f)
112 ds.normallookup(f)
113
113
114 for f in s.added:
114 for f in s.added:
115 if ds[f] == 'r':
115 if ds[f] == 'r':
116 # added + removed -> unknown
116 # added + removed -> unknown
117 ds.drop(f)
117 ds.drop(f)
118 elif ds[f] != 'a':
118 elif ds[f] != 'a':
119 ds.add(f)
119 ds.add(f)
120
120
121 for f in s.removed:
121 for f in s.removed:
122 if ds[f] == 'a':
122 if ds[f] == 'a':
123 # removed + added -> normal
123 # removed + added -> normal
124 ds.normallookup(f)
124 ds.normallookup(f)
125 elif ds[f] != 'r':
125 elif ds[f] != 'r':
126 ds.remove(f)
126 ds.remove(f)
127
127
128 # Merge old parent and old working dir copies
128 # Merge old parent and old working dir copies
129 oldcopies = {}
129 oldcopies = {}
130 for f in (s.modified + s.added):
130 for f in (s.modified + s.added):
131 src = oldctx[f].renamed()
131 src = oldctx[f].renamed()
132 if src:
132 if src:
133 oldcopies[f] = src[0]
133 oldcopies[f] = src[0]
134 oldcopies.update(copies)
134 oldcopies.update(copies)
135 copies = dict((dst, oldcopies.get(src, src))
135 copies = dict((dst, oldcopies.get(src, src))
136 for dst, src in oldcopies.iteritems())
136 for dst, src in oldcopies.iteritems())
137 # Adjust the dirstate copies
137 # Adjust the dirstate copies
138 for dst, src in copies.iteritems():
138 for dst, src in copies.iteritems():
139 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
139 if (src not in newctx or dst in newctx or ds[dst] != 'a'):
140 src = None
140 src = None
141 ds.copy(src, dst)
141 ds.copy(src, dst)
142
142
143 @command('uncommit',
143 @command('uncommit',
144 [('', 'keep', False, _('allow an empty commit after uncommiting')),
144 [('', 'keep', False, _('allow an empty commit after uncommiting')),
145 ] + commands.walkopts,
145 ] + commands.walkopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def uncommit(ui, repo, *pats, **opts):
147 def uncommit(ui, repo, *pats, **opts):
148 """uncommit part or all of a local changeset
148 """uncommit part or all of a local changeset
149
149
150 This command undoes the effect of a local commit, returning the affected
150 This command undoes the effect of a local commit, returning the affected
151 files to their uncommitted state. This means that files modified or
151 files to their uncommitted state. This means that files modified or
152 deleted in the changeset will be left unchanged, and so will remain
152 deleted in the changeset will be left unchanged, and so will remain
153 modified in the working directory.
153 modified in the working directory.
154 """
154 """
155 opts = pycompat.byteskwargs(opts)
155 opts = pycompat.byteskwargs(opts)
156
156
157 with repo.wlock(), repo.lock():
157 with repo.wlock(), repo.lock():
158 wctx = repo[None]
159
158
160 if not pats and not repo.ui.configbool('experimental',
159 if not pats and not repo.ui.configbool('experimental',
161 'uncommitondirtywdir'):
160 'uncommitondirtywdir'):
162 cmdutil.bailifchanged(repo)
161 cmdutil.bailifchanged(repo)
163 if wctx.parents()[0].node() == node.nullid:
164 raise error.Abort(_("cannot uncommit null changeset"))
165 if len(wctx.parents()) > 1:
166 raise error.Abort(_("cannot uncommit while merging"))
167 old = repo['.']
162 old = repo['.']
168 if not old.mutable():
163 rewriteutil.precheck(repo, [old.rev()], 'uncommit')
169 raise error.Abort(_('cannot uncommit public changesets'))
170 if len(old.parents()) > 1:
164 if len(old.parents()) > 1:
171 raise error.Abort(_("cannot uncommit merge changeset"))
165 raise error.Abort(_("cannot uncommit merge changeset"))
172 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
173 if not allowunstable and old.children():
174 raise error.Abort(_('cannot uncommit changeset with children'))
175
166
176 with repo.transaction('uncommit'):
167 with repo.transaction('uncommit'):
177 match = scmutil.match(old, pats, opts)
168 match = scmutil.match(old, pats, opts)
178 newid = _commitfiltered(repo, old, match, opts.get('keep'))
169 newid = _commitfiltered(repo, old, match, opts.get('keep'))
179 if newid is None:
170 if newid is None:
180 ui.status(_("nothing to uncommit\n"))
171 ui.status(_("nothing to uncommit\n"))
181 return 1
172 return 1
182
173
183 mapping = {}
174 mapping = {}
184 if newid != old.p1().node():
175 if newid != old.p1().node():
185 # Move local changes on filtered changeset
176 # Move local changes on filtered changeset
186 mapping[old.node()] = (newid,)
177 mapping[old.node()] = (newid,)
187 else:
178 else:
188 # Fully removed the old commit
179 # Fully removed the old commit
189 mapping[old.node()] = ()
180 mapping[old.node()] = ()
190
181
191 scmutil.cleanupnodes(repo, mapping, 'uncommit')
182 scmutil.cleanupnodes(repo, mapping, 'uncommit')
192
183
193 with repo.dirstate.parentchange():
184 with repo.dirstate.parentchange():
194 repo.dirstate.setparents(newid, node.nullid)
185 repo.dirstate.setparents(newid, node.nullid)
195 s = repo.status(old.p1(), old, match=match)
186 s = repo.status(old.p1(), old, match=match)
196 _fixdirstate(repo, old, repo[newid], s)
187 _fixdirstate(repo, old, repo[newid], s)
197
188
198 def predecessormarkers(ctx):
189 def predecessormarkers(ctx):
199 """yields the obsolete markers marking the given changeset as a successor"""
190 """yields the obsolete markers marking the given changeset as a successor"""
200 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
191 for data in ctx.repo().obsstore.predecessors.get(ctx.node(), ()):
201 yield obsutil.marker(ctx.repo(), data)
192 yield obsutil.marker(ctx.repo(), data)
202
193
203 @command('^unamend', [])
194 @command('^unamend', [])
204 def unamend(ui, repo, **opts):
195 def unamend(ui, repo, **opts):
205 """
196 """
206 undo the most recent amend operation on a current changeset
197 undo the most recent amend operation on a current changeset
207
198
208 This command will roll back to the previous version of a changeset,
199 This command will roll back to the previous version of a changeset,
209 leaving working directory in state in which it was before running
200 leaving working directory in state in which it was before running
210 `hg amend` (e.g. files modified as part of an amend will be
201 `hg amend` (e.g. files modified as part of an amend will be
211 marked as modified `hg status`)
202 marked as modified `hg status`)
212 """
203 """
213
204
214 unfi = repo.unfiltered()
205 unfi = repo.unfiltered()
215 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
206 with repo.wlock(), repo.lock(), repo.transaction('unamend'):
216
207
217 # identify the commit from which to unamend
208 # identify the commit from which to unamend
218 curctx = repo['.']
209 curctx = repo['.']
219
210
220 if not curctx.mutable():
211 if not curctx.mutable():
221 raise error.Abort(_('cannot unamend public changesets'))
212 raise error.Abort(_('cannot unamend public changesets'))
222
213
223 # identify the commit to which to unamend
214 # identify the commit to which to unamend
224 markers = list(predecessormarkers(curctx))
215 markers = list(predecessormarkers(curctx))
225 if len(markers) != 1:
216 if len(markers) != 1:
226 e = _("changeset must have one predecessor, found %i predecessors")
217 e = _("changeset must have one predecessor, found %i predecessors")
227 raise error.Abort(e % len(markers))
218 raise error.Abort(e % len(markers))
228
219
229 prednode = markers[0].prednode()
220 prednode = markers[0].prednode()
230 predctx = unfi[prednode]
221 predctx = unfi[prednode]
231
222
232 if curctx.children():
223 if curctx.children():
233 raise error.Abort(_("cannot unamend a changeset with children"))
224 raise error.Abort(_("cannot unamend a changeset with children"))
234
225
235 # add an extra so that we get a new hash
226 # add an extra so that we get a new hash
236 # note: allowing unamend to undo an unamend is an intentional feature
227 # note: allowing unamend to undo an unamend is an intentional feature
237 extras = predctx.extra()
228 extras = predctx.extra()
238 extras['unamend_source'] = curctx.hex()
229 extras['unamend_source'] = curctx.hex()
239
230
240 def filectxfn(repo, ctx_, path):
231 def filectxfn(repo, ctx_, path):
241 try:
232 try:
242 return predctx.filectx(path)
233 return predctx.filectx(path)
243 except KeyError:
234 except KeyError:
244 return None
235 return None
245
236
246 # Make a new commit same as predctx
237 # Make a new commit same as predctx
247 newctx = context.memctx(repo,
238 newctx = context.memctx(repo,
248 parents=(predctx.p1(), predctx.p2()),
239 parents=(predctx.p1(), predctx.p2()),
249 text=predctx.description(),
240 text=predctx.description(),
250 files=predctx.files(),
241 files=predctx.files(),
251 filectxfn=filectxfn,
242 filectxfn=filectxfn,
252 user=predctx.user(),
243 user=predctx.user(),
253 date=predctx.date(),
244 date=predctx.date(),
254 extra=extras)
245 extra=extras)
255 # phase handling
246 # phase handling
256 commitphase = curctx.phase()
247 commitphase = curctx.phase()
257 overrides = {('phases', 'new-commit'): commitphase}
248 overrides = {('phases', 'new-commit'): commitphase}
258 with repo.ui.configoverride(overrides, 'uncommit'):
249 with repo.ui.configoverride(overrides, 'uncommit'):
259 newprednode = repo.commitctx(newctx)
250 newprednode = repo.commitctx(newctx)
260
251
261 newpredctx = repo[newprednode]
252 newpredctx = repo[newprednode]
262 dirstate = repo.dirstate
253 dirstate = repo.dirstate
263
254
264 with dirstate.parentchange():
255 with dirstate.parentchange():
265 dirstate.setparents(newprednode, node.nullid)
256 dirstate.setparents(newprednode, node.nullid)
266 s = repo.status(predctx, curctx)
257 s = repo.status(predctx, curctx)
267 _fixdirstate(repo, curctx, newpredctx, s)
258 _fixdirstate(repo, curctx, newpredctx, s)
268
259
269 mapping = {curctx.node(): (newprednode,)}
260 mapping = {curctx.node(): (newprednode,)}
270 scmutil.cleanupnodes(repo, mapping, 'unamend')
261 scmutil.cleanupnodes(repo, mapping, 'unamend')
@@ -1,5592 +1,5587 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import sys
14 import sys
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import (
17 from .node import (
18 hex,
18 hex,
19 nullid,
19 nullid,
20 nullrev,
20 nullrev,
21 short,
21 short,
22 )
22 )
23 from . import (
23 from . import (
24 archival,
24 archival,
25 bookmarks,
25 bookmarks,
26 bundle2,
26 bundle2,
27 changegroup,
27 changegroup,
28 cmdutil,
28 cmdutil,
29 copies,
29 copies,
30 debugcommands as debugcommandsmod,
30 debugcommands as debugcommandsmod,
31 destutil,
31 destutil,
32 dirstateguard,
32 dirstateguard,
33 discovery,
33 discovery,
34 encoding,
34 encoding,
35 error,
35 error,
36 exchange,
36 exchange,
37 extensions,
37 extensions,
38 formatter,
38 formatter,
39 graphmod,
39 graphmod,
40 hbisect,
40 hbisect,
41 help,
41 help,
42 hg,
42 hg,
43 lock as lockmod,
43 lock as lockmod,
44 merge as mergemod,
44 merge as mergemod,
45 obsolete,
45 obsolete,
46 patch,
46 patch,
47 phases,
47 phases,
48 pycompat,
48 pycompat,
49 rcutil,
49 rcutil,
50 registrar,
50 registrar,
51 revsetlang,
51 revsetlang,
52 rewriteutil,
52 scmutil,
53 scmutil,
53 server,
54 server,
54 sshserver,
55 sshserver,
55 streamclone,
56 streamclone,
56 tags as tagsmod,
57 tags as tagsmod,
57 templatekw,
58 templatekw,
58 ui as uimod,
59 ui as uimod,
59 util,
60 util,
60 )
61 )
61
62
62 release = lockmod.release
63 release = lockmod.release
63
64
64 table = {}
65 table = {}
65 table.update(debugcommandsmod.command._table)
66 table.update(debugcommandsmod.command._table)
66
67
67 command = registrar.command(table)
68 command = registrar.command(table)
68 readonly = registrar.command.readonly
69 readonly = registrar.command.readonly
69
70
70 # common command options
71 # common command options
71
72
72 globalopts = [
73 globalopts = [
73 ('R', 'repository', '',
74 ('R', 'repository', '',
74 _('repository root directory or name of overlay bundle file'),
75 _('repository root directory or name of overlay bundle file'),
75 _('REPO')),
76 _('REPO')),
76 ('', 'cwd', '',
77 ('', 'cwd', '',
77 _('change working directory'), _('DIR')),
78 _('change working directory'), _('DIR')),
78 ('y', 'noninteractive', None,
79 ('y', 'noninteractive', None,
79 _('do not prompt, automatically pick the first choice for all prompts')),
80 _('do not prompt, automatically pick the first choice for all prompts')),
80 ('q', 'quiet', None, _('suppress output')),
81 ('q', 'quiet', None, _('suppress output')),
81 ('v', 'verbose', None, _('enable additional output')),
82 ('v', 'verbose', None, _('enable additional output')),
82 ('', 'color', '',
83 ('', 'color', '',
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # and should not be translated
85 # and should not be translated
85 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _('TYPE')),
87 _('TYPE')),
87 ('', 'config', [],
88 ('', 'config', [],
88 _('set/override config option (use \'section.name=value\')'),
89 _('set/override config option (use \'section.name=value\')'),
89 _('CONFIG')),
90 _('CONFIG')),
90 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debugger', None, _('start debugger')),
92 ('', 'debugger', None, _('start debugger')),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 _('ENCODE')),
94 _('ENCODE')),
94 ('', 'encodingmode', encoding.encodingmode,
95 ('', 'encodingmode', encoding.encodingmode,
95 _('set the charset encoding mode'), _('MODE')),
96 _('set the charset encoding mode'), _('MODE')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'time', None, _('time how long the command takes')),
98 ('', 'time', None, _('time how long the command takes')),
98 ('', 'profile', None, _('print command execution profile')),
99 ('', 'profile', None, _('print command execution profile')),
99 ('', 'version', None, _('output version information and exit')),
100 ('', 'version', None, _('output version information and exit')),
100 ('h', 'help', None, _('display help and exit')),
101 ('h', 'help', None, _('display help and exit')),
101 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'pager', 'auto',
103 ('', 'pager', 'auto',
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 ]
105 ]
105
106
106 dryrunopts = cmdutil.dryrunopts
107 dryrunopts = cmdutil.dryrunopts
107 remoteopts = cmdutil.remoteopts
108 remoteopts = cmdutil.remoteopts
108 walkopts = cmdutil.walkopts
109 walkopts = cmdutil.walkopts
109 commitopts = cmdutil.commitopts
110 commitopts = cmdutil.commitopts
110 commitopts2 = cmdutil.commitopts2
111 commitopts2 = cmdutil.commitopts2
111 formatteropts = cmdutil.formatteropts
112 formatteropts = cmdutil.formatteropts
112 templateopts = cmdutil.templateopts
113 templateopts = cmdutil.templateopts
113 logopts = cmdutil.logopts
114 logopts = cmdutil.logopts
114 diffopts = cmdutil.diffopts
115 diffopts = cmdutil.diffopts
115 diffwsopts = cmdutil.diffwsopts
116 diffwsopts = cmdutil.diffwsopts
116 diffopts2 = cmdutil.diffopts2
117 diffopts2 = cmdutil.diffopts2
117 mergetoolopts = cmdutil.mergetoolopts
118 mergetoolopts = cmdutil.mergetoolopts
118 similarityopts = cmdutil.similarityopts
119 similarityopts = cmdutil.similarityopts
119 subrepoopts = cmdutil.subrepoopts
120 subrepoopts = cmdutil.subrepoopts
120 debugrevlogopts = cmdutil.debugrevlogopts
121 debugrevlogopts = cmdutil.debugrevlogopts
121
122
122 # Commands start here, listed alphabetically
123 # Commands start here, listed alphabetically
123
124
124 @command('^add',
125 @command('^add',
125 walkopts + subrepoopts + dryrunopts,
126 walkopts + subrepoopts + dryrunopts,
126 _('[OPTION]... [FILE]...'),
127 _('[OPTION]... [FILE]...'),
127 inferrepo=True)
128 inferrepo=True)
128 def add(ui, repo, *pats, **opts):
129 def add(ui, repo, *pats, **opts):
129 """add the specified files on the next commit
130 """add the specified files on the next commit
130
131
131 Schedule files to be version controlled and added to the
132 Schedule files to be version controlled and added to the
132 repository.
133 repository.
133
134
134 The files will be added to the repository at the next commit. To
135 The files will be added to the repository at the next commit. To
135 undo an add before that, see :hg:`forget`.
136 undo an add before that, see :hg:`forget`.
136
137
137 If no names are given, add all files to the repository (except
138 If no names are given, add all files to the repository (except
138 files matching ``.hgignore``).
139 files matching ``.hgignore``).
139
140
140 .. container:: verbose
141 .. container:: verbose
141
142
142 Examples:
143 Examples:
143
144
144 - New (unknown) files are added
145 - New (unknown) files are added
145 automatically by :hg:`add`::
146 automatically by :hg:`add`::
146
147
147 $ ls
148 $ ls
148 foo.c
149 foo.c
149 $ hg status
150 $ hg status
150 ? foo.c
151 ? foo.c
151 $ hg add
152 $ hg add
152 adding foo.c
153 adding foo.c
153 $ hg status
154 $ hg status
154 A foo.c
155 A foo.c
155
156
156 - Specific files to be added can be specified::
157 - Specific files to be added can be specified::
157
158
158 $ ls
159 $ ls
159 bar.c foo.c
160 bar.c foo.c
160 $ hg status
161 $ hg status
161 ? bar.c
162 ? bar.c
162 ? foo.c
163 ? foo.c
163 $ hg add bar.c
164 $ hg add bar.c
164 $ hg status
165 $ hg status
165 A bar.c
166 A bar.c
166 ? foo.c
167 ? foo.c
167
168
168 Returns 0 if all files are successfully added.
169 Returns 0 if all files are successfully added.
169 """
170 """
170
171
171 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
172 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
172 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
173 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
173 return rejected and 1 or 0
174 return rejected and 1 or 0
174
175
175 @command('addremove',
176 @command('addremove',
176 similarityopts + subrepoopts + walkopts + dryrunopts,
177 similarityopts + subrepoopts + walkopts + dryrunopts,
177 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
178 inferrepo=True)
179 inferrepo=True)
179 def addremove(ui, repo, *pats, **opts):
180 def addremove(ui, repo, *pats, **opts):
180 """add all new files, delete all missing files
181 """add all new files, delete all missing files
181
182
182 Add all new files and remove all missing files from the
183 Add all new files and remove all missing files from the
183 repository.
184 repository.
184
185
185 Unless names are given, new files are ignored if they match any of
186 Unless names are given, new files are ignored if they match any of
186 the patterns in ``.hgignore``. As with add, these changes take
187 the patterns in ``.hgignore``. As with add, these changes take
187 effect at the next commit.
188 effect at the next commit.
188
189
189 Use the -s/--similarity option to detect renamed files. This
190 Use the -s/--similarity option to detect renamed files. This
190 option takes a percentage between 0 (disabled) and 100 (files must
191 option takes a percentage between 0 (disabled) and 100 (files must
191 be identical) as its parameter. With a parameter greater than 0,
192 be identical) as its parameter. With a parameter greater than 0,
192 this compares every removed file with every added file and records
193 this compares every removed file with every added file and records
193 those similar enough as renames. Detecting renamed files this way
194 those similar enough as renames. Detecting renamed files this way
194 can be expensive. After using this option, :hg:`status -C` can be
195 can be expensive. After using this option, :hg:`status -C` can be
195 used to check which files were identified as moved or renamed. If
196 used to check which files were identified as moved or renamed. If
196 not specified, -s/--similarity defaults to 100 and only renames of
197 not specified, -s/--similarity defaults to 100 and only renames of
197 identical files are detected.
198 identical files are detected.
198
199
199 .. container:: verbose
200 .. container:: verbose
200
201
201 Examples:
202 Examples:
202
203
203 - A number of files (bar.c and foo.c) are new,
204 - A number of files (bar.c and foo.c) are new,
204 while foobar.c has been removed (without using :hg:`remove`)
205 while foobar.c has been removed (without using :hg:`remove`)
205 from the repository::
206 from the repository::
206
207
207 $ ls
208 $ ls
208 bar.c foo.c
209 bar.c foo.c
209 $ hg status
210 $ hg status
210 ! foobar.c
211 ! foobar.c
211 ? bar.c
212 ? bar.c
212 ? foo.c
213 ? foo.c
213 $ hg addremove
214 $ hg addremove
214 adding bar.c
215 adding bar.c
215 adding foo.c
216 adding foo.c
216 removing foobar.c
217 removing foobar.c
217 $ hg status
218 $ hg status
218 A bar.c
219 A bar.c
219 A foo.c
220 A foo.c
220 R foobar.c
221 R foobar.c
221
222
222 - A file foobar.c was moved to foo.c without using :hg:`rename`.
223 - A file foobar.c was moved to foo.c without using :hg:`rename`.
223 Afterwards, it was edited slightly::
224 Afterwards, it was edited slightly::
224
225
225 $ ls
226 $ ls
226 foo.c
227 foo.c
227 $ hg status
228 $ hg status
228 ! foobar.c
229 ! foobar.c
229 ? foo.c
230 ? foo.c
230 $ hg addremove --similarity 90
231 $ hg addremove --similarity 90
231 removing foobar.c
232 removing foobar.c
232 adding foo.c
233 adding foo.c
233 recording removal of foobar.c as rename to foo.c (94% similar)
234 recording removal of foobar.c as rename to foo.c (94% similar)
234 $ hg status -C
235 $ hg status -C
235 A foo.c
236 A foo.c
236 foobar.c
237 foobar.c
237 R foobar.c
238 R foobar.c
238
239
239 Returns 0 if all files are successfully added.
240 Returns 0 if all files are successfully added.
240 """
241 """
241 opts = pycompat.byteskwargs(opts)
242 opts = pycompat.byteskwargs(opts)
242 try:
243 try:
243 sim = float(opts.get('similarity') or 100)
244 sim = float(opts.get('similarity') or 100)
244 except ValueError:
245 except ValueError:
245 raise error.Abort(_('similarity must be a number'))
246 raise error.Abort(_('similarity must be a number'))
246 if sim < 0 or sim > 100:
247 if sim < 0 or sim > 100:
247 raise error.Abort(_('similarity must be between 0 and 100'))
248 raise error.Abort(_('similarity must be between 0 and 100'))
248 matcher = scmutil.match(repo[None], pats, opts)
249 matcher = scmutil.match(repo[None], pats, opts)
249 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
250 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
250
251
251 @command('^annotate|blame',
252 @command('^annotate|blame',
252 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
253 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
253 ('', 'follow', None,
254 ('', 'follow', None,
254 _('follow copies/renames and list the filename (DEPRECATED)')),
255 _('follow copies/renames and list the filename (DEPRECATED)')),
255 ('', 'no-follow', None, _("don't follow copies and renames")),
256 ('', 'no-follow', None, _("don't follow copies and renames")),
256 ('a', 'text', None, _('treat all files as text')),
257 ('a', 'text', None, _('treat all files as text')),
257 ('u', 'user', None, _('list the author (long with -v)')),
258 ('u', 'user', None, _('list the author (long with -v)')),
258 ('f', 'file', None, _('list the filename')),
259 ('f', 'file', None, _('list the filename')),
259 ('d', 'date', None, _('list the date (short with -q)')),
260 ('d', 'date', None, _('list the date (short with -q)')),
260 ('n', 'number', None, _('list the revision number (default)')),
261 ('n', 'number', None, _('list the revision number (default)')),
261 ('c', 'changeset', None, _('list the changeset')),
262 ('c', 'changeset', None, _('list the changeset')),
262 ('l', 'line-number', None, _('show line number at the first appearance')),
263 ('l', 'line-number', None, _('show line number at the first appearance')),
263 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
264 ('', 'skip', [], _('revision to not display (EXPERIMENTAL)'), _('REV')),
264 ] + diffwsopts + walkopts + formatteropts,
265 ] + diffwsopts + walkopts + formatteropts,
265 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
266 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
266 inferrepo=True)
267 inferrepo=True)
267 def annotate(ui, repo, *pats, **opts):
268 def annotate(ui, repo, *pats, **opts):
268 """show changeset information by line for each file
269 """show changeset information by line for each file
269
270
270 List changes in files, showing the revision id responsible for
271 List changes in files, showing the revision id responsible for
271 each line.
272 each line.
272
273
273 This command is useful for discovering when a change was made and
274 This command is useful for discovering when a change was made and
274 by whom.
275 by whom.
275
276
276 If you include --file, --user, or --date, the revision number is
277 If you include --file, --user, or --date, the revision number is
277 suppressed unless you also include --number.
278 suppressed unless you also include --number.
278
279
279 Without the -a/--text option, annotate will avoid processing files
280 Without the -a/--text option, annotate will avoid processing files
280 it detects as binary. With -a, annotate will annotate the file
281 it detects as binary. With -a, annotate will annotate the file
281 anyway, although the results will probably be neither useful
282 anyway, although the results will probably be neither useful
282 nor desirable.
283 nor desirable.
283
284
284 Returns 0 on success.
285 Returns 0 on success.
285 """
286 """
286 opts = pycompat.byteskwargs(opts)
287 opts = pycompat.byteskwargs(opts)
287 if not pats:
288 if not pats:
288 raise error.Abort(_('at least one filename or pattern is required'))
289 raise error.Abort(_('at least one filename or pattern is required'))
289
290
290 if opts.get('follow'):
291 if opts.get('follow'):
291 # --follow is deprecated and now just an alias for -f/--file
292 # --follow is deprecated and now just an alias for -f/--file
292 # to mimic the behavior of Mercurial before version 1.5
293 # to mimic the behavior of Mercurial before version 1.5
293 opts['file'] = True
294 opts['file'] = True
294
295
295 ctx = scmutil.revsingle(repo, opts.get('rev'))
296 ctx = scmutil.revsingle(repo, opts.get('rev'))
296
297
297 rootfm = ui.formatter('annotate', opts)
298 rootfm = ui.formatter('annotate', opts)
298 if ui.quiet:
299 if ui.quiet:
299 datefunc = util.shortdate
300 datefunc = util.shortdate
300 else:
301 else:
301 datefunc = util.datestr
302 datefunc = util.datestr
302 if ctx.rev() is None:
303 if ctx.rev() is None:
303 def hexfn(node):
304 def hexfn(node):
304 if node is None:
305 if node is None:
305 return None
306 return None
306 else:
307 else:
307 return rootfm.hexfunc(node)
308 return rootfm.hexfunc(node)
308 if opts.get('changeset'):
309 if opts.get('changeset'):
309 # omit "+" suffix which is appended to node hex
310 # omit "+" suffix which is appended to node hex
310 def formatrev(rev):
311 def formatrev(rev):
311 if rev is None:
312 if rev is None:
312 return '%d' % ctx.p1().rev()
313 return '%d' % ctx.p1().rev()
313 else:
314 else:
314 return '%d' % rev
315 return '%d' % rev
315 else:
316 else:
316 def formatrev(rev):
317 def formatrev(rev):
317 if rev is None:
318 if rev is None:
318 return '%d+' % ctx.p1().rev()
319 return '%d+' % ctx.p1().rev()
319 else:
320 else:
320 return '%d ' % rev
321 return '%d ' % rev
321 def formathex(hex):
322 def formathex(hex):
322 if hex is None:
323 if hex is None:
323 return '%s+' % rootfm.hexfunc(ctx.p1().node())
324 return '%s+' % rootfm.hexfunc(ctx.p1().node())
324 else:
325 else:
325 return '%s ' % hex
326 return '%s ' % hex
326 else:
327 else:
327 hexfn = rootfm.hexfunc
328 hexfn = rootfm.hexfunc
328 formatrev = formathex = pycompat.bytestr
329 formatrev = formathex = pycompat.bytestr
329
330
330 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
331 opmap = [('user', ' ', lambda x: x.fctx.user(), ui.shortuser),
331 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
332 ('number', ' ', lambda x: x.fctx.rev(), formatrev),
332 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
333 ('changeset', ' ', lambda x: hexfn(x.fctx.node()), formathex),
333 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
334 ('date', ' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
334 ('file', ' ', lambda x: x.fctx.path(), str),
335 ('file', ' ', lambda x: x.fctx.path(), str),
335 ('line_number', ':', lambda x: x.lineno, str),
336 ('line_number', ':', lambda x: x.lineno, str),
336 ]
337 ]
337 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
338 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
338
339
339 if (not opts.get('user') and not opts.get('changeset')
340 if (not opts.get('user') and not opts.get('changeset')
340 and not opts.get('date') and not opts.get('file')):
341 and not opts.get('date') and not opts.get('file')):
341 opts['number'] = True
342 opts['number'] = True
342
343
343 linenumber = opts.get('line_number') is not None
344 linenumber = opts.get('line_number') is not None
344 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
345 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
345 raise error.Abort(_('at least one of -n/-c is required for -l'))
346 raise error.Abort(_('at least one of -n/-c is required for -l'))
346
347
347 ui.pager('annotate')
348 ui.pager('annotate')
348
349
349 if rootfm.isplain():
350 if rootfm.isplain():
350 def makefunc(get, fmt):
351 def makefunc(get, fmt):
351 return lambda x: fmt(get(x))
352 return lambda x: fmt(get(x))
352 else:
353 else:
353 def makefunc(get, fmt):
354 def makefunc(get, fmt):
354 return get
355 return get
355 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
356 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
356 if opts.get(op)]
357 if opts.get(op)]
357 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
358 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
358 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
359 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
359 if opts.get(op))
360 if opts.get(op))
360
361
361 def bad(x, y):
362 def bad(x, y):
362 raise error.Abort("%s: %s" % (x, y))
363 raise error.Abort("%s: %s" % (x, y))
363
364
364 m = scmutil.match(ctx, pats, opts, badfn=bad)
365 m = scmutil.match(ctx, pats, opts, badfn=bad)
365
366
366 follow = not opts.get('no_follow')
367 follow = not opts.get('no_follow')
367 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
368 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
368 whitespace=True)
369 whitespace=True)
369 skiprevs = opts.get('skip')
370 skiprevs = opts.get('skip')
370 if skiprevs:
371 if skiprevs:
371 skiprevs = scmutil.revrange(repo, skiprevs)
372 skiprevs = scmutil.revrange(repo, skiprevs)
372
373
373 for abs in ctx.walk(m):
374 for abs in ctx.walk(m):
374 fctx = ctx[abs]
375 fctx = ctx[abs]
375 rootfm.startitem()
376 rootfm.startitem()
376 rootfm.data(abspath=abs, path=m.rel(abs))
377 rootfm.data(abspath=abs, path=m.rel(abs))
377 if not opts.get('text') and fctx.isbinary():
378 if not opts.get('text') and fctx.isbinary():
378 rootfm.plain(_("%s: binary file\n")
379 rootfm.plain(_("%s: binary file\n")
379 % ((pats and m.rel(abs)) or abs))
380 % ((pats and m.rel(abs)) or abs))
380 continue
381 continue
381
382
382 fm = rootfm.nested('lines')
383 fm = rootfm.nested('lines')
383 lines = fctx.annotate(follow=follow, linenumber=linenumber,
384 lines = fctx.annotate(follow=follow, linenumber=linenumber,
384 skiprevs=skiprevs, diffopts=diffopts)
385 skiprevs=skiprevs, diffopts=diffopts)
385 if not lines:
386 if not lines:
386 fm.end()
387 fm.end()
387 continue
388 continue
388 formats = []
389 formats = []
389 pieces = []
390 pieces = []
390
391
391 for f, sep in funcmap:
392 for f, sep in funcmap:
392 l = [f(n) for n, dummy in lines]
393 l = [f(n) for n, dummy in lines]
393 if fm.isplain():
394 if fm.isplain():
394 sizes = [encoding.colwidth(x) for x in l]
395 sizes = [encoding.colwidth(x) for x in l]
395 ml = max(sizes)
396 ml = max(sizes)
396 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
397 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
397 else:
398 else:
398 formats.append(['%s' for x in l])
399 formats.append(['%s' for x in l])
399 pieces.append(l)
400 pieces.append(l)
400
401
401 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
402 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
402 fm.startitem()
403 fm.startitem()
403 fm.write(fields, "".join(f), *p)
404 fm.write(fields, "".join(f), *p)
404 if l[0].skip:
405 if l[0].skip:
405 fmt = "* %s"
406 fmt = "* %s"
406 else:
407 else:
407 fmt = ": %s"
408 fmt = ": %s"
408 fm.write('line', fmt, l[1])
409 fm.write('line', fmt, l[1])
409
410
410 if not lines[-1][1].endswith('\n'):
411 if not lines[-1][1].endswith('\n'):
411 fm.plain('\n')
412 fm.plain('\n')
412 fm.end()
413 fm.end()
413
414
414 rootfm.end()
415 rootfm.end()
415
416
416 @command('archive',
417 @command('archive',
417 [('', 'no-decode', None, _('do not pass files through decoders')),
418 [('', 'no-decode', None, _('do not pass files through decoders')),
418 ('p', 'prefix', '', _('directory prefix for files in archive'),
419 ('p', 'prefix', '', _('directory prefix for files in archive'),
419 _('PREFIX')),
420 _('PREFIX')),
420 ('r', 'rev', '', _('revision to distribute'), _('REV')),
421 ('r', 'rev', '', _('revision to distribute'), _('REV')),
421 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
422 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
422 ] + subrepoopts + walkopts,
423 ] + subrepoopts + walkopts,
423 _('[OPTION]... DEST'))
424 _('[OPTION]... DEST'))
424 def archive(ui, repo, dest, **opts):
425 def archive(ui, repo, dest, **opts):
425 '''create an unversioned archive of a repository revision
426 '''create an unversioned archive of a repository revision
426
427
427 By default, the revision used is the parent of the working
428 By default, the revision used is the parent of the working
428 directory; use -r/--rev to specify a different revision.
429 directory; use -r/--rev to specify a different revision.
429
430
430 The archive type is automatically detected based on file
431 The archive type is automatically detected based on file
431 extension (to override, use -t/--type).
432 extension (to override, use -t/--type).
432
433
433 .. container:: verbose
434 .. container:: verbose
434
435
435 Examples:
436 Examples:
436
437
437 - create a zip file containing the 1.0 release::
438 - create a zip file containing the 1.0 release::
438
439
439 hg archive -r 1.0 project-1.0.zip
440 hg archive -r 1.0 project-1.0.zip
440
441
441 - create a tarball excluding .hg files::
442 - create a tarball excluding .hg files::
442
443
443 hg archive project.tar.gz -X ".hg*"
444 hg archive project.tar.gz -X ".hg*"
444
445
445 Valid types are:
446 Valid types are:
446
447
447 :``files``: a directory full of files (default)
448 :``files``: a directory full of files (default)
448 :``tar``: tar archive, uncompressed
449 :``tar``: tar archive, uncompressed
449 :``tbz2``: tar archive, compressed using bzip2
450 :``tbz2``: tar archive, compressed using bzip2
450 :``tgz``: tar archive, compressed using gzip
451 :``tgz``: tar archive, compressed using gzip
451 :``uzip``: zip archive, uncompressed
452 :``uzip``: zip archive, uncompressed
452 :``zip``: zip archive, compressed using deflate
453 :``zip``: zip archive, compressed using deflate
453
454
454 The exact name of the destination archive or directory is given
455 The exact name of the destination archive or directory is given
455 using a format string; see :hg:`help export` for details.
456 using a format string; see :hg:`help export` for details.
456
457
457 Each member added to an archive file has a directory prefix
458 Each member added to an archive file has a directory prefix
458 prepended. Use -p/--prefix to specify a format string for the
459 prepended. Use -p/--prefix to specify a format string for the
459 prefix. The default is the basename of the archive, with suffixes
460 prefix. The default is the basename of the archive, with suffixes
460 removed.
461 removed.
461
462
462 Returns 0 on success.
463 Returns 0 on success.
463 '''
464 '''
464
465
465 opts = pycompat.byteskwargs(opts)
466 opts = pycompat.byteskwargs(opts)
466 ctx = scmutil.revsingle(repo, opts.get('rev'))
467 ctx = scmutil.revsingle(repo, opts.get('rev'))
467 if not ctx:
468 if not ctx:
468 raise error.Abort(_('no working directory: please specify a revision'))
469 raise error.Abort(_('no working directory: please specify a revision'))
469 node = ctx.node()
470 node = ctx.node()
470 dest = cmdutil.makefilename(repo, dest, node)
471 dest = cmdutil.makefilename(repo, dest, node)
471 if os.path.realpath(dest) == repo.root:
472 if os.path.realpath(dest) == repo.root:
472 raise error.Abort(_('repository root cannot be destination'))
473 raise error.Abort(_('repository root cannot be destination'))
473
474
474 kind = opts.get('type') or archival.guesskind(dest) or 'files'
475 kind = opts.get('type') or archival.guesskind(dest) or 'files'
475 prefix = opts.get('prefix')
476 prefix = opts.get('prefix')
476
477
477 if dest == '-':
478 if dest == '-':
478 if kind == 'files':
479 if kind == 'files':
479 raise error.Abort(_('cannot archive plain files to stdout'))
480 raise error.Abort(_('cannot archive plain files to stdout'))
480 dest = cmdutil.makefileobj(repo, dest)
481 dest = cmdutil.makefileobj(repo, dest)
481 if not prefix:
482 if not prefix:
482 prefix = os.path.basename(repo.root) + '-%h'
483 prefix = os.path.basename(repo.root) + '-%h'
483
484
484 prefix = cmdutil.makefilename(repo, prefix, node)
485 prefix = cmdutil.makefilename(repo, prefix, node)
485 match = scmutil.match(ctx, [], opts)
486 match = scmutil.match(ctx, [], opts)
486 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
487 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
487 match, prefix, subrepos=opts.get('subrepos'))
488 match, prefix, subrepos=opts.get('subrepos'))
488
489
489 @command('backout',
490 @command('backout',
490 [('', 'merge', None, _('merge with old dirstate parent after backout')),
491 [('', 'merge', None, _('merge with old dirstate parent after backout')),
491 ('', 'commit', None,
492 ('', 'commit', None,
492 _('commit if no conflicts were encountered (DEPRECATED)')),
493 _('commit if no conflicts were encountered (DEPRECATED)')),
493 ('', 'no-commit', None, _('do not commit')),
494 ('', 'no-commit', None, _('do not commit')),
494 ('', 'parent', '',
495 ('', 'parent', '',
495 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
496 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
496 ('r', 'rev', '', _('revision to backout'), _('REV')),
497 ('r', 'rev', '', _('revision to backout'), _('REV')),
497 ('e', 'edit', False, _('invoke editor on commit messages')),
498 ('e', 'edit', False, _('invoke editor on commit messages')),
498 ] + mergetoolopts + walkopts + commitopts + commitopts2,
499 ] + mergetoolopts + walkopts + commitopts + commitopts2,
499 _('[OPTION]... [-r] REV'))
500 _('[OPTION]... [-r] REV'))
500 def backout(ui, repo, node=None, rev=None, **opts):
501 def backout(ui, repo, node=None, rev=None, **opts):
501 '''reverse effect of earlier changeset
502 '''reverse effect of earlier changeset
502
503
503 Prepare a new changeset with the effect of REV undone in the
504 Prepare a new changeset with the effect of REV undone in the
504 current working directory. If no conflicts were encountered,
505 current working directory. If no conflicts were encountered,
505 it will be committed immediately.
506 it will be committed immediately.
506
507
507 If REV is the parent of the working directory, then this new changeset
508 If REV is the parent of the working directory, then this new changeset
508 is committed automatically (unless --no-commit is specified).
509 is committed automatically (unless --no-commit is specified).
509
510
510 .. note::
511 .. note::
511
512
512 :hg:`backout` cannot be used to fix either an unwanted or
513 :hg:`backout` cannot be used to fix either an unwanted or
513 incorrect merge.
514 incorrect merge.
514
515
515 .. container:: verbose
516 .. container:: verbose
516
517
517 Examples:
518 Examples:
518
519
519 - Reverse the effect of the parent of the working directory.
520 - Reverse the effect of the parent of the working directory.
520 This backout will be committed immediately::
521 This backout will be committed immediately::
521
522
522 hg backout -r .
523 hg backout -r .
523
524
524 - Reverse the effect of previous bad revision 23::
525 - Reverse the effect of previous bad revision 23::
525
526
526 hg backout -r 23
527 hg backout -r 23
527
528
528 - Reverse the effect of previous bad revision 23 and
529 - Reverse the effect of previous bad revision 23 and
529 leave changes uncommitted::
530 leave changes uncommitted::
530
531
531 hg backout -r 23 --no-commit
532 hg backout -r 23 --no-commit
532 hg commit -m "Backout revision 23"
533 hg commit -m "Backout revision 23"
533
534
534 By default, the pending changeset will have one parent,
535 By default, the pending changeset will have one parent,
535 maintaining a linear history. With --merge, the pending
536 maintaining a linear history. With --merge, the pending
536 changeset will instead have two parents: the old parent of the
537 changeset will instead have two parents: the old parent of the
537 working directory and a new child of REV that simply undoes REV.
538 working directory and a new child of REV that simply undoes REV.
538
539
539 Before version 1.7, the behavior without --merge was equivalent
540 Before version 1.7, the behavior without --merge was equivalent
540 to specifying --merge followed by :hg:`update --clean .` to
541 to specifying --merge followed by :hg:`update --clean .` to
541 cancel the merge and leave the child of REV as a head to be
542 cancel the merge and leave the child of REV as a head to be
542 merged separately.
543 merged separately.
543
544
544 See :hg:`help dates` for a list of formats valid for -d/--date.
545 See :hg:`help dates` for a list of formats valid for -d/--date.
545
546
546 See :hg:`help revert` for a way to restore files to the state
547 See :hg:`help revert` for a way to restore files to the state
547 of another revision.
548 of another revision.
548
549
549 Returns 0 on success, 1 if nothing to backout or there are unresolved
550 Returns 0 on success, 1 if nothing to backout or there are unresolved
550 files.
551 files.
551 '''
552 '''
552 wlock = lock = None
553 wlock = lock = None
553 try:
554 try:
554 wlock = repo.wlock()
555 wlock = repo.wlock()
555 lock = repo.lock()
556 lock = repo.lock()
556 return _dobackout(ui, repo, node, rev, **opts)
557 return _dobackout(ui, repo, node, rev, **opts)
557 finally:
558 finally:
558 release(lock, wlock)
559 release(lock, wlock)
559
560
560 def _dobackout(ui, repo, node=None, rev=None, **opts):
561 def _dobackout(ui, repo, node=None, rev=None, **opts):
561 opts = pycompat.byteskwargs(opts)
562 opts = pycompat.byteskwargs(opts)
562 if opts.get('commit') and opts.get('no_commit'):
563 if opts.get('commit') and opts.get('no_commit'):
563 raise error.Abort(_("cannot use --commit with --no-commit"))
564 raise error.Abort(_("cannot use --commit with --no-commit"))
564 if opts.get('merge') and opts.get('no_commit'):
565 if opts.get('merge') and opts.get('no_commit'):
565 raise error.Abort(_("cannot use --merge with --no-commit"))
566 raise error.Abort(_("cannot use --merge with --no-commit"))
566
567
567 if rev and node:
568 if rev and node:
568 raise error.Abort(_("please specify just one revision"))
569 raise error.Abort(_("please specify just one revision"))
569
570
570 if not rev:
571 if not rev:
571 rev = node
572 rev = node
572
573
573 if not rev:
574 if not rev:
574 raise error.Abort(_("please specify a revision to backout"))
575 raise error.Abort(_("please specify a revision to backout"))
575
576
576 date = opts.get('date')
577 date = opts.get('date')
577 if date:
578 if date:
578 opts['date'] = util.parsedate(date)
579 opts['date'] = util.parsedate(date)
579
580
580 cmdutil.checkunfinished(repo)
581 cmdutil.checkunfinished(repo)
581 cmdutil.bailifchanged(repo)
582 cmdutil.bailifchanged(repo)
582 node = scmutil.revsingle(repo, rev).node()
583 node = scmutil.revsingle(repo, rev).node()
583
584
584 op1, op2 = repo.dirstate.parents()
585 op1, op2 = repo.dirstate.parents()
585 if not repo.changelog.isancestor(node, op1):
586 if not repo.changelog.isancestor(node, op1):
586 raise error.Abort(_('cannot backout change that is not an ancestor'))
587 raise error.Abort(_('cannot backout change that is not an ancestor'))
587
588
588 p1, p2 = repo.changelog.parents(node)
589 p1, p2 = repo.changelog.parents(node)
589 if p1 == nullid:
590 if p1 == nullid:
590 raise error.Abort(_('cannot backout a change with no parents'))
591 raise error.Abort(_('cannot backout a change with no parents'))
591 if p2 != nullid:
592 if p2 != nullid:
592 if not opts.get('parent'):
593 if not opts.get('parent'):
593 raise error.Abort(_('cannot backout a merge changeset'))
594 raise error.Abort(_('cannot backout a merge changeset'))
594 p = repo.lookup(opts['parent'])
595 p = repo.lookup(opts['parent'])
595 if p not in (p1, p2):
596 if p not in (p1, p2):
596 raise error.Abort(_('%s is not a parent of %s') %
597 raise error.Abort(_('%s is not a parent of %s') %
597 (short(p), short(node)))
598 (short(p), short(node)))
598 parent = p
599 parent = p
599 else:
600 else:
600 if opts.get('parent'):
601 if opts.get('parent'):
601 raise error.Abort(_('cannot use --parent on non-merge changeset'))
602 raise error.Abort(_('cannot use --parent on non-merge changeset'))
602 parent = p1
603 parent = p1
603
604
604 # the backout should appear on the same branch
605 # the backout should appear on the same branch
605 branch = repo.dirstate.branch()
606 branch = repo.dirstate.branch()
606 bheads = repo.branchheads(branch)
607 bheads = repo.branchheads(branch)
607 rctx = scmutil.revsingle(repo, hex(parent))
608 rctx = scmutil.revsingle(repo, hex(parent))
608 if not opts.get('merge') and op1 != node:
609 if not opts.get('merge') and op1 != node:
609 dsguard = dirstateguard.dirstateguard(repo, 'backout')
610 dsguard = dirstateguard.dirstateguard(repo, 'backout')
610 try:
611 try:
611 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
612 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
612 'backout')
613 'backout')
613 stats = mergemod.update(repo, parent, True, True, node, False)
614 stats = mergemod.update(repo, parent, True, True, node, False)
614 repo.setparents(op1, op2)
615 repo.setparents(op1, op2)
615 dsguard.close()
616 dsguard.close()
616 hg._showstats(repo, stats)
617 hg._showstats(repo, stats)
617 if stats[3]:
618 if stats[3]:
618 repo.ui.status(_("use 'hg resolve' to retry unresolved "
619 repo.ui.status(_("use 'hg resolve' to retry unresolved "
619 "file merges\n"))
620 "file merges\n"))
620 return 1
621 return 1
621 finally:
622 finally:
622 ui.setconfig('ui', 'forcemerge', '', '')
623 ui.setconfig('ui', 'forcemerge', '', '')
623 lockmod.release(dsguard)
624 lockmod.release(dsguard)
624 else:
625 else:
625 hg.clean(repo, node, show_stats=False)
626 hg.clean(repo, node, show_stats=False)
626 repo.dirstate.setbranch(branch)
627 repo.dirstate.setbranch(branch)
627 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
628 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
628
629
629 if opts.get('no_commit'):
630 if opts.get('no_commit'):
630 msg = _("changeset %s backed out, "
631 msg = _("changeset %s backed out, "
631 "don't forget to commit.\n")
632 "don't forget to commit.\n")
632 ui.status(msg % short(node))
633 ui.status(msg % short(node))
633 return 0
634 return 0
634
635
635 def commitfunc(ui, repo, message, match, opts):
636 def commitfunc(ui, repo, message, match, opts):
636 editform = 'backout'
637 editform = 'backout'
637 e = cmdutil.getcommiteditor(editform=editform,
638 e = cmdutil.getcommiteditor(editform=editform,
638 **pycompat.strkwargs(opts))
639 **pycompat.strkwargs(opts))
639 if not message:
640 if not message:
640 # we don't translate commit messages
641 # we don't translate commit messages
641 message = "Backed out changeset %s" % short(node)
642 message = "Backed out changeset %s" % short(node)
642 e = cmdutil.getcommiteditor(edit=True, editform=editform)
643 e = cmdutil.getcommiteditor(edit=True, editform=editform)
643 return repo.commit(message, opts.get('user'), opts.get('date'),
644 return repo.commit(message, opts.get('user'), opts.get('date'),
644 match, editor=e)
645 match, editor=e)
645 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
646 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
646 if not newnode:
647 if not newnode:
647 ui.status(_("nothing changed\n"))
648 ui.status(_("nothing changed\n"))
648 return 1
649 return 1
649 cmdutil.commitstatus(repo, newnode, branch, bheads)
650 cmdutil.commitstatus(repo, newnode, branch, bheads)
650
651
651 def nice(node):
652 def nice(node):
652 return '%d:%s' % (repo.changelog.rev(node), short(node))
653 return '%d:%s' % (repo.changelog.rev(node), short(node))
653 ui.status(_('changeset %s backs out changeset %s\n') %
654 ui.status(_('changeset %s backs out changeset %s\n') %
654 (nice(repo.changelog.tip()), nice(node)))
655 (nice(repo.changelog.tip()), nice(node)))
655 if opts.get('merge') and op1 != node:
656 if opts.get('merge') and op1 != node:
656 hg.clean(repo, op1, show_stats=False)
657 hg.clean(repo, op1, show_stats=False)
657 ui.status(_('merging with changeset %s\n')
658 ui.status(_('merging with changeset %s\n')
658 % nice(repo.changelog.tip()))
659 % nice(repo.changelog.tip()))
659 try:
660 try:
660 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
661 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
661 'backout')
662 'backout')
662 return hg.merge(repo, hex(repo.changelog.tip()))
663 return hg.merge(repo, hex(repo.changelog.tip()))
663 finally:
664 finally:
664 ui.setconfig('ui', 'forcemerge', '', '')
665 ui.setconfig('ui', 'forcemerge', '', '')
665 return 0
666 return 0
666
667
667 @command('bisect',
668 @command('bisect',
668 [('r', 'reset', False, _('reset bisect state')),
669 [('r', 'reset', False, _('reset bisect state')),
669 ('g', 'good', False, _('mark changeset good')),
670 ('g', 'good', False, _('mark changeset good')),
670 ('b', 'bad', False, _('mark changeset bad')),
671 ('b', 'bad', False, _('mark changeset bad')),
671 ('s', 'skip', False, _('skip testing changeset')),
672 ('s', 'skip', False, _('skip testing changeset')),
672 ('e', 'extend', False, _('extend the bisect range')),
673 ('e', 'extend', False, _('extend the bisect range')),
673 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
674 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
674 ('U', 'noupdate', False, _('do not update to target'))],
675 ('U', 'noupdate', False, _('do not update to target'))],
675 _("[-gbsr] [-U] [-c CMD] [REV]"))
676 _("[-gbsr] [-U] [-c CMD] [REV]"))
676 def bisect(ui, repo, rev=None, extra=None, command=None,
677 def bisect(ui, repo, rev=None, extra=None, command=None,
677 reset=None, good=None, bad=None, skip=None, extend=None,
678 reset=None, good=None, bad=None, skip=None, extend=None,
678 noupdate=None):
679 noupdate=None):
679 """subdivision search of changesets
680 """subdivision search of changesets
680
681
681 This command helps to find changesets which introduce problems. To
682 This command helps to find changesets which introduce problems. To
682 use, mark the earliest changeset you know exhibits the problem as
683 use, mark the earliest changeset you know exhibits the problem as
683 bad, then mark the latest changeset which is free from the problem
684 bad, then mark the latest changeset which is free from the problem
684 as good. Bisect will update your working directory to a revision
685 as good. Bisect will update your working directory to a revision
685 for testing (unless the -U/--noupdate option is specified). Once
686 for testing (unless the -U/--noupdate option is specified). Once
686 you have performed tests, mark the working directory as good or
687 you have performed tests, mark the working directory as good or
687 bad, and bisect will either update to another candidate changeset
688 bad, and bisect will either update to another candidate changeset
688 or announce that it has found the bad revision.
689 or announce that it has found the bad revision.
689
690
690 As a shortcut, you can also use the revision argument to mark a
691 As a shortcut, you can also use the revision argument to mark a
691 revision as good or bad without checking it out first.
692 revision as good or bad without checking it out first.
692
693
693 If you supply a command, it will be used for automatic bisection.
694 If you supply a command, it will be used for automatic bisection.
694 The environment variable HG_NODE will contain the ID of the
695 The environment variable HG_NODE will contain the ID of the
695 changeset being tested. The exit status of the command will be
696 changeset being tested. The exit status of the command will be
696 used to mark revisions as good or bad: status 0 means good, 125
697 used to mark revisions as good or bad: status 0 means good, 125
697 means to skip the revision, 127 (command not found) will abort the
698 means to skip the revision, 127 (command not found) will abort the
698 bisection, and any other non-zero exit status means the revision
699 bisection, and any other non-zero exit status means the revision
699 is bad.
700 is bad.
700
701
701 .. container:: verbose
702 .. container:: verbose
702
703
703 Some examples:
704 Some examples:
704
705
705 - start a bisection with known bad revision 34, and good revision 12::
706 - start a bisection with known bad revision 34, and good revision 12::
706
707
707 hg bisect --bad 34
708 hg bisect --bad 34
708 hg bisect --good 12
709 hg bisect --good 12
709
710
710 - advance the current bisection by marking current revision as good or
711 - advance the current bisection by marking current revision as good or
711 bad::
712 bad::
712
713
713 hg bisect --good
714 hg bisect --good
714 hg bisect --bad
715 hg bisect --bad
715
716
716 - mark the current revision, or a known revision, to be skipped (e.g. if
717 - mark the current revision, or a known revision, to be skipped (e.g. if
717 that revision is not usable because of another issue)::
718 that revision is not usable because of another issue)::
718
719
719 hg bisect --skip
720 hg bisect --skip
720 hg bisect --skip 23
721 hg bisect --skip 23
721
722
722 - skip all revisions that do not touch directories ``foo`` or ``bar``::
723 - skip all revisions that do not touch directories ``foo`` or ``bar``::
723
724
724 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
725 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
725
726
726 - forget the current bisection::
727 - forget the current bisection::
727
728
728 hg bisect --reset
729 hg bisect --reset
729
730
730 - use 'make && make tests' to automatically find the first broken
731 - use 'make && make tests' to automatically find the first broken
731 revision::
732 revision::
732
733
733 hg bisect --reset
734 hg bisect --reset
734 hg bisect --bad 34
735 hg bisect --bad 34
735 hg bisect --good 12
736 hg bisect --good 12
736 hg bisect --command "make && make tests"
737 hg bisect --command "make && make tests"
737
738
738 - see all changesets whose states are already known in the current
739 - see all changesets whose states are already known in the current
739 bisection::
740 bisection::
740
741
741 hg log -r "bisect(pruned)"
742 hg log -r "bisect(pruned)"
742
743
743 - see the changeset currently being bisected (especially useful
744 - see the changeset currently being bisected (especially useful
744 if running with -U/--noupdate)::
745 if running with -U/--noupdate)::
745
746
746 hg log -r "bisect(current)"
747 hg log -r "bisect(current)"
747
748
748 - see all changesets that took part in the current bisection::
749 - see all changesets that took part in the current bisection::
749
750
750 hg log -r "bisect(range)"
751 hg log -r "bisect(range)"
751
752
752 - you can even get a nice graph::
753 - you can even get a nice graph::
753
754
754 hg log --graph -r "bisect(range)"
755 hg log --graph -r "bisect(range)"
755
756
756 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
757 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
757
758
758 Returns 0 on success.
759 Returns 0 on success.
759 """
760 """
760 # backward compatibility
761 # backward compatibility
761 if rev in "good bad reset init".split():
762 if rev in "good bad reset init".split():
762 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
763 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
763 cmd, rev, extra = rev, extra, None
764 cmd, rev, extra = rev, extra, None
764 if cmd == "good":
765 if cmd == "good":
765 good = True
766 good = True
766 elif cmd == "bad":
767 elif cmd == "bad":
767 bad = True
768 bad = True
768 else:
769 else:
769 reset = True
770 reset = True
770 elif extra:
771 elif extra:
771 raise error.Abort(_('incompatible arguments'))
772 raise error.Abort(_('incompatible arguments'))
772
773
773 incompatibles = {
774 incompatibles = {
774 '--bad': bad,
775 '--bad': bad,
775 '--command': bool(command),
776 '--command': bool(command),
776 '--extend': extend,
777 '--extend': extend,
777 '--good': good,
778 '--good': good,
778 '--reset': reset,
779 '--reset': reset,
779 '--skip': skip,
780 '--skip': skip,
780 }
781 }
781
782
782 enabled = [x for x in incompatibles if incompatibles[x]]
783 enabled = [x for x in incompatibles if incompatibles[x]]
783
784
784 if len(enabled) > 1:
785 if len(enabled) > 1:
785 raise error.Abort(_('%s and %s are incompatible') %
786 raise error.Abort(_('%s and %s are incompatible') %
786 tuple(sorted(enabled)[0:2]))
787 tuple(sorted(enabled)[0:2]))
787
788
788 if reset:
789 if reset:
789 hbisect.resetstate(repo)
790 hbisect.resetstate(repo)
790 return
791 return
791
792
792 state = hbisect.load_state(repo)
793 state = hbisect.load_state(repo)
793
794
794 # update state
795 # update state
795 if good or bad or skip:
796 if good or bad or skip:
796 if rev:
797 if rev:
797 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
798 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
798 else:
799 else:
799 nodes = [repo.lookup('.')]
800 nodes = [repo.lookup('.')]
800 if good:
801 if good:
801 state['good'] += nodes
802 state['good'] += nodes
802 elif bad:
803 elif bad:
803 state['bad'] += nodes
804 state['bad'] += nodes
804 elif skip:
805 elif skip:
805 state['skip'] += nodes
806 state['skip'] += nodes
806 hbisect.save_state(repo, state)
807 hbisect.save_state(repo, state)
807 if not (state['good'] and state['bad']):
808 if not (state['good'] and state['bad']):
808 return
809 return
809
810
810 def mayupdate(repo, node, show_stats=True):
811 def mayupdate(repo, node, show_stats=True):
811 """common used update sequence"""
812 """common used update sequence"""
812 if noupdate:
813 if noupdate:
813 return
814 return
814 cmdutil.checkunfinished(repo)
815 cmdutil.checkunfinished(repo)
815 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
816 return hg.clean(repo, node, show_stats=show_stats)
817 return hg.clean(repo, node, show_stats=show_stats)
817
818
818 displayer = cmdutil.show_changeset(ui, repo, {})
819 displayer = cmdutil.show_changeset(ui, repo, {})
819
820
820 if command:
821 if command:
821 changesets = 1
822 changesets = 1
822 if noupdate:
823 if noupdate:
823 try:
824 try:
824 node = state['current'][0]
825 node = state['current'][0]
825 except LookupError:
826 except LookupError:
826 raise error.Abort(_('current bisect revision is unknown - '
827 raise error.Abort(_('current bisect revision is unknown - '
827 'start a new bisect to fix'))
828 'start a new bisect to fix'))
828 else:
829 else:
829 node, p2 = repo.dirstate.parents()
830 node, p2 = repo.dirstate.parents()
830 if p2 != nullid:
831 if p2 != nullid:
831 raise error.Abort(_('current bisect revision is a merge'))
832 raise error.Abort(_('current bisect revision is a merge'))
832 if rev:
833 if rev:
833 node = repo[scmutil.revsingle(repo, rev, node)].node()
834 node = repo[scmutil.revsingle(repo, rev, node)].node()
834 try:
835 try:
835 while changesets:
836 while changesets:
836 # update state
837 # update state
837 state['current'] = [node]
838 state['current'] = [node]
838 hbisect.save_state(repo, state)
839 hbisect.save_state(repo, state)
839 status = ui.system(command, environ={'HG_NODE': hex(node)},
840 status = ui.system(command, environ={'HG_NODE': hex(node)},
840 blockedtag='bisect_check')
841 blockedtag='bisect_check')
841 if status == 125:
842 if status == 125:
842 transition = "skip"
843 transition = "skip"
843 elif status == 0:
844 elif status == 0:
844 transition = "good"
845 transition = "good"
845 # status < 0 means process was killed
846 # status < 0 means process was killed
846 elif status == 127:
847 elif status == 127:
847 raise error.Abort(_("failed to execute %s") % command)
848 raise error.Abort(_("failed to execute %s") % command)
848 elif status < 0:
849 elif status < 0:
849 raise error.Abort(_("%s killed") % command)
850 raise error.Abort(_("%s killed") % command)
850 else:
851 else:
851 transition = "bad"
852 transition = "bad"
852 state[transition].append(node)
853 state[transition].append(node)
853 ctx = repo[node]
854 ctx = repo[node]
854 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
855 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
855 hbisect.checkstate(state)
856 hbisect.checkstate(state)
856 # bisect
857 # bisect
857 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 nodes, changesets, bgood = hbisect.bisect(repo, state)
858 # update to next check
859 # update to next check
859 node = nodes[0]
860 node = nodes[0]
860 mayupdate(repo, node, show_stats=False)
861 mayupdate(repo, node, show_stats=False)
861 finally:
862 finally:
862 state['current'] = [node]
863 state['current'] = [node]
863 hbisect.save_state(repo, state)
864 hbisect.save_state(repo, state)
864 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
865 return
866 return
866
867
867 hbisect.checkstate(state)
868 hbisect.checkstate(state)
868
869
869 # actually bisect
870 # actually bisect
870 nodes, changesets, good = hbisect.bisect(repo, state)
871 nodes, changesets, good = hbisect.bisect(repo, state)
871 if extend:
872 if extend:
872 if not changesets:
873 if not changesets:
873 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 extendnode = hbisect.extendrange(repo, state, nodes, good)
874 if extendnode is not None:
875 if extendnode is not None:
875 ui.write(_("Extending search to changeset %d:%s\n")
876 ui.write(_("Extending search to changeset %d:%s\n")
876 % (extendnode.rev(), extendnode))
877 % (extendnode.rev(), extendnode))
877 state['current'] = [extendnode.node()]
878 state['current'] = [extendnode.node()]
878 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
879 return mayupdate(repo, extendnode.node())
880 return mayupdate(repo, extendnode.node())
880 raise error.Abort(_("nothing to extend"))
881 raise error.Abort(_("nothing to extend"))
881
882
882 if changesets == 0:
883 if changesets == 0:
883 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 hbisect.printresult(ui, repo, state, displayer, nodes, good)
884 else:
885 else:
885 assert len(nodes) == 1 # only a single node can be tested next
886 assert len(nodes) == 1 # only a single node can be tested next
886 node = nodes[0]
887 node = nodes[0]
887 # compute the approximate number of remaining tests
888 # compute the approximate number of remaining tests
888 tests, size = 0, 2
889 tests, size = 0, 2
889 while size <= changesets:
890 while size <= changesets:
890 tests, size = tests + 1, size * 2
891 tests, size = tests + 1, size * 2
891 rev = repo.changelog.rev(node)
892 rev = repo.changelog.rev(node)
892 ui.write(_("Testing changeset %d:%s "
893 ui.write(_("Testing changeset %d:%s "
893 "(%d changesets remaining, ~%d tests)\n")
894 "(%d changesets remaining, ~%d tests)\n")
894 % (rev, short(node), changesets, tests))
895 % (rev, short(node), changesets, tests))
895 state['current'] = [node]
896 state['current'] = [node]
896 hbisect.save_state(repo, state)
897 hbisect.save_state(repo, state)
897 return mayupdate(repo, node)
898 return mayupdate(repo, node)
898
899
899 @command('bookmarks|bookmark',
900 @command('bookmarks|bookmark',
900 [('f', 'force', False, _('force')),
901 [('f', 'force', False, _('force')),
901 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
902 ('d', 'delete', False, _('delete a given bookmark')),
903 ('d', 'delete', False, _('delete a given bookmark')),
903 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
904 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ('i', 'inactive', False, _('mark a bookmark inactive')),
905 ] + formatteropts,
906 ] + formatteropts,
906 _('hg bookmarks [OPTIONS]... [NAME]...'))
907 _('hg bookmarks [OPTIONS]... [NAME]...'))
907 def bookmark(ui, repo, *names, **opts):
908 def bookmark(ui, repo, *names, **opts):
908 '''create a new bookmark or list existing bookmarks
909 '''create a new bookmark or list existing bookmarks
909
910
910 Bookmarks are labels on changesets to help track lines of development.
911 Bookmarks are labels on changesets to help track lines of development.
911 Bookmarks are unversioned and can be moved, renamed and deleted.
912 Bookmarks are unversioned and can be moved, renamed and deleted.
912 Deleting or moving a bookmark has no effect on the associated changesets.
913 Deleting or moving a bookmark has no effect on the associated changesets.
913
914
914 Creating or updating to a bookmark causes it to be marked as 'active'.
915 Creating or updating to a bookmark causes it to be marked as 'active'.
915 The active bookmark is indicated with a '*'.
916 The active bookmark is indicated with a '*'.
916 When a commit is made, the active bookmark will advance to the new commit.
917 When a commit is made, the active bookmark will advance to the new commit.
917 A plain :hg:`update` will also advance an active bookmark, if possible.
918 A plain :hg:`update` will also advance an active bookmark, if possible.
918 Updating away from a bookmark will cause it to be deactivated.
919 Updating away from a bookmark will cause it to be deactivated.
919
920
920 Bookmarks can be pushed and pulled between repositories (see
921 Bookmarks can be pushed and pulled between repositories (see
921 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
922 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
922 diverged, a new 'divergent bookmark' of the form 'name@path' will
923 diverged, a new 'divergent bookmark' of the form 'name@path' will
923 be created. Using :hg:`merge` will resolve the divergence.
924 be created. Using :hg:`merge` will resolve the divergence.
924
925
925 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
926 Specifying bookmark as '.' to -m or -d options is equivalent to specifying
926 the active bookmark's name.
927 the active bookmark's name.
927
928
928 A bookmark named '@' has the special property that :hg:`clone` will
929 A bookmark named '@' has the special property that :hg:`clone` will
929 check it out by default if it exists.
930 check it out by default if it exists.
930
931
931 .. container:: verbose
932 .. container:: verbose
932
933
933 Examples:
934 Examples:
934
935
935 - create an active bookmark for a new line of development::
936 - create an active bookmark for a new line of development::
936
937
937 hg book new-feature
938 hg book new-feature
938
939
939 - create an inactive bookmark as a place marker::
940 - create an inactive bookmark as a place marker::
940
941
941 hg book -i reviewed
942 hg book -i reviewed
942
943
943 - create an inactive bookmark on another changeset::
944 - create an inactive bookmark on another changeset::
944
945
945 hg book -r .^ tested
946 hg book -r .^ tested
946
947
947 - rename bookmark turkey to dinner::
948 - rename bookmark turkey to dinner::
948
949
949 hg book -m turkey dinner
950 hg book -m turkey dinner
950
951
951 - move the '@' bookmark from another branch::
952 - move the '@' bookmark from another branch::
952
953
953 hg book -f @
954 hg book -f @
954 '''
955 '''
955 force = opts.get(r'force')
956 force = opts.get(r'force')
956 rev = opts.get(r'rev')
957 rev = opts.get(r'rev')
957 delete = opts.get(r'delete')
958 delete = opts.get(r'delete')
958 rename = opts.get(r'rename')
959 rename = opts.get(r'rename')
959 inactive = opts.get(r'inactive')
960 inactive = opts.get(r'inactive')
960
961
961 if delete and rename:
962 if delete and rename:
962 raise error.Abort(_("--delete and --rename are incompatible"))
963 raise error.Abort(_("--delete and --rename are incompatible"))
963 if delete and rev:
964 if delete and rev:
964 raise error.Abort(_("--rev is incompatible with --delete"))
965 raise error.Abort(_("--rev is incompatible with --delete"))
965 if rename and rev:
966 if rename and rev:
966 raise error.Abort(_("--rev is incompatible with --rename"))
967 raise error.Abort(_("--rev is incompatible with --rename"))
967 if not names and (delete or rev):
968 if not names and (delete or rev):
968 raise error.Abort(_("bookmark name required"))
969 raise error.Abort(_("bookmark name required"))
969
970
970 if delete or rename or names or inactive:
971 if delete or rename or names or inactive:
971 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
972 with repo.wlock(), repo.lock(), repo.transaction('bookmark') as tr:
972 if delete:
973 if delete:
973 names = pycompat.maplist(repo._bookmarks.expandname, names)
974 names = pycompat.maplist(repo._bookmarks.expandname, names)
974 bookmarks.delete(repo, tr, names)
975 bookmarks.delete(repo, tr, names)
975 elif rename:
976 elif rename:
976 if not names:
977 if not names:
977 raise error.Abort(_("new bookmark name required"))
978 raise error.Abort(_("new bookmark name required"))
978 elif len(names) > 1:
979 elif len(names) > 1:
979 raise error.Abort(_("only one new bookmark name allowed"))
980 raise error.Abort(_("only one new bookmark name allowed"))
980 rename = repo._bookmarks.expandname(rename)
981 rename = repo._bookmarks.expandname(rename)
981 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
982 bookmarks.rename(repo, tr, rename, names[0], force, inactive)
982 elif names:
983 elif names:
983 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
984 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
984 elif inactive:
985 elif inactive:
985 if len(repo._bookmarks) == 0:
986 if len(repo._bookmarks) == 0:
986 ui.status(_("no bookmarks set\n"))
987 ui.status(_("no bookmarks set\n"))
987 elif not repo._activebookmark:
988 elif not repo._activebookmark:
988 ui.status(_("no active bookmark\n"))
989 ui.status(_("no active bookmark\n"))
989 else:
990 else:
990 bookmarks.deactivate(repo)
991 bookmarks.deactivate(repo)
991 else: # show bookmarks
992 else: # show bookmarks
992 bookmarks.printbookmarks(ui, repo, **opts)
993 bookmarks.printbookmarks(ui, repo, **opts)
993
994
994 @command('branch',
995 @command('branch',
995 [('f', 'force', None,
996 [('f', 'force', None,
996 _('set branch name even if it shadows an existing branch')),
997 _('set branch name even if it shadows an existing branch')),
997 ('C', 'clean', None, _('reset branch name to parent branch name'))],
998 ('C', 'clean', None, _('reset branch name to parent branch name'))],
998 _('[-fC] [NAME]'))
999 _('[-fC] [NAME]'))
999 def branch(ui, repo, label=None, **opts):
1000 def branch(ui, repo, label=None, **opts):
1000 """set or show the current branch name
1001 """set or show the current branch name
1001
1002
1002 .. note::
1003 .. note::
1003
1004
1004 Branch names are permanent and global. Use :hg:`bookmark` to create a
1005 Branch names are permanent and global. Use :hg:`bookmark` to create a
1005 light-weight bookmark instead. See :hg:`help glossary` for more
1006 light-weight bookmark instead. See :hg:`help glossary` for more
1006 information about named branches and bookmarks.
1007 information about named branches and bookmarks.
1007
1008
1008 With no argument, show the current branch name. With one argument,
1009 With no argument, show the current branch name. With one argument,
1009 set the working directory branch name (the branch will not exist
1010 set the working directory branch name (the branch will not exist
1010 in the repository until the next commit). Standard practice
1011 in the repository until the next commit). Standard practice
1011 recommends that primary development take place on the 'default'
1012 recommends that primary development take place on the 'default'
1012 branch.
1013 branch.
1013
1014
1014 Unless -f/--force is specified, branch will not let you set a
1015 Unless -f/--force is specified, branch will not let you set a
1015 branch name that already exists.
1016 branch name that already exists.
1016
1017
1017 Use -C/--clean to reset the working directory branch to that of
1018 Use -C/--clean to reset the working directory branch to that of
1018 the parent of the working directory, negating a previous branch
1019 the parent of the working directory, negating a previous branch
1019 change.
1020 change.
1020
1021
1021 Use the command :hg:`update` to switch to an existing branch. Use
1022 Use the command :hg:`update` to switch to an existing branch. Use
1022 :hg:`commit --close-branch` to mark this branch head as closed.
1023 :hg:`commit --close-branch` to mark this branch head as closed.
1023 When all heads of a branch are closed, the branch will be
1024 When all heads of a branch are closed, the branch will be
1024 considered closed.
1025 considered closed.
1025
1026
1026 Returns 0 on success.
1027 Returns 0 on success.
1027 """
1028 """
1028 opts = pycompat.byteskwargs(opts)
1029 opts = pycompat.byteskwargs(opts)
1029 if label:
1030 if label:
1030 label = label.strip()
1031 label = label.strip()
1031
1032
1032 if not opts.get('clean') and not label:
1033 if not opts.get('clean') and not label:
1033 ui.write("%s\n" % repo.dirstate.branch())
1034 ui.write("%s\n" % repo.dirstate.branch())
1034 return
1035 return
1035
1036
1036 with repo.wlock():
1037 with repo.wlock():
1037 if opts.get('clean'):
1038 if opts.get('clean'):
1038 label = repo[None].p1().branch()
1039 label = repo[None].p1().branch()
1039 repo.dirstate.setbranch(label)
1040 repo.dirstate.setbranch(label)
1040 ui.status(_('reset working directory to branch %s\n') % label)
1041 ui.status(_('reset working directory to branch %s\n') % label)
1041 elif label:
1042 elif label:
1042 if not opts.get('force') and label in repo.branchmap():
1043 if not opts.get('force') and label in repo.branchmap():
1043 if label not in [p.branch() for p in repo[None].parents()]:
1044 if label not in [p.branch() for p in repo[None].parents()]:
1044 raise error.Abort(_('a branch of the same name already'
1045 raise error.Abort(_('a branch of the same name already'
1045 ' exists'),
1046 ' exists'),
1046 # i18n: "it" refers to an existing branch
1047 # i18n: "it" refers to an existing branch
1047 hint=_("use 'hg update' to switch to it"))
1048 hint=_("use 'hg update' to switch to it"))
1048 scmutil.checknewlabel(repo, label, 'branch')
1049 scmutil.checknewlabel(repo, label, 'branch')
1049 repo.dirstate.setbranch(label)
1050 repo.dirstate.setbranch(label)
1050 ui.status(_('marked working directory as branch %s\n') % label)
1051 ui.status(_('marked working directory as branch %s\n') % label)
1051
1052
1052 # find any open named branches aside from default
1053 # find any open named branches aside from default
1053 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1054 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1054 if n != "default" and not c]
1055 if n != "default" and not c]
1055 if not others:
1056 if not others:
1056 ui.status(_('(branches are permanent and global, '
1057 ui.status(_('(branches are permanent and global, '
1057 'did you want a bookmark?)\n'))
1058 'did you want a bookmark?)\n'))
1058
1059
1059 @command('branches',
1060 @command('branches',
1060 [('a', 'active', False,
1061 [('a', 'active', False,
1061 _('show only branches that have unmerged heads (DEPRECATED)')),
1062 _('show only branches that have unmerged heads (DEPRECATED)')),
1062 ('c', 'closed', False, _('show normal and closed branches')),
1063 ('c', 'closed', False, _('show normal and closed branches')),
1063 ] + formatteropts,
1064 ] + formatteropts,
1064 _('[-c]'), cmdtype=readonly)
1065 _('[-c]'), cmdtype=readonly)
1065 def branches(ui, repo, active=False, closed=False, **opts):
1066 def branches(ui, repo, active=False, closed=False, **opts):
1066 """list repository named branches
1067 """list repository named branches
1067
1068
1068 List the repository's named branches, indicating which ones are
1069 List the repository's named branches, indicating which ones are
1069 inactive. If -c/--closed is specified, also list branches which have
1070 inactive. If -c/--closed is specified, also list branches which have
1070 been marked closed (see :hg:`commit --close-branch`).
1071 been marked closed (see :hg:`commit --close-branch`).
1071
1072
1072 Use the command :hg:`update` to switch to an existing branch.
1073 Use the command :hg:`update` to switch to an existing branch.
1073
1074
1074 Returns 0.
1075 Returns 0.
1075 """
1076 """
1076
1077
1077 opts = pycompat.byteskwargs(opts)
1078 opts = pycompat.byteskwargs(opts)
1078 ui.pager('branches')
1079 ui.pager('branches')
1079 fm = ui.formatter('branches', opts)
1080 fm = ui.formatter('branches', opts)
1080 hexfunc = fm.hexfunc
1081 hexfunc = fm.hexfunc
1081
1082
1082 allheads = set(repo.heads())
1083 allheads = set(repo.heads())
1083 branches = []
1084 branches = []
1084 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1085 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1085 isactive = False
1086 isactive = False
1086 if not isclosed:
1087 if not isclosed:
1087 openheads = set(repo.branchmap().iteropen(heads))
1088 openheads = set(repo.branchmap().iteropen(heads))
1088 isactive = bool(openheads & allheads)
1089 isactive = bool(openheads & allheads)
1089 branches.append((tag, repo[tip], isactive, not isclosed))
1090 branches.append((tag, repo[tip], isactive, not isclosed))
1090 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1091 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1091 reverse=True)
1092 reverse=True)
1092
1093
1093 for tag, ctx, isactive, isopen in branches:
1094 for tag, ctx, isactive, isopen in branches:
1094 if active and not isactive:
1095 if active and not isactive:
1095 continue
1096 continue
1096 if isactive:
1097 if isactive:
1097 label = 'branches.active'
1098 label = 'branches.active'
1098 notice = ''
1099 notice = ''
1099 elif not isopen:
1100 elif not isopen:
1100 if not closed:
1101 if not closed:
1101 continue
1102 continue
1102 label = 'branches.closed'
1103 label = 'branches.closed'
1103 notice = _(' (closed)')
1104 notice = _(' (closed)')
1104 else:
1105 else:
1105 label = 'branches.inactive'
1106 label = 'branches.inactive'
1106 notice = _(' (inactive)')
1107 notice = _(' (inactive)')
1107 current = (tag == repo.dirstate.branch())
1108 current = (tag == repo.dirstate.branch())
1108 if current:
1109 if current:
1109 label = 'branches.current'
1110 label = 'branches.current'
1110
1111
1111 fm.startitem()
1112 fm.startitem()
1112 fm.write('branch', '%s', tag, label=label)
1113 fm.write('branch', '%s', tag, label=label)
1113 rev = ctx.rev()
1114 rev = ctx.rev()
1114 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1115 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1115 fmt = ' ' * padsize + ' %d:%s'
1116 fmt = ' ' * padsize + ' %d:%s'
1116 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1117 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1117 label='log.changeset changeset.%s' % ctx.phasestr())
1118 label='log.changeset changeset.%s' % ctx.phasestr())
1118 fm.context(ctx=ctx)
1119 fm.context(ctx=ctx)
1119 fm.data(active=isactive, closed=not isopen, current=current)
1120 fm.data(active=isactive, closed=not isopen, current=current)
1120 if not ui.quiet:
1121 if not ui.quiet:
1121 fm.plain(notice)
1122 fm.plain(notice)
1122 fm.plain('\n')
1123 fm.plain('\n')
1123 fm.end()
1124 fm.end()
1124
1125
1125 @command('bundle',
1126 @command('bundle',
1126 [('f', 'force', None, _('run even when the destination is unrelated')),
1127 [('f', 'force', None, _('run even when the destination is unrelated')),
1127 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1128 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1128 _('REV')),
1129 _('REV')),
1129 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1130 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1130 _('BRANCH')),
1131 _('BRANCH')),
1131 ('', 'base', [],
1132 ('', 'base', [],
1132 _('a base changeset assumed to be available at the destination'),
1133 _('a base changeset assumed to be available at the destination'),
1133 _('REV')),
1134 _('REV')),
1134 ('a', 'all', None, _('bundle all changesets in the repository')),
1135 ('a', 'all', None, _('bundle all changesets in the repository')),
1135 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1136 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1136 ] + remoteopts,
1137 ] + remoteopts,
1137 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1138 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1138 def bundle(ui, repo, fname, dest=None, **opts):
1139 def bundle(ui, repo, fname, dest=None, **opts):
1139 """create a bundle file
1140 """create a bundle file
1140
1141
1141 Generate a bundle file containing data to be added to a repository.
1142 Generate a bundle file containing data to be added to a repository.
1142
1143
1143 To create a bundle containing all changesets, use -a/--all
1144 To create a bundle containing all changesets, use -a/--all
1144 (or --base null). Otherwise, hg assumes the destination will have
1145 (or --base null). Otherwise, hg assumes the destination will have
1145 all the nodes you specify with --base parameters. Otherwise, hg
1146 all the nodes you specify with --base parameters. Otherwise, hg
1146 will assume the repository has all the nodes in destination, or
1147 will assume the repository has all the nodes in destination, or
1147 default-push/default if no destination is specified.
1148 default-push/default if no destination is specified.
1148
1149
1149 You can change bundle format with the -t/--type option. See
1150 You can change bundle format with the -t/--type option. See
1150 :hg:`help bundlespec` for documentation on this format. By default,
1151 :hg:`help bundlespec` for documentation on this format. By default,
1151 the most appropriate format is used and compression defaults to
1152 the most appropriate format is used and compression defaults to
1152 bzip2.
1153 bzip2.
1153
1154
1154 The bundle file can then be transferred using conventional means
1155 The bundle file can then be transferred using conventional means
1155 and applied to another repository with the unbundle or pull
1156 and applied to another repository with the unbundle or pull
1156 command. This is useful when direct push and pull are not
1157 command. This is useful when direct push and pull are not
1157 available or when exporting an entire repository is undesirable.
1158 available or when exporting an entire repository is undesirable.
1158
1159
1159 Applying bundles preserves all changeset contents including
1160 Applying bundles preserves all changeset contents including
1160 permissions, copy/rename information, and revision history.
1161 permissions, copy/rename information, and revision history.
1161
1162
1162 Returns 0 on success, 1 if no changes found.
1163 Returns 0 on success, 1 if no changes found.
1163 """
1164 """
1164 opts = pycompat.byteskwargs(opts)
1165 opts = pycompat.byteskwargs(opts)
1165 revs = None
1166 revs = None
1166 if 'rev' in opts:
1167 if 'rev' in opts:
1167 revstrings = opts['rev']
1168 revstrings = opts['rev']
1168 revs = scmutil.revrange(repo, revstrings)
1169 revs = scmutil.revrange(repo, revstrings)
1169 if revstrings and not revs:
1170 if revstrings and not revs:
1170 raise error.Abort(_('no commits to bundle'))
1171 raise error.Abort(_('no commits to bundle'))
1171
1172
1172 bundletype = opts.get('type', 'bzip2').lower()
1173 bundletype = opts.get('type', 'bzip2').lower()
1173 try:
1174 try:
1174 bcompression, cgversion, params = exchange.parsebundlespec(
1175 bcompression, cgversion, params = exchange.parsebundlespec(
1175 repo, bundletype, strict=False)
1176 repo, bundletype, strict=False)
1176 except error.UnsupportedBundleSpecification as e:
1177 except error.UnsupportedBundleSpecification as e:
1177 raise error.Abort(str(e),
1178 raise error.Abort(str(e),
1178 hint=_("see 'hg help bundlespec' for supported "
1179 hint=_("see 'hg help bundlespec' for supported "
1179 "values for --type"))
1180 "values for --type"))
1180
1181
1181 # Packed bundles are a pseudo bundle format for now.
1182 # Packed bundles are a pseudo bundle format for now.
1182 if cgversion == 's1':
1183 if cgversion == 's1':
1183 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1184 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1184 hint=_("use 'hg debugcreatestreamclonebundle'"))
1185 hint=_("use 'hg debugcreatestreamclonebundle'"))
1185
1186
1186 if opts.get('all'):
1187 if opts.get('all'):
1187 if dest:
1188 if dest:
1188 raise error.Abort(_("--all is incompatible with specifying "
1189 raise error.Abort(_("--all is incompatible with specifying "
1189 "a destination"))
1190 "a destination"))
1190 if opts.get('base'):
1191 if opts.get('base'):
1191 ui.warn(_("ignoring --base because --all was specified\n"))
1192 ui.warn(_("ignoring --base because --all was specified\n"))
1192 base = ['null']
1193 base = ['null']
1193 else:
1194 else:
1194 base = scmutil.revrange(repo, opts.get('base'))
1195 base = scmutil.revrange(repo, opts.get('base'))
1195 if cgversion not in changegroup.supportedoutgoingversions(repo):
1196 if cgversion not in changegroup.supportedoutgoingversions(repo):
1196 raise error.Abort(_("repository does not support bundle version %s") %
1197 raise error.Abort(_("repository does not support bundle version %s") %
1197 cgversion)
1198 cgversion)
1198
1199
1199 if base:
1200 if base:
1200 if dest:
1201 if dest:
1201 raise error.Abort(_("--base is incompatible with specifying "
1202 raise error.Abort(_("--base is incompatible with specifying "
1202 "a destination"))
1203 "a destination"))
1203 common = [repo.lookup(rev) for rev in base]
1204 common = [repo.lookup(rev) for rev in base]
1204 heads = revs and map(repo.lookup, revs) or None
1205 heads = revs and map(repo.lookup, revs) or None
1205 outgoing = discovery.outgoing(repo, common, heads)
1206 outgoing = discovery.outgoing(repo, common, heads)
1206 else:
1207 else:
1207 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 other = hg.peer(repo, opts, dest)
1210 other = hg.peer(repo, opts, dest)
1210 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 heads = revs and map(repo.lookup, revs) or revs
1212 heads = revs and map(repo.lookup, revs) or revs
1212 outgoing = discovery.findcommonoutgoing(repo, other,
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1213 onlyheads=heads,
1214 onlyheads=heads,
1214 force=opts.get('force'),
1215 force=opts.get('force'),
1215 portable=True)
1216 portable=True)
1216
1217
1217 if not outgoing.missing:
1218 if not outgoing.missing:
1218 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1219 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1219 return 1
1220 return 1
1220
1221
1221 if cgversion == '01': #bundle1
1222 if cgversion == '01': #bundle1
1222 if bcompression is None:
1223 if bcompression is None:
1223 bcompression = 'UN'
1224 bcompression = 'UN'
1224 bversion = 'HG10' + bcompression
1225 bversion = 'HG10' + bcompression
1225 bcompression = None
1226 bcompression = None
1226 elif cgversion in ('02', '03'):
1227 elif cgversion in ('02', '03'):
1227 bversion = 'HG20'
1228 bversion = 'HG20'
1228 else:
1229 else:
1229 raise error.ProgrammingError(
1230 raise error.ProgrammingError(
1230 'bundle: unexpected changegroup version %s' % cgversion)
1231 'bundle: unexpected changegroup version %s' % cgversion)
1231
1232
1232 # TODO compression options should be derived from bundlespec parsing.
1233 # TODO compression options should be derived from bundlespec parsing.
1233 # This is a temporary hack to allow adjusting bundle compression
1234 # This is a temporary hack to allow adjusting bundle compression
1234 # level without a) formalizing the bundlespec changes to declare it
1235 # level without a) formalizing the bundlespec changes to declare it
1235 # b) introducing a command flag.
1236 # b) introducing a command flag.
1236 compopts = {}
1237 compopts = {}
1237 complevel = ui.configint('experimental', 'bundlecomplevel')
1238 complevel = ui.configint('experimental', 'bundlecomplevel')
1238 if complevel is not None:
1239 if complevel is not None:
1239 compopts['level'] = complevel
1240 compopts['level'] = complevel
1240
1241
1241
1242
1242 contentopts = {'cg.version': cgversion}
1243 contentopts = {'cg.version': cgversion}
1243 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1244 if repo.ui.configbool('experimental', 'evolution.bundle-obsmarker'):
1244 contentopts['obsolescence'] = True
1245 contentopts['obsolescence'] = True
1245 if repo.ui.configbool('experimental', 'bundle-phases'):
1246 if repo.ui.configbool('experimental', 'bundle-phases'):
1246 contentopts['phases'] = True
1247 contentopts['phases'] = True
1247 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1248 bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing,
1248 contentopts, compression=bcompression,
1249 contentopts, compression=bcompression,
1249 compopts=compopts)
1250 compopts=compopts)
1250
1251
1251 @command('cat',
1252 @command('cat',
1252 [('o', 'output', '',
1253 [('o', 'output', '',
1253 _('print output to file with formatted name'), _('FORMAT')),
1254 _('print output to file with formatted name'), _('FORMAT')),
1254 ('r', 'rev', '', _('print the given revision'), _('REV')),
1255 ('r', 'rev', '', _('print the given revision'), _('REV')),
1255 ('', 'decode', None, _('apply any matching decode filter')),
1256 ('', 'decode', None, _('apply any matching decode filter')),
1256 ] + walkopts + formatteropts,
1257 ] + walkopts + formatteropts,
1257 _('[OPTION]... FILE...'),
1258 _('[OPTION]... FILE...'),
1258 inferrepo=True, cmdtype=readonly)
1259 inferrepo=True, cmdtype=readonly)
1259 def cat(ui, repo, file1, *pats, **opts):
1260 def cat(ui, repo, file1, *pats, **opts):
1260 """output the current or given revision of files
1261 """output the current or given revision of files
1261
1262
1262 Print the specified files as they were at the given revision. If
1263 Print the specified files as they were at the given revision. If
1263 no revision is given, the parent of the working directory is used.
1264 no revision is given, the parent of the working directory is used.
1264
1265
1265 Output may be to a file, in which case the name of the file is
1266 Output may be to a file, in which case the name of the file is
1266 given using a format string. The formatting rules as follows:
1267 given using a format string. The formatting rules as follows:
1267
1268
1268 :``%%``: literal "%" character
1269 :``%%``: literal "%" character
1269 :``%s``: basename of file being printed
1270 :``%s``: basename of file being printed
1270 :``%d``: dirname of file being printed, or '.' if in repository root
1271 :``%d``: dirname of file being printed, or '.' if in repository root
1271 :``%p``: root-relative path name of file being printed
1272 :``%p``: root-relative path name of file being printed
1272 :``%H``: changeset hash (40 hexadecimal digits)
1273 :``%H``: changeset hash (40 hexadecimal digits)
1273 :``%R``: changeset revision number
1274 :``%R``: changeset revision number
1274 :``%h``: short-form changeset hash (12 hexadecimal digits)
1275 :``%h``: short-form changeset hash (12 hexadecimal digits)
1275 :``%r``: zero-padded changeset revision number
1276 :``%r``: zero-padded changeset revision number
1276 :``%b``: basename of the exporting repository
1277 :``%b``: basename of the exporting repository
1277
1278
1278 Returns 0 on success.
1279 Returns 0 on success.
1279 """
1280 """
1280 ctx = scmutil.revsingle(repo, opts.get('rev'))
1281 ctx = scmutil.revsingle(repo, opts.get('rev'))
1281 m = scmutil.match(ctx, (file1,) + pats, opts)
1282 m = scmutil.match(ctx, (file1,) + pats, opts)
1282 fntemplate = opts.pop('output', '')
1283 fntemplate = opts.pop('output', '')
1283 if cmdutil.isstdiofilename(fntemplate):
1284 if cmdutil.isstdiofilename(fntemplate):
1284 fntemplate = ''
1285 fntemplate = ''
1285
1286
1286 if fntemplate:
1287 if fntemplate:
1287 fm = formatter.nullformatter(ui, 'cat')
1288 fm = formatter.nullformatter(ui, 'cat')
1288 else:
1289 else:
1289 ui.pager('cat')
1290 ui.pager('cat')
1290 fm = ui.formatter('cat', opts)
1291 fm = ui.formatter('cat', opts)
1291 with fm:
1292 with fm:
1292 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1293 return cmdutil.cat(ui, repo, ctx, m, fm, fntemplate, '', **opts)
1293
1294
1294 @command('^clone',
1295 @command('^clone',
1295 [('U', 'noupdate', None, _('the clone will include an empty working '
1296 [('U', 'noupdate', None, _('the clone will include an empty working '
1296 'directory (only a repository)')),
1297 'directory (only a repository)')),
1297 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1298 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1298 _('REV')),
1299 _('REV')),
1299 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1300 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1300 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1301 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1301 ('', 'pull', None, _('use pull protocol to copy metadata')),
1302 ('', 'pull', None, _('use pull protocol to copy metadata')),
1302 ('', 'uncompressed', None,
1303 ('', 'uncompressed', None,
1303 _('an alias to --stream (DEPRECATED)')),
1304 _('an alias to --stream (DEPRECATED)')),
1304 ('', 'stream', None,
1305 ('', 'stream', None,
1305 _('clone with minimal data processing')),
1306 _('clone with minimal data processing')),
1306 ] + remoteopts,
1307 ] + remoteopts,
1307 _('[OPTION]... SOURCE [DEST]'),
1308 _('[OPTION]... SOURCE [DEST]'),
1308 norepo=True)
1309 norepo=True)
1309 def clone(ui, source, dest=None, **opts):
1310 def clone(ui, source, dest=None, **opts):
1310 """make a copy of an existing repository
1311 """make a copy of an existing repository
1311
1312
1312 Create a copy of an existing repository in a new directory.
1313 Create a copy of an existing repository in a new directory.
1313
1314
1314 If no destination directory name is specified, it defaults to the
1315 If no destination directory name is specified, it defaults to the
1315 basename of the source.
1316 basename of the source.
1316
1317
1317 The location of the source is added to the new repository's
1318 The location of the source is added to the new repository's
1318 ``.hg/hgrc`` file, as the default to be used for future pulls.
1319 ``.hg/hgrc`` file, as the default to be used for future pulls.
1319
1320
1320 Only local paths and ``ssh://`` URLs are supported as
1321 Only local paths and ``ssh://`` URLs are supported as
1321 destinations. For ``ssh://`` destinations, no working directory or
1322 destinations. For ``ssh://`` destinations, no working directory or
1322 ``.hg/hgrc`` will be created on the remote side.
1323 ``.hg/hgrc`` will be created on the remote side.
1323
1324
1324 If the source repository has a bookmark called '@' set, that
1325 If the source repository has a bookmark called '@' set, that
1325 revision will be checked out in the new repository by default.
1326 revision will be checked out in the new repository by default.
1326
1327
1327 To check out a particular version, use -u/--update, or
1328 To check out a particular version, use -u/--update, or
1328 -U/--noupdate to create a clone with no working directory.
1329 -U/--noupdate to create a clone with no working directory.
1329
1330
1330 To pull only a subset of changesets, specify one or more revisions
1331 To pull only a subset of changesets, specify one or more revisions
1331 identifiers with -r/--rev or branches with -b/--branch. The
1332 identifiers with -r/--rev or branches with -b/--branch. The
1332 resulting clone will contain only the specified changesets and
1333 resulting clone will contain only the specified changesets and
1333 their ancestors. These options (or 'clone src#rev dest') imply
1334 their ancestors. These options (or 'clone src#rev dest') imply
1334 --pull, even for local source repositories.
1335 --pull, even for local source repositories.
1335
1336
1336 In normal clone mode, the remote normalizes repository data into a common
1337 In normal clone mode, the remote normalizes repository data into a common
1337 exchange format and the receiving end translates this data into its local
1338 exchange format and the receiving end translates this data into its local
1338 storage format. --stream activates a different clone mode that essentially
1339 storage format. --stream activates a different clone mode that essentially
1339 copies repository files from the remote with minimal data processing. This
1340 copies repository files from the remote with minimal data processing. This
1340 significantly reduces the CPU cost of a clone both remotely and locally.
1341 significantly reduces the CPU cost of a clone both remotely and locally.
1341 However, it often increases the transferred data size by 30-40%. This can
1342 However, it often increases the transferred data size by 30-40%. This can
1342 result in substantially faster clones where I/O throughput is plentiful,
1343 result in substantially faster clones where I/O throughput is plentiful,
1343 especially for larger repositories. A side-effect of --stream clones is
1344 especially for larger repositories. A side-effect of --stream clones is
1344 that storage settings and requirements on the remote are applied locally:
1345 that storage settings and requirements on the remote are applied locally:
1345 a modern client may inherit legacy or inefficient storage used by the
1346 a modern client may inherit legacy or inefficient storage used by the
1346 remote or a legacy Mercurial client may not be able to clone from a
1347 remote or a legacy Mercurial client may not be able to clone from a
1347 modern Mercurial remote.
1348 modern Mercurial remote.
1348
1349
1349 .. note::
1350 .. note::
1350
1351
1351 Specifying a tag will include the tagged changeset but not the
1352 Specifying a tag will include the tagged changeset but not the
1352 changeset containing the tag.
1353 changeset containing the tag.
1353
1354
1354 .. container:: verbose
1355 .. container:: verbose
1355
1356
1356 For efficiency, hardlinks are used for cloning whenever the
1357 For efficiency, hardlinks are used for cloning whenever the
1357 source and destination are on the same filesystem (note this
1358 source and destination are on the same filesystem (note this
1358 applies only to the repository data, not to the working
1359 applies only to the repository data, not to the working
1359 directory). Some filesystems, such as AFS, implement hardlinking
1360 directory). Some filesystems, such as AFS, implement hardlinking
1360 incorrectly, but do not report errors. In these cases, use the
1361 incorrectly, but do not report errors. In these cases, use the
1361 --pull option to avoid hardlinking.
1362 --pull option to avoid hardlinking.
1362
1363
1363 Mercurial will update the working directory to the first applicable
1364 Mercurial will update the working directory to the first applicable
1364 revision from this list:
1365 revision from this list:
1365
1366
1366 a) null if -U or the source repository has no changesets
1367 a) null if -U or the source repository has no changesets
1367 b) if -u . and the source repository is local, the first parent of
1368 b) if -u . and the source repository is local, the first parent of
1368 the source repository's working directory
1369 the source repository's working directory
1369 c) the changeset specified with -u (if a branch name, this means the
1370 c) the changeset specified with -u (if a branch name, this means the
1370 latest head of that branch)
1371 latest head of that branch)
1371 d) the changeset specified with -r
1372 d) the changeset specified with -r
1372 e) the tipmost head specified with -b
1373 e) the tipmost head specified with -b
1373 f) the tipmost head specified with the url#branch source syntax
1374 f) the tipmost head specified with the url#branch source syntax
1374 g) the revision marked with the '@' bookmark, if present
1375 g) the revision marked with the '@' bookmark, if present
1375 h) the tipmost head of the default branch
1376 h) the tipmost head of the default branch
1376 i) tip
1377 i) tip
1377
1378
1378 When cloning from servers that support it, Mercurial may fetch
1379 When cloning from servers that support it, Mercurial may fetch
1379 pre-generated data from a server-advertised URL. When this is done,
1380 pre-generated data from a server-advertised URL. When this is done,
1380 hooks operating on incoming changesets and changegroups may fire twice,
1381 hooks operating on incoming changesets and changegroups may fire twice,
1381 once for the bundle fetched from the URL and another for any additional
1382 once for the bundle fetched from the URL and another for any additional
1382 data not fetched from this URL. In addition, if an error occurs, the
1383 data not fetched from this URL. In addition, if an error occurs, the
1383 repository may be rolled back to a partial clone. This behavior may
1384 repository may be rolled back to a partial clone. This behavior may
1384 change in future releases. See :hg:`help -e clonebundles` for more.
1385 change in future releases. See :hg:`help -e clonebundles` for more.
1385
1386
1386 Examples:
1387 Examples:
1387
1388
1388 - clone a remote repository to a new directory named hg/::
1389 - clone a remote repository to a new directory named hg/::
1389
1390
1390 hg clone https://www.mercurial-scm.org/repo/hg/
1391 hg clone https://www.mercurial-scm.org/repo/hg/
1391
1392
1392 - create a lightweight local clone::
1393 - create a lightweight local clone::
1393
1394
1394 hg clone project/ project-feature/
1395 hg clone project/ project-feature/
1395
1396
1396 - clone from an absolute path on an ssh server (note double-slash)::
1397 - clone from an absolute path on an ssh server (note double-slash)::
1397
1398
1398 hg clone ssh://user@server//home/projects/alpha/
1399 hg clone ssh://user@server//home/projects/alpha/
1399
1400
1400 - do a streaming clone while checking out a specified version::
1401 - do a streaming clone while checking out a specified version::
1401
1402
1402 hg clone --stream http://server/repo -u 1.5
1403 hg clone --stream http://server/repo -u 1.5
1403
1404
1404 - create a repository without changesets after a particular revision::
1405 - create a repository without changesets after a particular revision::
1405
1406
1406 hg clone -r 04e544 experimental/ good/
1407 hg clone -r 04e544 experimental/ good/
1407
1408
1408 - clone (and track) a particular named branch::
1409 - clone (and track) a particular named branch::
1409
1410
1410 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1411 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1411
1412
1412 See :hg:`help urls` for details on specifying URLs.
1413 See :hg:`help urls` for details on specifying URLs.
1413
1414
1414 Returns 0 on success.
1415 Returns 0 on success.
1415 """
1416 """
1416 opts = pycompat.byteskwargs(opts)
1417 opts = pycompat.byteskwargs(opts)
1417 if opts.get('noupdate') and opts.get('updaterev'):
1418 if opts.get('noupdate') and opts.get('updaterev'):
1418 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1419 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1419
1420
1420 r = hg.clone(ui, opts, source, dest,
1421 r = hg.clone(ui, opts, source, dest,
1421 pull=opts.get('pull'),
1422 pull=opts.get('pull'),
1422 stream=opts.get('stream') or opts.get('uncompressed'),
1423 stream=opts.get('stream') or opts.get('uncompressed'),
1423 rev=opts.get('rev'),
1424 rev=opts.get('rev'),
1424 update=opts.get('updaterev') or not opts.get('noupdate'),
1425 update=opts.get('updaterev') or not opts.get('noupdate'),
1425 branch=opts.get('branch'),
1426 branch=opts.get('branch'),
1426 shareopts=opts.get('shareopts'))
1427 shareopts=opts.get('shareopts'))
1427
1428
1428 return r is None
1429 return r is None
1429
1430
1430 @command('^commit|ci',
1431 @command('^commit|ci',
1431 [('A', 'addremove', None,
1432 [('A', 'addremove', None,
1432 _('mark new/missing files as added/removed before committing')),
1433 _('mark new/missing files as added/removed before committing')),
1433 ('', 'close-branch', None,
1434 ('', 'close-branch', None,
1434 _('mark a branch head as closed')),
1435 _('mark a branch head as closed')),
1435 ('', 'amend', None, _('amend the parent of the working directory')),
1436 ('', 'amend', None, _('amend the parent of the working directory')),
1436 ('s', 'secret', None, _('use the secret phase for committing')),
1437 ('s', 'secret', None, _('use the secret phase for committing')),
1437 ('e', 'edit', None, _('invoke editor on commit messages')),
1438 ('e', 'edit', None, _('invoke editor on commit messages')),
1438 ('i', 'interactive', None, _('use interactive mode')),
1439 ('i', 'interactive', None, _('use interactive mode')),
1439 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1440 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1440 _('[OPTION]... [FILE]...'),
1441 _('[OPTION]... [FILE]...'),
1441 inferrepo=True)
1442 inferrepo=True)
1442 def commit(ui, repo, *pats, **opts):
1443 def commit(ui, repo, *pats, **opts):
1443 """commit the specified files or all outstanding changes
1444 """commit the specified files or all outstanding changes
1444
1445
1445 Commit changes to the given files into the repository. Unlike a
1446 Commit changes to the given files into the repository. Unlike a
1446 centralized SCM, this operation is a local operation. See
1447 centralized SCM, this operation is a local operation. See
1447 :hg:`push` for a way to actively distribute your changes.
1448 :hg:`push` for a way to actively distribute your changes.
1448
1449
1449 If a list of files is omitted, all changes reported by :hg:`status`
1450 If a list of files is omitted, all changes reported by :hg:`status`
1450 will be committed.
1451 will be committed.
1451
1452
1452 If you are committing the result of a merge, do not provide any
1453 If you are committing the result of a merge, do not provide any
1453 filenames or -I/-X filters.
1454 filenames or -I/-X filters.
1454
1455
1455 If no commit message is specified, Mercurial starts your
1456 If no commit message is specified, Mercurial starts your
1456 configured editor where you can enter a message. In case your
1457 configured editor where you can enter a message. In case your
1457 commit fails, you will find a backup of your message in
1458 commit fails, you will find a backup of your message in
1458 ``.hg/last-message.txt``.
1459 ``.hg/last-message.txt``.
1459
1460
1460 The --close-branch flag can be used to mark the current branch
1461 The --close-branch flag can be used to mark the current branch
1461 head closed. When all heads of a branch are closed, the branch
1462 head closed. When all heads of a branch are closed, the branch
1462 will be considered closed and no longer listed.
1463 will be considered closed and no longer listed.
1463
1464
1464 The --amend flag can be used to amend the parent of the
1465 The --amend flag can be used to amend the parent of the
1465 working directory with a new commit that contains the changes
1466 working directory with a new commit that contains the changes
1466 in the parent in addition to those currently reported by :hg:`status`,
1467 in the parent in addition to those currently reported by :hg:`status`,
1467 if there are any. The old commit is stored in a backup bundle in
1468 if there are any. The old commit is stored in a backup bundle in
1468 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1469 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1469 on how to restore it).
1470 on how to restore it).
1470
1471
1471 Message, user and date are taken from the amended commit unless
1472 Message, user and date are taken from the amended commit unless
1472 specified. When a message isn't specified on the command line,
1473 specified. When a message isn't specified on the command line,
1473 the editor will open with the message of the amended commit.
1474 the editor will open with the message of the amended commit.
1474
1475
1475 It is not possible to amend public changesets (see :hg:`help phases`)
1476 It is not possible to amend public changesets (see :hg:`help phases`)
1476 or changesets that have children.
1477 or changesets that have children.
1477
1478
1478 See :hg:`help dates` for a list of formats valid for -d/--date.
1479 See :hg:`help dates` for a list of formats valid for -d/--date.
1479
1480
1480 Returns 0 on success, 1 if nothing changed.
1481 Returns 0 on success, 1 if nothing changed.
1481
1482
1482 .. container:: verbose
1483 .. container:: verbose
1483
1484
1484 Examples:
1485 Examples:
1485
1486
1486 - commit all files ending in .py::
1487 - commit all files ending in .py::
1487
1488
1488 hg commit --include "set:**.py"
1489 hg commit --include "set:**.py"
1489
1490
1490 - commit all non-binary files::
1491 - commit all non-binary files::
1491
1492
1492 hg commit --exclude "set:binary()"
1493 hg commit --exclude "set:binary()"
1493
1494
1494 - amend the current commit and set the date to now::
1495 - amend the current commit and set the date to now::
1495
1496
1496 hg commit --amend --date now
1497 hg commit --amend --date now
1497 """
1498 """
1498 wlock = lock = None
1499 wlock = lock = None
1499 try:
1500 try:
1500 wlock = repo.wlock()
1501 wlock = repo.wlock()
1501 lock = repo.lock()
1502 lock = repo.lock()
1502 return _docommit(ui, repo, *pats, **opts)
1503 return _docommit(ui, repo, *pats, **opts)
1503 finally:
1504 finally:
1504 release(lock, wlock)
1505 release(lock, wlock)
1505
1506
1506 def _docommit(ui, repo, *pats, **opts):
1507 def _docommit(ui, repo, *pats, **opts):
1507 if opts.get(r'interactive'):
1508 if opts.get(r'interactive'):
1508 opts.pop(r'interactive')
1509 opts.pop(r'interactive')
1509 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1510 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1510 cmdutil.recordfilter, *pats,
1511 cmdutil.recordfilter, *pats,
1511 **opts)
1512 **opts)
1512 # ret can be 0 (no changes to record) or the value returned by
1513 # ret can be 0 (no changes to record) or the value returned by
1513 # commit(), 1 if nothing changed or None on success.
1514 # commit(), 1 if nothing changed or None on success.
1514 return 1 if ret == 0 else ret
1515 return 1 if ret == 0 else ret
1515
1516
1516 opts = pycompat.byteskwargs(opts)
1517 opts = pycompat.byteskwargs(opts)
1517 if opts.get('subrepos'):
1518 if opts.get('subrepos'):
1518 if opts.get('amend'):
1519 if opts.get('amend'):
1519 raise error.Abort(_('cannot amend with --subrepos'))
1520 raise error.Abort(_('cannot amend with --subrepos'))
1520 # Let --subrepos on the command line override config setting.
1521 # Let --subrepos on the command line override config setting.
1521 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1522 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1522
1523
1523 cmdutil.checkunfinished(repo, commit=True)
1524 cmdutil.checkunfinished(repo, commit=True)
1524
1525
1525 branch = repo[None].branch()
1526 branch = repo[None].branch()
1526 bheads = repo.branchheads(branch)
1527 bheads = repo.branchheads(branch)
1527
1528
1528 extra = {}
1529 extra = {}
1529 if opts.get('close_branch'):
1530 if opts.get('close_branch'):
1530 extra['close'] = 1
1531 extra['close'] = 1
1531
1532
1532 if not bheads:
1533 if not bheads:
1533 raise error.Abort(_('can only close branch heads'))
1534 raise error.Abort(_('can only close branch heads'))
1534 elif opts.get('amend'):
1535 elif opts.get('amend'):
1535 if repo[None].parents()[0].p1().branch() != branch and \
1536 if repo[None].parents()[0].p1().branch() != branch and \
1536 repo[None].parents()[0].p2().branch() != branch:
1537 repo[None].parents()[0].p2().branch() != branch:
1537 raise error.Abort(_('can only close branch heads'))
1538 raise error.Abort(_('can only close branch heads'))
1538
1539
1539 if opts.get('amend'):
1540 if opts.get('amend'):
1540 if ui.configbool('ui', 'commitsubrepos'):
1541 if ui.configbool('ui', 'commitsubrepos'):
1541 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1542 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1542
1543
1543 old = repo['.']
1544 old = repo['.']
1544 if not old.mutable():
1545 rewriteutil.precheck(repo, [old.rev()], 'amend')
1545 raise error.Abort(_('cannot amend public changesets'))
1546 if len(repo[None].parents()) > 1:
1547 raise error.Abort(_('cannot amend while merging'))
1548 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1549 if not allowunstable and old.children():
1550 raise error.Abort(_('cannot amend changeset with children'))
1551
1546
1552 # Currently histedit gets confused if an amend happens while histedit
1547 # Currently histedit gets confused if an amend happens while histedit
1553 # is in progress. Since we have a checkunfinished command, we are
1548 # is in progress. Since we have a checkunfinished command, we are
1554 # temporarily honoring it.
1549 # temporarily honoring it.
1555 #
1550 #
1556 # Note: eventually this guard will be removed. Please do not expect
1551 # Note: eventually this guard will be removed. Please do not expect
1557 # this behavior to remain.
1552 # this behavior to remain.
1558 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1553 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1559 cmdutil.checkunfinished(repo)
1554 cmdutil.checkunfinished(repo)
1560
1555
1561 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1556 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
1562 if node == old.node():
1557 if node == old.node():
1563 ui.status(_("nothing changed\n"))
1558 ui.status(_("nothing changed\n"))
1564 return 1
1559 return 1
1565 else:
1560 else:
1566 def commitfunc(ui, repo, message, match, opts):
1561 def commitfunc(ui, repo, message, match, opts):
1567 overrides = {}
1562 overrides = {}
1568 if opts.get('secret'):
1563 if opts.get('secret'):
1569 overrides[('phases', 'new-commit')] = 'secret'
1564 overrides[('phases', 'new-commit')] = 'secret'
1570
1565
1571 baseui = repo.baseui
1566 baseui = repo.baseui
1572 with baseui.configoverride(overrides, 'commit'):
1567 with baseui.configoverride(overrides, 'commit'):
1573 with ui.configoverride(overrides, 'commit'):
1568 with ui.configoverride(overrides, 'commit'):
1574 editform = cmdutil.mergeeditform(repo[None],
1569 editform = cmdutil.mergeeditform(repo[None],
1575 'commit.normal')
1570 'commit.normal')
1576 editor = cmdutil.getcommiteditor(
1571 editor = cmdutil.getcommiteditor(
1577 editform=editform, **pycompat.strkwargs(opts))
1572 editform=editform, **pycompat.strkwargs(opts))
1578 return repo.commit(message,
1573 return repo.commit(message,
1579 opts.get('user'),
1574 opts.get('user'),
1580 opts.get('date'),
1575 opts.get('date'),
1581 match,
1576 match,
1582 editor=editor,
1577 editor=editor,
1583 extra=extra)
1578 extra=extra)
1584
1579
1585 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1580 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1586
1581
1587 if not node:
1582 if not node:
1588 stat = cmdutil.postcommitstatus(repo, pats, opts)
1583 stat = cmdutil.postcommitstatus(repo, pats, opts)
1589 if stat[3]:
1584 if stat[3]:
1590 ui.status(_("nothing changed (%d missing files, see "
1585 ui.status(_("nothing changed (%d missing files, see "
1591 "'hg status')\n") % len(stat[3]))
1586 "'hg status')\n") % len(stat[3]))
1592 else:
1587 else:
1593 ui.status(_("nothing changed\n"))
1588 ui.status(_("nothing changed\n"))
1594 return 1
1589 return 1
1595
1590
1596 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1591 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1597
1592
1598 @command('config|showconfig|debugconfig',
1593 @command('config|showconfig|debugconfig',
1599 [('u', 'untrusted', None, _('show untrusted configuration options')),
1594 [('u', 'untrusted', None, _('show untrusted configuration options')),
1600 ('e', 'edit', None, _('edit user config')),
1595 ('e', 'edit', None, _('edit user config')),
1601 ('l', 'local', None, _('edit repository config')),
1596 ('l', 'local', None, _('edit repository config')),
1602 ('g', 'global', None, _('edit global config'))] + formatteropts,
1597 ('g', 'global', None, _('edit global config'))] + formatteropts,
1603 _('[-u] [NAME]...'),
1598 _('[-u] [NAME]...'),
1604 optionalrepo=True, cmdtype=readonly)
1599 optionalrepo=True, cmdtype=readonly)
1605 def config(ui, repo, *values, **opts):
1600 def config(ui, repo, *values, **opts):
1606 """show combined config settings from all hgrc files
1601 """show combined config settings from all hgrc files
1607
1602
1608 With no arguments, print names and values of all config items.
1603 With no arguments, print names and values of all config items.
1609
1604
1610 With one argument of the form section.name, print just the value
1605 With one argument of the form section.name, print just the value
1611 of that config item.
1606 of that config item.
1612
1607
1613 With multiple arguments, print names and values of all config
1608 With multiple arguments, print names and values of all config
1614 items with matching section names.
1609 items with matching section names.
1615
1610
1616 With --edit, start an editor on the user-level config file. With
1611 With --edit, start an editor on the user-level config file. With
1617 --global, edit the system-wide config file. With --local, edit the
1612 --global, edit the system-wide config file. With --local, edit the
1618 repository-level config file.
1613 repository-level config file.
1619
1614
1620 With --debug, the source (filename and line number) is printed
1615 With --debug, the source (filename and line number) is printed
1621 for each config item.
1616 for each config item.
1622
1617
1623 See :hg:`help config` for more information about config files.
1618 See :hg:`help config` for more information about config files.
1624
1619
1625 Returns 0 on success, 1 if NAME does not exist.
1620 Returns 0 on success, 1 if NAME does not exist.
1626
1621
1627 """
1622 """
1628
1623
1629 opts = pycompat.byteskwargs(opts)
1624 opts = pycompat.byteskwargs(opts)
1630 if opts.get('edit') or opts.get('local') or opts.get('global'):
1625 if opts.get('edit') or opts.get('local') or opts.get('global'):
1631 if opts.get('local') and opts.get('global'):
1626 if opts.get('local') and opts.get('global'):
1632 raise error.Abort(_("can't use --local and --global together"))
1627 raise error.Abort(_("can't use --local and --global together"))
1633
1628
1634 if opts.get('local'):
1629 if opts.get('local'):
1635 if not repo:
1630 if not repo:
1636 raise error.Abort(_("can't use --local outside a repository"))
1631 raise error.Abort(_("can't use --local outside a repository"))
1637 paths = [repo.vfs.join('hgrc')]
1632 paths = [repo.vfs.join('hgrc')]
1638 elif opts.get('global'):
1633 elif opts.get('global'):
1639 paths = rcutil.systemrcpath()
1634 paths = rcutil.systemrcpath()
1640 else:
1635 else:
1641 paths = rcutil.userrcpath()
1636 paths = rcutil.userrcpath()
1642
1637
1643 for f in paths:
1638 for f in paths:
1644 if os.path.exists(f):
1639 if os.path.exists(f):
1645 break
1640 break
1646 else:
1641 else:
1647 if opts.get('global'):
1642 if opts.get('global'):
1648 samplehgrc = uimod.samplehgrcs['global']
1643 samplehgrc = uimod.samplehgrcs['global']
1649 elif opts.get('local'):
1644 elif opts.get('local'):
1650 samplehgrc = uimod.samplehgrcs['local']
1645 samplehgrc = uimod.samplehgrcs['local']
1651 else:
1646 else:
1652 samplehgrc = uimod.samplehgrcs['user']
1647 samplehgrc = uimod.samplehgrcs['user']
1653
1648
1654 f = paths[0]
1649 f = paths[0]
1655 fp = open(f, "wb")
1650 fp = open(f, "wb")
1656 fp.write(util.tonativeeol(samplehgrc))
1651 fp.write(util.tonativeeol(samplehgrc))
1657 fp.close()
1652 fp.close()
1658
1653
1659 editor = ui.geteditor()
1654 editor = ui.geteditor()
1660 ui.system("%s \"%s\"" % (editor, f),
1655 ui.system("%s \"%s\"" % (editor, f),
1661 onerr=error.Abort, errprefix=_("edit failed"),
1656 onerr=error.Abort, errprefix=_("edit failed"),
1662 blockedtag='config_edit')
1657 blockedtag='config_edit')
1663 return
1658 return
1664 ui.pager('config')
1659 ui.pager('config')
1665 fm = ui.formatter('config', opts)
1660 fm = ui.formatter('config', opts)
1666 for t, f in rcutil.rccomponents():
1661 for t, f in rcutil.rccomponents():
1667 if t == 'path':
1662 if t == 'path':
1668 ui.debug('read config from: %s\n' % f)
1663 ui.debug('read config from: %s\n' % f)
1669 elif t == 'items':
1664 elif t == 'items':
1670 for section, name, value, source in f:
1665 for section, name, value, source in f:
1671 ui.debug('set config by: %s\n' % source)
1666 ui.debug('set config by: %s\n' % source)
1672 else:
1667 else:
1673 raise error.ProgrammingError('unknown rctype: %s' % t)
1668 raise error.ProgrammingError('unknown rctype: %s' % t)
1674 untrusted = bool(opts.get('untrusted'))
1669 untrusted = bool(opts.get('untrusted'))
1675 if values:
1670 if values:
1676 sections = [v for v in values if '.' not in v]
1671 sections = [v for v in values if '.' not in v]
1677 items = [v for v in values if '.' in v]
1672 items = [v for v in values if '.' in v]
1678 if len(items) > 1 or items and sections:
1673 if len(items) > 1 or items and sections:
1679 raise error.Abort(_('only one config item permitted'))
1674 raise error.Abort(_('only one config item permitted'))
1680 matched = False
1675 matched = False
1681 for section, name, value in ui.walkconfig(untrusted=untrusted):
1676 for section, name, value in ui.walkconfig(untrusted=untrusted):
1682 source = ui.configsource(section, name, untrusted)
1677 source = ui.configsource(section, name, untrusted)
1683 value = pycompat.bytestr(value)
1678 value = pycompat.bytestr(value)
1684 if fm.isplain():
1679 if fm.isplain():
1685 source = source or 'none'
1680 source = source or 'none'
1686 value = value.replace('\n', '\\n')
1681 value = value.replace('\n', '\\n')
1687 entryname = section + '.' + name
1682 entryname = section + '.' + name
1688 if values:
1683 if values:
1689 for v in values:
1684 for v in values:
1690 if v == section:
1685 if v == section:
1691 fm.startitem()
1686 fm.startitem()
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1687 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1693 fm.write('name value', '%s=%s\n', entryname, value)
1688 fm.write('name value', '%s=%s\n', entryname, value)
1694 matched = True
1689 matched = True
1695 elif v == entryname:
1690 elif v == entryname:
1696 fm.startitem()
1691 fm.startitem()
1697 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1692 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1698 fm.write('value', '%s\n', value)
1693 fm.write('value', '%s\n', value)
1699 fm.data(name=entryname)
1694 fm.data(name=entryname)
1700 matched = True
1695 matched = True
1701 else:
1696 else:
1702 fm.startitem()
1697 fm.startitem()
1703 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1698 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1704 fm.write('name value', '%s=%s\n', entryname, value)
1699 fm.write('name value', '%s=%s\n', entryname, value)
1705 matched = True
1700 matched = True
1706 fm.end()
1701 fm.end()
1707 if matched:
1702 if matched:
1708 return 0
1703 return 0
1709 return 1
1704 return 1
1710
1705
1711 @command('copy|cp',
1706 @command('copy|cp',
1712 [('A', 'after', None, _('record a copy that has already occurred')),
1707 [('A', 'after', None, _('record a copy that has already occurred')),
1713 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1708 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1714 ] + walkopts + dryrunopts,
1709 ] + walkopts + dryrunopts,
1715 _('[OPTION]... [SOURCE]... DEST'))
1710 _('[OPTION]... [SOURCE]... DEST'))
1716 def copy(ui, repo, *pats, **opts):
1711 def copy(ui, repo, *pats, **opts):
1717 """mark files as copied for the next commit
1712 """mark files as copied for the next commit
1718
1713
1719 Mark dest as having copies of source files. If dest is a
1714 Mark dest as having copies of source files. If dest is a
1720 directory, copies are put in that directory. If dest is a file,
1715 directory, copies are put in that directory. If dest is a file,
1721 the source must be a single file.
1716 the source must be a single file.
1722
1717
1723 By default, this command copies the contents of files as they
1718 By default, this command copies the contents of files as they
1724 exist in the working directory. If invoked with -A/--after, the
1719 exist in the working directory. If invoked with -A/--after, the
1725 operation is recorded, but no copying is performed.
1720 operation is recorded, but no copying is performed.
1726
1721
1727 This command takes effect with the next commit. To undo a copy
1722 This command takes effect with the next commit. To undo a copy
1728 before that, see :hg:`revert`.
1723 before that, see :hg:`revert`.
1729
1724
1730 Returns 0 on success, 1 if errors are encountered.
1725 Returns 0 on success, 1 if errors are encountered.
1731 """
1726 """
1732 opts = pycompat.byteskwargs(opts)
1727 opts = pycompat.byteskwargs(opts)
1733 with repo.wlock(False):
1728 with repo.wlock(False):
1734 return cmdutil.copy(ui, repo, pats, opts)
1729 return cmdutil.copy(ui, repo, pats, opts)
1735
1730
1736 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1731 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1737 def debugcommands(ui, cmd='', *args):
1732 def debugcommands(ui, cmd='', *args):
1738 """list all available commands and options"""
1733 """list all available commands and options"""
1739 for cmd, vals in sorted(table.iteritems()):
1734 for cmd, vals in sorted(table.iteritems()):
1740 cmd = cmd.split('|')[0].strip('^')
1735 cmd = cmd.split('|')[0].strip('^')
1741 opts = ', '.join([i[1] for i in vals[1]])
1736 opts = ', '.join([i[1] for i in vals[1]])
1742 ui.write('%s: %s\n' % (cmd, opts))
1737 ui.write('%s: %s\n' % (cmd, opts))
1743
1738
1744 @command('debugcomplete',
1739 @command('debugcomplete',
1745 [('o', 'options', None, _('show the command options'))],
1740 [('o', 'options', None, _('show the command options'))],
1746 _('[-o] CMD'),
1741 _('[-o] CMD'),
1747 norepo=True)
1742 norepo=True)
1748 def debugcomplete(ui, cmd='', **opts):
1743 def debugcomplete(ui, cmd='', **opts):
1749 """returns the completion list associated with the given command"""
1744 """returns the completion list associated with the given command"""
1750
1745
1751 if opts.get('options'):
1746 if opts.get('options'):
1752 options = []
1747 options = []
1753 otables = [globalopts]
1748 otables = [globalopts]
1754 if cmd:
1749 if cmd:
1755 aliases, entry = cmdutil.findcmd(cmd, table, False)
1750 aliases, entry = cmdutil.findcmd(cmd, table, False)
1756 otables.append(entry[1])
1751 otables.append(entry[1])
1757 for t in otables:
1752 for t in otables:
1758 for o in t:
1753 for o in t:
1759 if "(DEPRECATED)" in o[3]:
1754 if "(DEPRECATED)" in o[3]:
1760 continue
1755 continue
1761 if o[0]:
1756 if o[0]:
1762 options.append('-%s' % o[0])
1757 options.append('-%s' % o[0])
1763 options.append('--%s' % o[1])
1758 options.append('--%s' % o[1])
1764 ui.write("%s\n" % "\n".join(options))
1759 ui.write("%s\n" % "\n".join(options))
1765 return
1760 return
1766
1761
1767 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1762 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1768 if ui.verbose:
1763 if ui.verbose:
1769 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1764 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1770 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1765 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1771
1766
1772 @command('^diff',
1767 @command('^diff',
1773 [('r', 'rev', [], _('revision'), _('REV')),
1768 [('r', 'rev', [], _('revision'), _('REV')),
1774 ('c', 'change', '', _('change made by revision'), _('REV'))
1769 ('c', 'change', '', _('change made by revision'), _('REV'))
1775 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1770 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1776 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1771 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1777 inferrepo=True, cmdtype=readonly)
1772 inferrepo=True, cmdtype=readonly)
1778 def diff(ui, repo, *pats, **opts):
1773 def diff(ui, repo, *pats, **opts):
1779 """diff repository (or selected files)
1774 """diff repository (or selected files)
1780
1775
1781 Show differences between revisions for the specified files.
1776 Show differences between revisions for the specified files.
1782
1777
1783 Differences between files are shown using the unified diff format.
1778 Differences between files are shown using the unified diff format.
1784
1779
1785 .. note::
1780 .. note::
1786
1781
1787 :hg:`diff` may generate unexpected results for merges, as it will
1782 :hg:`diff` may generate unexpected results for merges, as it will
1788 default to comparing against the working directory's first
1783 default to comparing against the working directory's first
1789 parent changeset if no revisions are specified.
1784 parent changeset if no revisions are specified.
1790
1785
1791 When two revision arguments are given, then changes are shown
1786 When two revision arguments are given, then changes are shown
1792 between those revisions. If only one revision is specified then
1787 between those revisions. If only one revision is specified then
1793 that revision is compared to the working directory, and, when no
1788 that revision is compared to the working directory, and, when no
1794 revisions are specified, the working directory files are compared
1789 revisions are specified, the working directory files are compared
1795 to its first parent.
1790 to its first parent.
1796
1791
1797 Alternatively you can specify -c/--change with a revision to see
1792 Alternatively you can specify -c/--change with a revision to see
1798 the changes in that changeset relative to its first parent.
1793 the changes in that changeset relative to its first parent.
1799
1794
1800 Without the -a/--text option, diff will avoid generating diffs of
1795 Without the -a/--text option, diff will avoid generating diffs of
1801 files it detects as binary. With -a, diff will generate a diff
1796 files it detects as binary. With -a, diff will generate a diff
1802 anyway, probably with undesirable results.
1797 anyway, probably with undesirable results.
1803
1798
1804 Use the -g/--git option to generate diffs in the git extended diff
1799 Use the -g/--git option to generate diffs in the git extended diff
1805 format. For more information, read :hg:`help diffs`.
1800 format. For more information, read :hg:`help diffs`.
1806
1801
1807 .. container:: verbose
1802 .. container:: verbose
1808
1803
1809 Examples:
1804 Examples:
1810
1805
1811 - compare a file in the current working directory to its parent::
1806 - compare a file in the current working directory to its parent::
1812
1807
1813 hg diff foo.c
1808 hg diff foo.c
1814
1809
1815 - compare two historical versions of a directory, with rename info::
1810 - compare two historical versions of a directory, with rename info::
1816
1811
1817 hg diff --git -r 1.0:1.2 lib/
1812 hg diff --git -r 1.0:1.2 lib/
1818
1813
1819 - get change stats relative to the last change on some date::
1814 - get change stats relative to the last change on some date::
1820
1815
1821 hg diff --stat -r "date('may 2')"
1816 hg diff --stat -r "date('may 2')"
1822
1817
1823 - diff all newly-added files that contain a keyword::
1818 - diff all newly-added files that contain a keyword::
1824
1819
1825 hg diff "set:added() and grep(GNU)"
1820 hg diff "set:added() and grep(GNU)"
1826
1821
1827 - compare a revision and its parents::
1822 - compare a revision and its parents::
1828
1823
1829 hg diff -c 9353 # compare against first parent
1824 hg diff -c 9353 # compare against first parent
1830 hg diff -r 9353^:9353 # same using revset syntax
1825 hg diff -r 9353^:9353 # same using revset syntax
1831 hg diff -r 9353^2:9353 # compare against the second parent
1826 hg diff -r 9353^2:9353 # compare against the second parent
1832
1827
1833 Returns 0 on success.
1828 Returns 0 on success.
1834 """
1829 """
1835
1830
1836 opts = pycompat.byteskwargs(opts)
1831 opts = pycompat.byteskwargs(opts)
1837 revs = opts.get('rev')
1832 revs = opts.get('rev')
1838 change = opts.get('change')
1833 change = opts.get('change')
1839 stat = opts.get('stat')
1834 stat = opts.get('stat')
1840 reverse = opts.get('reverse')
1835 reverse = opts.get('reverse')
1841
1836
1842 if revs and change:
1837 if revs and change:
1843 msg = _('cannot specify --rev and --change at the same time')
1838 msg = _('cannot specify --rev and --change at the same time')
1844 raise error.Abort(msg)
1839 raise error.Abort(msg)
1845 elif change:
1840 elif change:
1846 node2 = scmutil.revsingle(repo, change, None).node()
1841 node2 = scmutil.revsingle(repo, change, None).node()
1847 node1 = repo[node2].p1().node()
1842 node1 = repo[node2].p1().node()
1848 else:
1843 else:
1849 node1, node2 = scmutil.revpair(repo, revs)
1844 node1, node2 = scmutil.revpair(repo, revs)
1850
1845
1851 if reverse:
1846 if reverse:
1852 node1, node2 = node2, node1
1847 node1, node2 = node2, node1
1853
1848
1854 diffopts = patch.diffallopts(ui, opts)
1849 diffopts = patch.diffallopts(ui, opts)
1855 m = scmutil.match(repo[node2], pats, opts)
1850 m = scmutil.match(repo[node2], pats, opts)
1856 ui.pager('diff')
1851 ui.pager('diff')
1857 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1852 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1858 listsubrepos=opts.get('subrepos'),
1853 listsubrepos=opts.get('subrepos'),
1859 root=opts.get('root'))
1854 root=opts.get('root'))
1860
1855
1861 @command('^export',
1856 @command('^export',
1862 [('o', 'output', '',
1857 [('o', 'output', '',
1863 _('print output to file with formatted name'), _('FORMAT')),
1858 _('print output to file with formatted name'), _('FORMAT')),
1864 ('', 'switch-parent', None, _('diff against the second parent')),
1859 ('', 'switch-parent', None, _('diff against the second parent')),
1865 ('r', 'rev', [], _('revisions to export'), _('REV')),
1860 ('r', 'rev', [], _('revisions to export'), _('REV')),
1866 ] + diffopts,
1861 ] + diffopts,
1867 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1862 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'), cmdtype=readonly)
1868 def export(ui, repo, *changesets, **opts):
1863 def export(ui, repo, *changesets, **opts):
1869 """dump the header and diffs for one or more changesets
1864 """dump the header and diffs for one or more changesets
1870
1865
1871 Print the changeset header and diffs for one or more revisions.
1866 Print the changeset header and diffs for one or more revisions.
1872 If no revision is given, the parent of the working directory is used.
1867 If no revision is given, the parent of the working directory is used.
1873
1868
1874 The information shown in the changeset header is: author, date,
1869 The information shown in the changeset header is: author, date,
1875 branch name (if non-default), changeset hash, parent(s) and commit
1870 branch name (if non-default), changeset hash, parent(s) and commit
1876 comment.
1871 comment.
1877
1872
1878 .. note::
1873 .. note::
1879
1874
1880 :hg:`export` may generate unexpected diff output for merge
1875 :hg:`export` may generate unexpected diff output for merge
1881 changesets, as it will compare the merge changeset against its
1876 changesets, as it will compare the merge changeset against its
1882 first parent only.
1877 first parent only.
1883
1878
1884 Output may be to a file, in which case the name of the file is
1879 Output may be to a file, in which case the name of the file is
1885 given using a format string. The formatting rules are as follows:
1880 given using a format string. The formatting rules are as follows:
1886
1881
1887 :``%%``: literal "%" character
1882 :``%%``: literal "%" character
1888 :``%H``: changeset hash (40 hexadecimal digits)
1883 :``%H``: changeset hash (40 hexadecimal digits)
1889 :``%N``: number of patches being generated
1884 :``%N``: number of patches being generated
1890 :``%R``: changeset revision number
1885 :``%R``: changeset revision number
1891 :``%b``: basename of the exporting repository
1886 :``%b``: basename of the exporting repository
1892 :``%h``: short-form changeset hash (12 hexadecimal digits)
1887 :``%h``: short-form changeset hash (12 hexadecimal digits)
1893 :``%m``: first line of the commit message (only alphanumeric characters)
1888 :``%m``: first line of the commit message (only alphanumeric characters)
1894 :``%n``: zero-padded sequence number, starting at 1
1889 :``%n``: zero-padded sequence number, starting at 1
1895 :``%r``: zero-padded changeset revision number
1890 :``%r``: zero-padded changeset revision number
1896
1891
1897 Without the -a/--text option, export will avoid generating diffs
1892 Without the -a/--text option, export will avoid generating diffs
1898 of files it detects as binary. With -a, export will generate a
1893 of files it detects as binary. With -a, export will generate a
1899 diff anyway, probably with undesirable results.
1894 diff anyway, probably with undesirable results.
1900
1895
1901 Use the -g/--git option to generate diffs in the git extended diff
1896 Use the -g/--git option to generate diffs in the git extended diff
1902 format. See :hg:`help diffs` for more information.
1897 format. See :hg:`help diffs` for more information.
1903
1898
1904 With the --switch-parent option, the diff will be against the
1899 With the --switch-parent option, the diff will be against the
1905 second parent. It can be useful to review a merge.
1900 second parent. It can be useful to review a merge.
1906
1901
1907 .. container:: verbose
1902 .. container:: verbose
1908
1903
1909 Examples:
1904 Examples:
1910
1905
1911 - use export and import to transplant a bugfix to the current
1906 - use export and import to transplant a bugfix to the current
1912 branch::
1907 branch::
1913
1908
1914 hg export -r 9353 | hg import -
1909 hg export -r 9353 | hg import -
1915
1910
1916 - export all the changesets between two revisions to a file with
1911 - export all the changesets between two revisions to a file with
1917 rename information::
1912 rename information::
1918
1913
1919 hg export --git -r 123:150 > changes.txt
1914 hg export --git -r 123:150 > changes.txt
1920
1915
1921 - split outgoing changes into a series of patches with
1916 - split outgoing changes into a series of patches with
1922 descriptive names::
1917 descriptive names::
1923
1918
1924 hg export -r "outgoing()" -o "%n-%m.patch"
1919 hg export -r "outgoing()" -o "%n-%m.patch"
1925
1920
1926 Returns 0 on success.
1921 Returns 0 on success.
1927 """
1922 """
1928 opts = pycompat.byteskwargs(opts)
1923 opts = pycompat.byteskwargs(opts)
1929 changesets += tuple(opts.get('rev', []))
1924 changesets += tuple(opts.get('rev', []))
1930 if not changesets:
1925 if not changesets:
1931 changesets = ['.']
1926 changesets = ['.']
1932 revs = scmutil.revrange(repo, changesets)
1927 revs = scmutil.revrange(repo, changesets)
1933 if not revs:
1928 if not revs:
1934 raise error.Abort(_("export requires at least one changeset"))
1929 raise error.Abort(_("export requires at least one changeset"))
1935 if len(revs) > 1:
1930 if len(revs) > 1:
1936 ui.note(_('exporting patches:\n'))
1931 ui.note(_('exporting patches:\n'))
1937 else:
1932 else:
1938 ui.note(_('exporting patch:\n'))
1933 ui.note(_('exporting patch:\n'))
1939 ui.pager('export')
1934 ui.pager('export')
1940 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1935 cmdutil.export(repo, revs, fntemplate=opts.get('output'),
1941 switch_parent=opts.get('switch_parent'),
1936 switch_parent=opts.get('switch_parent'),
1942 opts=patch.diffallopts(ui, opts))
1937 opts=patch.diffallopts(ui, opts))
1943
1938
1944 @command('files',
1939 @command('files',
1945 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1940 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
1946 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1941 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
1947 ] + walkopts + formatteropts + subrepoopts,
1942 ] + walkopts + formatteropts + subrepoopts,
1948 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1943 _('[OPTION]... [FILE]...'), cmdtype=readonly)
1949 def files(ui, repo, *pats, **opts):
1944 def files(ui, repo, *pats, **opts):
1950 """list tracked files
1945 """list tracked files
1951
1946
1952 Print files under Mercurial control in the working directory or
1947 Print files under Mercurial control in the working directory or
1953 specified revision for given files (excluding removed files).
1948 specified revision for given files (excluding removed files).
1954 Files can be specified as filenames or filesets.
1949 Files can be specified as filenames or filesets.
1955
1950
1956 If no files are given to match, this command prints the names
1951 If no files are given to match, this command prints the names
1957 of all files under Mercurial control.
1952 of all files under Mercurial control.
1958
1953
1959 .. container:: verbose
1954 .. container:: verbose
1960
1955
1961 Examples:
1956 Examples:
1962
1957
1963 - list all files under the current directory::
1958 - list all files under the current directory::
1964
1959
1965 hg files .
1960 hg files .
1966
1961
1967 - shows sizes and flags for current revision::
1962 - shows sizes and flags for current revision::
1968
1963
1969 hg files -vr .
1964 hg files -vr .
1970
1965
1971 - list all files named README::
1966 - list all files named README::
1972
1967
1973 hg files -I "**/README"
1968 hg files -I "**/README"
1974
1969
1975 - list all binary files::
1970 - list all binary files::
1976
1971
1977 hg files "set:binary()"
1972 hg files "set:binary()"
1978
1973
1979 - find files containing a regular expression::
1974 - find files containing a regular expression::
1980
1975
1981 hg files "set:grep('bob')"
1976 hg files "set:grep('bob')"
1982
1977
1983 - search tracked file contents with xargs and grep::
1978 - search tracked file contents with xargs and grep::
1984
1979
1985 hg files -0 | xargs -0 grep foo
1980 hg files -0 | xargs -0 grep foo
1986
1981
1987 See :hg:`help patterns` and :hg:`help filesets` for more information
1982 See :hg:`help patterns` and :hg:`help filesets` for more information
1988 on specifying file patterns.
1983 on specifying file patterns.
1989
1984
1990 Returns 0 if a match is found, 1 otherwise.
1985 Returns 0 if a match is found, 1 otherwise.
1991
1986
1992 """
1987 """
1993
1988
1994 opts = pycompat.byteskwargs(opts)
1989 opts = pycompat.byteskwargs(opts)
1995 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1990 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1996
1991
1997 end = '\n'
1992 end = '\n'
1998 if opts.get('print0'):
1993 if opts.get('print0'):
1999 end = '\0'
1994 end = '\0'
2000 fmt = '%s' + end
1995 fmt = '%s' + end
2001
1996
2002 m = scmutil.match(ctx, pats, opts)
1997 m = scmutil.match(ctx, pats, opts)
2003 ui.pager('files')
1998 ui.pager('files')
2004 with ui.formatter('files', opts) as fm:
1999 with ui.formatter('files', opts) as fm:
2005 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2000 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2006
2001
2007 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2002 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2008 def forget(ui, repo, *pats, **opts):
2003 def forget(ui, repo, *pats, **opts):
2009 """forget the specified files on the next commit
2004 """forget the specified files on the next commit
2010
2005
2011 Mark the specified files so they will no longer be tracked
2006 Mark the specified files so they will no longer be tracked
2012 after the next commit.
2007 after the next commit.
2013
2008
2014 This only removes files from the current branch, not from the
2009 This only removes files from the current branch, not from the
2015 entire project history, and it does not delete them from the
2010 entire project history, and it does not delete them from the
2016 working directory.
2011 working directory.
2017
2012
2018 To delete the file from the working directory, see :hg:`remove`.
2013 To delete the file from the working directory, see :hg:`remove`.
2019
2014
2020 To undo a forget before the next commit, see :hg:`add`.
2015 To undo a forget before the next commit, see :hg:`add`.
2021
2016
2022 .. container:: verbose
2017 .. container:: verbose
2023
2018
2024 Examples:
2019 Examples:
2025
2020
2026 - forget newly-added binary files::
2021 - forget newly-added binary files::
2027
2022
2028 hg forget "set:added() and binary()"
2023 hg forget "set:added() and binary()"
2029
2024
2030 - forget files that would be excluded by .hgignore::
2025 - forget files that would be excluded by .hgignore::
2031
2026
2032 hg forget "set:hgignore()"
2027 hg forget "set:hgignore()"
2033
2028
2034 Returns 0 on success.
2029 Returns 0 on success.
2035 """
2030 """
2036
2031
2037 opts = pycompat.byteskwargs(opts)
2032 opts = pycompat.byteskwargs(opts)
2038 if not pats:
2033 if not pats:
2039 raise error.Abort(_('no files specified'))
2034 raise error.Abort(_('no files specified'))
2040
2035
2041 m = scmutil.match(repo[None], pats, opts)
2036 m = scmutil.match(repo[None], pats, opts)
2042 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2037 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2043 return rejected and 1 or 0
2038 return rejected and 1 or 0
2044
2039
2045 @command(
2040 @command(
2046 'graft',
2041 'graft',
2047 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2042 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2048 ('c', 'continue', False, _('resume interrupted graft')),
2043 ('c', 'continue', False, _('resume interrupted graft')),
2049 ('e', 'edit', False, _('invoke editor on commit messages')),
2044 ('e', 'edit', False, _('invoke editor on commit messages')),
2050 ('', 'log', None, _('append graft info to log message')),
2045 ('', 'log', None, _('append graft info to log message')),
2051 ('f', 'force', False, _('force graft')),
2046 ('f', 'force', False, _('force graft')),
2052 ('D', 'currentdate', False,
2047 ('D', 'currentdate', False,
2053 _('record the current date as commit date')),
2048 _('record the current date as commit date')),
2054 ('U', 'currentuser', False,
2049 ('U', 'currentuser', False,
2055 _('record the current user as committer'), _('DATE'))]
2050 _('record the current user as committer'), _('DATE'))]
2056 + commitopts2 + mergetoolopts + dryrunopts,
2051 + commitopts2 + mergetoolopts + dryrunopts,
2057 _('[OPTION]... [-r REV]... REV...'))
2052 _('[OPTION]... [-r REV]... REV...'))
2058 def graft(ui, repo, *revs, **opts):
2053 def graft(ui, repo, *revs, **opts):
2059 '''copy changes from other branches onto the current branch
2054 '''copy changes from other branches onto the current branch
2060
2055
2061 This command uses Mercurial's merge logic to copy individual
2056 This command uses Mercurial's merge logic to copy individual
2062 changes from other branches without merging branches in the
2057 changes from other branches without merging branches in the
2063 history graph. This is sometimes known as 'backporting' or
2058 history graph. This is sometimes known as 'backporting' or
2064 'cherry-picking'. By default, graft will copy user, date, and
2059 'cherry-picking'. By default, graft will copy user, date, and
2065 description from the source changesets.
2060 description from the source changesets.
2066
2061
2067 Changesets that are ancestors of the current revision, that have
2062 Changesets that are ancestors of the current revision, that have
2068 already been grafted, or that are merges will be skipped.
2063 already been grafted, or that are merges will be skipped.
2069
2064
2070 If --log is specified, log messages will have a comment appended
2065 If --log is specified, log messages will have a comment appended
2071 of the form::
2066 of the form::
2072
2067
2073 (grafted from CHANGESETHASH)
2068 (grafted from CHANGESETHASH)
2074
2069
2075 If --force is specified, revisions will be grafted even if they
2070 If --force is specified, revisions will be grafted even if they
2076 are already ancestors of, or have been grafted to, the destination.
2071 are already ancestors of, or have been grafted to, the destination.
2077 This is useful when the revisions have since been backed out.
2072 This is useful when the revisions have since been backed out.
2078
2073
2079 If a graft merge results in conflicts, the graft process is
2074 If a graft merge results in conflicts, the graft process is
2080 interrupted so that the current merge can be manually resolved.
2075 interrupted so that the current merge can be manually resolved.
2081 Once all conflicts are addressed, the graft process can be
2076 Once all conflicts are addressed, the graft process can be
2082 continued with the -c/--continue option.
2077 continued with the -c/--continue option.
2083
2078
2084 .. note::
2079 .. note::
2085
2080
2086 The -c/--continue option does not reapply earlier options, except
2081 The -c/--continue option does not reapply earlier options, except
2087 for --force.
2082 for --force.
2088
2083
2089 .. container:: verbose
2084 .. container:: verbose
2090
2085
2091 Examples:
2086 Examples:
2092
2087
2093 - copy a single change to the stable branch and edit its description::
2088 - copy a single change to the stable branch and edit its description::
2094
2089
2095 hg update stable
2090 hg update stable
2096 hg graft --edit 9393
2091 hg graft --edit 9393
2097
2092
2098 - graft a range of changesets with one exception, updating dates::
2093 - graft a range of changesets with one exception, updating dates::
2099
2094
2100 hg graft -D "2085::2093 and not 2091"
2095 hg graft -D "2085::2093 and not 2091"
2101
2096
2102 - continue a graft after resolving conflicts::
2097 - continue a graft after resolving conflicts::
2103
2098
2104 hg graft -c
2099 hg graft -c
2105
2100
2106 - show the source of a grafted changeset::
2101 - show the source of a grafted changeset::
2107
2102
2108 hg log --debug -r .
2103 hg log --debug -r .
2109
2104
2110 - show revisions sorted by date::
2105 - show revisions sorted by date::
2111
2106
2112 hg log -r "sort(all(), date)"
2107 hg log -r "sort(all(), date)"
2113
2108
2114 See :hg:`help revisions` for more about specifying revisions.
2109 See :hg:`help revisions` for more about specifying revisions.
2115
2110
2116 Returns 0 on successful completion.
2111 Returns 0 on successful completion.
2117 '''
2112 '''
2118 with repo.wlock():
2113 with repo.wlock():
2119 return _dograft(ui, repo, *revs, **opts)
2114 return _dograft(ui, repo, *revs, **opts)
2120
2115
2121 def _dograft(ui, repo, *revs, **opts):
2116 def _dograft(ui, repo, *revs, **opts):
2122 opts = pycompat.byteskwargs(opts)
2117 opts = pycompat.byteskwargs(opts)
2123 if revs and opts.get('rev'):
2118 if revs and opts.get('rev'):
2124 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2119 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2125 'revision ordering!\n'))
2120 'revision ordering!\n'))
2126
2121
2127 revs = list(revs)
2122 revs = list(revs)
2128 revs.extend(opts.get('rev'))
2123 revs.extend(opts.get('rev'))
2129
2124
2130 if not opts.get('user') and opts.get('currentuser'):
2125 if not opts.get('user') and opts.get('currentuser'):
2131 opts['user'] = ui.username()
2126 opts['user'] = ui.username()
2132 if not opts.get('date') and opts.get('currentdate'):
2127 if not opts.get('date') and opts.get('currentdate'):
2133 opts['date'] = "%d %d" % util.makedate()
2128 opts['date'] = "%d %d" % util.makedate()
2134
2129
2135 editor = cmdutil.getcommiteditor(editform='graft',
2130 editor = cmdutil.getcommiteditor(editform='graft',
2136 **pycompat.strkwargs(opts))
2131 **pycompat.strkwargs(opts))
2137
2132
2138 cont = False
2133 cont = False
2139 if opts.get('continue'):
2134 if opts.get('continue'):
2140 cont = True
2135 cont = True
2141 if revs:
2136 if revs:
2142 raise error.Abort(_("can't specify --continue and revisions"))
2137 raise error.Abort(_("can't specify --continue and revisions"))
2143 # read in unfinished revisions
2138 # read in unfinished revisions
2144 try:
2139 try:
2145 nodes = repo.vfs.read('graftstate').splitlines()
2140 nodes = repo.vfs.read('graftstate').splitlines()
2146 revs = [repo[node].rev() for node in nodes]
2141 revs = [repo[node].rev() for node in nodes]
2147 except IOError as inst:
2142 except IOError as inst:
2148 if inst.errno != errno.ENOENT:
2143 if inst.errno != errno.ENOENT:
2149 raise
2144 raise
2150 cmdutil.wrongtooltocontinue(repo, _('graft'))
2145 cmdutil.wrongtooltocontinue(repo, _('graft'))
2151 else:
2146 else:
2152 cmdutil.checkunfinished(repo)
2147 cmdutil.checkunfinished(repo)
2153 cmdutil.bailifchanged(repo)
2148 cmdutil.bailifchanged(repo)
2154 if not revs:
2149 if not revs:
2155 raise error.Abort(_('no revisions specified'))
2150 raise error.Abort(_('no revisions specified'))
2156 revs = scmutil.revrange(repo, revs)
2151 revs = scmutil.revrange(repo, revs)
2157
2152
2158 skipped = set()
2153 skipped = set()
2159 # check for merges
2154 # check for merges
2160 for rev in repo.revs('%ld and merge()', revs):
2155 for rev in repo.revs('%ld and merge()', revs):
2161 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2156 ui.warn(_('skipping ungraftable merge revision %d\n') % rev)
2162 skipped.add(rev)
2157 skipped.add(rev)
2163 revs = [r for r in revs if r not in skipped]
2158 revs = [r for r in revs if r not in skipped]
2164 if not revs:
2159 if not revs:
2165 return -1
2160 return -1
2166
2161
2167 # Don't check in the --continue case, in effect retaining --force across
2162 # Don't check in the --continue case, in effect retaining --force across
2168 # --continues. That's because without --force, any revisions we decided to
2163 # --continues. That's because without --force, any revisions we decided to
2169 # skip would have been filtered out here, so they wouldn't have made their
2164 # skip would have been filtered out here, so they wouldn't have made their
2170 # way to the graftstate. With --force, any revisions we would have otherwise
2165 # way to the graftstate. With --force, any revisions we would have otherwise
2171 # skipped would not have been filtered out, and if they hadn't been applied
2166 # skipped would not have been filtered out, and if they hadn't been applied
2172 # already, they'd have been in the graftstate.
2167 # already, they'd have been in the graftstate.
2173 if not (cont or opts.get('force')):
2168 if not (cont or opts.get('force')):
2174 # check for ancestors of dest branch
2169 # check for ancestors of dest branch
2175 crev = repo['.'].rev()
2170 crev = repo['.'].rev()
2176 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2171 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2177 # XXX make this lazy in the future
2172 # XXX make this lazy in the future
2178 # don't mutate while iterating, create a copy
2173 # don't mutate while iterating, create a copy
2179 for rev in list(revs):
2174 for rev in list(revs):
2180 if rev in ancestors:
2175 if rev in ancestors:
2181 ui.warn(_('skipping ancestor revision %d:%s\n') %
2176 ui.warn(_('skipping ancestor revision %d:%s\n') %
2182 (rev, repo[rev]))
2177 (rev, repo[rev]))
2183 # XXX remove on list is slow
2178 # XXX remove on list is slow
2184 revs.remove(rev)
2179 revs.remove(rev)
2185 if not revs:
2180 if not revs:
2186 return -1
2181 return -1
2187
2182
2188 # analyze revs for earlier grafts
2183 # analyze revs for earlier grafts
2189 ids = {}
2184 ids = {}
2190 for ctx in repo.set("%ld", revs):
2185 for ctx in repo.set("%ld", revs):
2191 ids[ctx.hex()] = ctx.rev()
2186 ids[ctx.hex()] = ctx.rev()
2192 n = ctx.extra().get('source')
2187 n = ctx.extra().get('source')
2193 if n:
2188 if n:
2194 ids[n] = ctx.rev()
2189 ids[n] = ctx.rev()
2195
2190
2196 # check ancestors for earlier grafts
2191 # check ancestors for earlier grafts
2197 ui.debug('scanning for duplicate grafts\n')
2192 ui.debug('scanning for duplicate grafts\n')
2198
2193
2199 # The only changesets we can be sure doesn't contain grafts of any
2194 # The only changesets we can be sure doesn't contain grafts of any
2200 # revs, are the ones that are common ancestors of *all* revs:
2195 # revs, are the ones that are common ancestors of *all* revs:
2201 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2196 for rev in repo.revs('only(%d,ancestor(%ld))', crev, revs):
2202 ctx = repo[rev]
2197 ctx = repo[rev]
2203 n = ctx.extra().get('source')
2198 n = ctx.extra().get('source')
2204 if n in ids:
2199 if n in ids:
2205 try:
2200 try:
2206 r = repo[n].rev()
2201 r = repo[n].rev()
2207 except error.RepoLookupError:
2202 except error.RepoLookupError:
2208 r = None
2203 r = None
2209 if r in revs:
2204 if r in revs:
2210 ui.warn(_('skipping revision %d:%s '
2205 ui.warn(_('skipping revision %d:%s '
2211 '(already grafted to %d:%s)\n')
2206 '(already grafted to %d:%s)\n')
2212 % (r, repo[r], rev, ctx))
2207 % (r, repo[r], rev, ctx))
2213 revs.remove(r)
2208 revs.remove(r)
2214 elif ids[n] in revs:
2209 elif ids[n] in revs:
2215 if r is None:
2210 if r is None:
2216 ui.warn(_('skipping already grafted revision %d:%s '
2211 ui.warn(_('skipping already grafted revision %d:%s '
2217 '(%d:%s also has unknown origin %s)\n')
2212 '(%d:%s also has unknown origin %s)\n')
2218 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2213 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2219 else:
2214 else:
2220 ui.warn(_('skipping already grafted revision %d:%s '
2215 ui.warn(_('skipping already grafted revision %d:%s '
2221 '(%d:%s also has origin %d:%s)\n')
2216 '(%d:%s also has origin %d:%s)\n')
2222 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2217 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2223 revs.remove(ids[n])
2218 revs.remove(ids[n])
2224 elif ctx.hex() in ids:
2219 elif ctx.hex() in ids:
2225 r = ids[ctx.hex()]
2220 r = ids[ctx.hex()]
2226 ui.warn(_('skipping already grafted revision %d:%s '
2221 ui.warn(_('skipping already grafted revision %d:%s '
2227 '(was grafted from %d:%s)\n') %
2222 '(was grafted from %d:%s)\n') %
2228 (r, repo[r], rev, ctx))
2223 (r, repo[r], rev, ctx))
2229 revs.remove(r)
2224 revs.remove(r)
2230 if not revs:
2225 if not revs:
2231 return -1
2226 return -1
2232
2227
2233 for pos, ctx in enumerate(repo.set("%ld", revs)):
2228 for pos, ctx in enumerate(repo.set("%ld", revs)):
2234 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2229 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2235 ctx.description().split('\n', 1)[0])
2230 ctx.description().split('\n', 1)[0])
2236 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2231 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2237 if names:
2232 if names:
2238 desc += ' (%s)' % ' '.join(names)
2233 desc += ' (%s)' % ' '.join(names)
2239 ui.status(_('grafting %s\n') % desc)
2234 ui.status(_('grafting %s\n') % desc)
2240 if opts.get('dry_run'):
2235 if opts.get('dry_run'):
2241 continue
2236 continue
2242
2237
2243 source = ctx.extra().get('source')
2238 source = ctx.extra().get('source')
2244 extra = {}
2239 extra = {}
2245 if source:
2240 if source:
2246 extra['source'] = source
2241 extra['source'] = source
2247 extra['intermediate-source'] = ctx.hex()
2242 extra['intermediate-source'] = ctx.hex()
2248 else:
2243 else:
2249 extra['source'] = ctx.hex()
2244 extra['source'] = ctx.hex()
2250 user = ctx.user()
2245 user = ctx.user()
2251 if opts.get('user'):
2246 if opts.get('user'):
2252 user = opts['user']
2247 user = opts['user']
2253 date = ctx.date()
2248 date = ctx.date()
2254 if opts.get('date'):
2249 if opts.get('date'):
2255 date = opts['date']
2250 date = opts['date']
2256 message = ctx.description()
2251 message = ctx.description()
2257 if opts.get('log'):
2252 if opts.get('log'):
2258 message += '\n(grafted from %s)' % ctx.hex()
2253 message += '\n(grafted from %s)' % ctx.hex()
2259
2254
2260 # we don't merge the first commit when continuing
2255 # we don't merge the first commit when continuing
2261 if not cont:
2256 if not cont:
2262 # perform the graft merge with p1(rev) as 'ancestor'
2257 # perform the graft merge with p1(rev) as 'ancestor'
2263 try:
2258 try:
2264 # ui.forcemerge is an internal variable, do not document
2259 # ui.forcemerge is an internal variable, do not document
2265 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2260 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2266 'graft')
2261 'graft')
2267 stats = mergemod.graft(repo, ctx, ctx.p1(),
2262 stats = mergemod.graft(repo, ctx, ctx.p1(),
2268 ['local', 'graft'])
2263 ['local', 'graft'])
2269 finally:
2264 finally:
2270 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2265 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2271 # report any conflicts
2266 # report any conflicts
2272 if stats and stats[3] > 0:
2267 if stats and stats[3] > 0:
2273 # write out state for --continue
2268 # write out state for --continue
2274 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2269 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2275 repo.vfs.write('graftstate', ''.join(nodelines))
2270 repo.vfs.write('graftstate', ''.join(nodelines))
2276 extra = ''
2271 extra = ''
2277 if opts.get('user'):
2272 if opts.get('user'):
2278 extra += ' --user %s' % util.shellquote(opts['user'])
2273 extra += ' --user %s' % util.shellquote(opts['user'])
2279 if opts.get('date'):
2274 if opts.get('date'):
2280 extra += ' --date %s' % util.shellquote(opts['date'])
2275 extra += ' --date %s' % util.shellquote(opts['date'])
2281 if opts.get('log'):
2276 if opts.get('log'):
2282 extra += ' --log'
2277 extra += ' --log'
2283 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2278 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2284 raise error.Abort(
2279 raise error.Abort(
2285 _("unresolved conflicts, can't continue"),
2280 _("unresolved conflicts, can't continue"),
2286 hint=hint)
2281 hint=hint)
2287 else:
2282 else:
2288 cont = False
2283 cont = False
2289
2284
2290 # commit
2285 # commit
2291 node = repo.commit(text=message, user=user,
2286 node = repo.commit(text=message, user=user,
2292 date=date, extra=extra, editor=editor)
2287 date=date, extra=extra, editor=editor)
2293 if node is None:
2288 if node is None:
2294 ui.warn(
2289 ui.warn(
2295 _('note: graft of %d:%s created no changes to commit\n') %
2290 _('note: graft of %d:%s created no changes to commit\n') %
2296 (ctx.rev(), ctx))
2291 (ctx.rev(), ctx))
2297
2292
2298 # remove state when we complete successfully
2293 # remove state when we complete successfully
2299 if not opts.get('dry_run'):
2294 if not opts.get('dry_run'):
2300 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2295 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2301
2296
2302 return 0
2297 return 0
2303
2298
2304 @command('grep',
2299 @command('grep',
2305 [('0', 'print0', None, _('end fields with NUL')),
2300 [('0', 'print0', None, _('end fields with NUL')),
2306 ('', 'all', None, _('print all revisions that match')),
2301 ('', 'all', None, _('print all revisions that match')),
2307 ('a', 'text', None, _('treat all files as text')),
2302 ('a', 'text', None, _('treat all files as text')),
2308 ('f', 'follow', None,
2303 ('f', 'follow', None,
2309 _('follow changeset history,'
2304 _('follow changeset history,'
2310 ' or file history across copies and renames')),
2305 ' or file history across copies and renames')),
2311 ('i', 'ignore-case', None, _('ignore case when matching')),
2306 ('i', 'ignore-case', None, _('ignore case when matching')),
2312 ('l', 'files-with-matches', None,
2307 ('l', 'files-with-matches', None,
2313 _('print only filenames and revisions that match')),
2308 _('print only filenames and revisions that match')),
2314 ('n', 'line-number', None, _('print matching line numbers')),
2309 ('n', 'line-number', None, _('print matching line numbers')),
2315 ('r', 'rev', [],
2310 ('r', 'rev', [],
2316 _('only search files changed within revision range'), _('REV')),
2311 _('only search files changed within revision range'), _('REV')),
2317 ('u', 'user', None, _('list the author (long with -v)')),
2312 ('u', 'user', None, _('list the author (long with -v)')),
2318 ('d', 'date', None, _('list the date (short with -q)')),
2313 ('d', 'date', None, _('list the date (short with -q)')),
2319 ] + formatteropts + walkopts,
2314 ] + formatteropts + walkopts,
2320 _('[OPTION]... PATTERN [FILE]...'),
2315 _('[OPTION]... PATTERN [FILE]...'),
2321 inferrepo=True, cmdtype=readonly)
2316 inferrepo=True, cmdtype=readonly)
2322 def grep(ui, repo, pattern, *pats, **opts):
2317 def grep(ui, repo, pattern, *pats, **opts):
2323 """search revision history for a pattern in specified files
2318 """search revision history for a pattern in specified files
2324
2319
2325 Search revision history for a regular expression in the specified
2320 Search revision history for a regular expression in the specified
2326 files or the entire project.
2321 files or the entire project.
2327
2322
2328 By default, grep prints the most recent revision number for each
2323 By default, grep prints the most recent revision number for each
2329 file in which it finds a match. To get it to print every revision
2324 file in which it finds a match. To get it to print every revision
2330 that contains a change in match status ("-" for a match that becomes
2325 that contains a change in match status ("-" for a match that becomes
2331 a non-match, or "+" for a non-match that becomes a match), use the
2326 a non-match, or "+" for a non-match that becomes a match), use the
2332 --all flag.
2327 --all flag.
2333
2328
2334 PATTERN can be any Python (roughly Perl-compatible) regular
2329 PATTERN can be any Python (roughly Perl-compatible) regular
2335 expression.
2330 expression.
2336
2331
2337 If no FILEs are specified (and -f/--follow isn't set), all files in
2332 If no FILEs are specified (and -f/--follow isn't set), all files in
2338 the repository are searched, including those that don't exist in the
2333 the repository are searched, including those that don't exist in the
2339 current branch or have been deleted in a prior changeset.
2334 current branch or have been deleted in a prior changeset.
2340
2335
2341 Returns 0 if a match is found, 1 otherwise.
2336 Returns 0 if a match is found, 1 otherwise.
2342 """
2337 """
2343 opts = pycompat.byteskwargs(opts)
2338 opts = pycompat.byteskwargs(opts)
2344 reflags = re.M
2339 reflags = re.M
2345 if opts.get('ignore_case'):
2340 if opts.get('ignore_case'):
2346 reflags |= re.I
2341 reflags |= re.I
2347 try:
2342 try:
2348 regexp = util.re.compile(pattern, reflags)
2343 regexp = util.re.compile(pattern, reflags)
2349 except re.error as inst:
2344 except re.error as inst:
2350 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2345 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2351 return 1
2346 return 1
2352 sep, eol = ':', '\n'
2347 sep, eol = ':', '\n'
2353 if opts.get('print0'):
2348 if opts.get('print0'):
2354 sep = eol = '\0'
2349 sep = eol = '\0'
2355
2350
2356 getfile = util.lrucachefunc(repo.file)
2351 getfile = util.lrucachefunc(repo.file)
2357
2352
2358 def matchlines(body):
2353 def matchlines(body):
2359 begin = 0
2354 begin = 0
2360 linenum = 0
2355 linenum = 0
2361 while begin < len(body):
2356 while begin < len(body):
2362 match = regexp.search(body, begin)
2357 match = regexp.search(body, begin)
2363 if not match:
2358 if not match:
2364 break
2359 break
2365 mstart, mend = match.span()
2360 mstart, mend = match.span()
2366 linenum += body.count('\n', begin, mstart) + 1
2361 linenum += body.count('\n', begin, mstart) + 1
2367 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2362 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2368 begin = body.find('\n', mend) + 1 or len(body) + 1
2363 begin = body.find('\n', mend) + 1 or len(body) + 1
2369 lend = begin - 1
2364 lend = begin - 1
2370 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2365 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2371
2366
2372 class linestate(object):
2367 class linestate(object):
2373 def __init__(self, line, linenum, colstart, colend):
2368 def __init__(self, line, linenum, colstart, colend):
2374 self.line = line
2369 self.line = line
2375 self.linenum = linenum
2370 self.linenum = linenum
2376 self.colstart = colstart
2371 self.colstart = colstart
2377 self.colend = colend
2372 self.colend = colend
2378
2373
2379 def __hash__(self):
2374 def __hash__(self):
2380 return hash((self.linenum, self.line))
2375 return hash((self.linenum, self.line))
2381
2376
2382 def __eq__(self, other):
2377 def __eq__(self, other):
2383 return self.line == other.line
2378 return self.line == other.line
2384
2379
2385 def findpos(self):
2380 def findpos(self):
2386 """Iterate all (start, end) indices of matches"""
2381 """Iterate all (start, end) indices of matches"""
2387 yield self.colstart, self.colend
2382 yield self.colstart, self.colend
2388 p = self.colend
2383 p = self.colend
2389 while p < len(self.line):
2384 while p < len(self.line):
2390 m = regexp.search(self.line, p)
2385 m = regexp.search(self.line, p)
2391 if not m:
2386 if not m:
2392 break
2387 break
2393 yield m.span()
2388 yield m.span()
2394 p = m.end()
2389 p = m.end()
2395
2390
2396 matches = {}
2391 matches = {}
2397 copies = {}
2392 copies = {}
2398 def grepbody(fn, rev, body):
2393 def grepbody(fn, rev, body):
2399 matches[rev].setdefault(fn, [])
2394 matches[rev].setdefault(fn, [])
2400 m = matches[rev][fn]
2395 m = matches[rev][fn]
2401 for lnum, cstart, cend, line in matchlines(body):
2396 for lnum, cstart, cend, line in matchlines(body):
2402 s = linestate(line, lnum, cstart, cend)
2397 s = linestate(line, lnum, cstart, cend)
2403 m.append(s)
2398 m.append(s)
2404
2399
2405 def difflinestates(a, b):
2400 def difflinestates(a, b):
2406 sm = difflib.SequenceMatcher(None, a, b)
2401 sm = difflib.SequenceMatcher(None, a, b)
2407 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2402 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2408 if tag == 'insert':
2403 if tag == 'insert':
2409 for i in xrange(blo, bhi):
2404 for i in xrange(blo, bhi):
2410 yield ('+', b[i])
2405 yield ('+', b[i])
2411 elif tag == 'delete':
2406 elif tag == 'delete':
2412 for i in xrange(alo, ahi):
2407 for i in xrange(alo, ahi):
2413 yield ('-', a[i])
2408 yield ('-', a[i])
2414 elif tag == 'replace':
2409 elif tag == 'replace':
2415 for i in xrange(alo, ahi):
2410 for i in xrange(alo, ahi):
2416 yield ('-', a[i])
2411 yield ('-', a[i])
2417 for i in xrange(blo, bhi):
2412 for i in xrange(blo, bhi):
2418 yield ('+', b[i])
2413 yield ('+', b[i])
2419
2414
2420 def display(fm, fn, ctx, pstates, states):
2415 def display(fm, fn, ctx, pstates, states):
2421 rev = ctx.rev()
2416 rev = ctx.rev()
2422 if fm.isplain():
2417 if fm.isplain():
2423 formatuser = ui.shortuser
2418 formatuser = ui.shortuser
2424 else:
2419 else:
2425 formatuser = str
2420 formatuser = str
2426 if ui.quiet:
2421 if ui.quiet:
2427 datefmt = '%Y-%m-%d'
2422 datefmt = '%Y-%m-%d'
2428 else:
2423 else:
2429 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2424 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2430 found = False
2425 found = False
2431 @util.cachefunc
2426 @util.cachefunc
2432 def binary():
2427 def binary():
2433 flog = getfile(fn)
2428 flog = getfile(fn)
2434 return util.binary(flog.read(ctx.filenode(fn)))
2429 return util.binary(flog.read(ctx.filenode(fn)))
2435
2430
2436 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2431 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2437 if opts.get('all'):
2432 if opts.get('all'):
2438 iter = difflinestates(pstates, states)
2433 iter = difflinestates(pstates, states)
2439 else:
2434 else:
2440 iter = [('', l) for l in states]
2435 iter = [('', l) for l in states]
2441 for change, l in iter:
2436 for change, l in iter:
2442 fm.startitem()
2437 fm.startitem()
2443 fm.data(node=fm.hexfunc(ctx.node()))
2438 fm.data(node=fm.hexfunc(ctx.node()))
2444 cols = [
2439 cols = [
2445 ('filename', fn, True),
2440 ('filename', fn, True),
2446 ('rev', rev, True),
2441 ('rev', rev, True),
2447 ('linenumber', l.linenum, opts.get('line_number')),
2442 ('linenumber', l.linenum, opts.get('line_number')),
2448 ]
2443 ]
2449 if opts.get('all'):
2444 if opts.get('all'):
2450 cols.append(('change', change, True))
2445 cols.append(('change', change, True))
2451 cols.extend([
2446 cols.extend([
2452 ('user', formatuser(ctx.user()), opts.get('user')),
2447 ('user', formatuser(ctx.user()), opts.get('user')),
2453 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2448 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2454 ])
2449 ])
2455 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2450 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2456 for name, data, cond in cols:
2451 for name, data, cond in cols:
2457 field = fieldnamemap.get(name, name)
2452 field = fieldnamemap.get(name, name)
2458 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2453 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2459 if cond and name != lastcol:
2454 if cond and name != lastcol:
2460 fm.plain(sep, label='grep.sep')
2455 fm.plain(sep, label='grep.sep')
2461 if not opts.get('files_with_matches'):
2456 if not opts.get('files_with_matches'):
2462 fm.plain(sep, label='grep.sep')
2457 fm.plain(sep, label='grep.sep')
2463 if not opts.get('text') and binary():
2458 if not opts.get('text') and binary():
2464 fm.plain(_(" Binary file matches"))
2459 fm.plain(_(" Binary file matches"))
2465 else:
2460 else:
2466 displaymatches(fm.nested('texts'), l)
2461 displaymatches(fm.nested('texts'), l)
2467 fm.plain(eol)
2462 fm.plain(eol)
2468 found = True
2463 found = True
2469 if opts.get('files_with_matches'):
2464 if opts.get('files_with_matches'):
2470 break
2465 break
2471 return found
2466 return found
2472
2467
2473 def displaymatches(fm, l):
2468 def displaymatches(fm, l):
2474 p = 0
2469 p = 0
2475 for s, e in l.findpos():
2470 for s, e in l.findpos():
2476 if p < s:
2471 if p < s:
2477 fm.startitem()
2472 fm.startitem()
2478 fm.write('text', '%s', l.line[p:s])
2473 fm.write('text', '%s', l.line[p:s])
2479 fm.data(matched=False)
2474 fm.data(matched=False)
2480 fm.startitem()
2475 fm.startitem()
2481 fm.write('text', '%s', l.line[s:e], label='grep.match')
2476 fm.write('text', '%s', l.line[s:e], label='grep.match')
2482 fm.data(matched=True)
2477 fm.data(matched=True)
2483 p = e
2478 p = e
2484 if p < len(l.line):
2479 if p < len(l.line):
2485 fm.startitem()
2480 fm.startitem()
2486 fm.write('text', '%s', l.line[p:])
2481 fm.write('text', '%s', l.line[p:])
2487 fm.data(matched=False)
2482 fm.data(matched=False)
2488 fm.end()
2483 fm.end()
2489
2484
2490 skip = {}
2485 skip = {}
2491 revfiles = {}
2486 revfiles = {}
2492 match = scmutil.match(repo[None], pats, opts)
2487 match = scmutil.match(repo[None], pats, opts)
2493 found = False
2488 found = False
2494 follow = opts.get('follow')
2489 follow = opts.get('follow')
2495
2490
2496 def prep(ctx, fns):
2491 def prep(ctx, fns):
2497 rev = ctx.rev()
2492 rev = ctx.rev()
2498 pctx = ctx.p1()
2493 pctx = ctx.p1()
2499 parent = pctx.rev()
2494 parent = pctx.rev()
2500 matches.setdefault(rev, {})
2495 matches.setdefault(rev, {})
2501 matches.setdefault(parent, {})
2496 matches.setdefault(parent, {})
2502 files = revfiles.setdefault(rev, [])
2497 files = revfiles.setdefault(rev, [])
2503 for fn in fns:
2498 for fn in fns:
2504 flog = getfile(fn)
2499 flog = getfile(fn)
2505 try:
2500 try:
2506 fnode = ctx.filenode(fn)
2501 fnode = ctx.filenode(fn)
2507 except error.LookupError:
2502 except error.LookupError:
2508 continue
2503 continue
2509
2504
2510 copied = flog.renamed(fnode)
2505 copied = flog.renamed(fnode)
2511 copy = follow and copied and copied[0]
2506 copy = follow and copied and copied[0]
2512 if copy:
2507 if copy:
2513 copies.setdefault(rev, {})[fn] = copy
2508 copies.setdefault(rev, {})[fn] = copy
2514 if fn in skip:
2509 if fn in skip:
2515 if copy:
2510 if copy:
2516 skip[copy] = True
2511 skip[copy] = True
2517 continue
2512 continue
2518 files.append(fn)
2513 files.append(fn)
2519
2514
2520 if fn not in matches[rev]:
2515 if fn not in matches[rev]:
2521 grepbody(fn, rev, flog.read(fnode))
2516 grepbody(fn, rev, flog.read(fnode))
2522
2517
2523 pfn = copy or fn
2518 pfn = copy or fn
2524 if pfn not in matches[parent]:
2519 if pfn not in matches[parent]:
2525 try:
2520 try:
2526 fnode = pctx.filenode(pfn)
2521 fnode = pctx.filenode(pfn)
2527 grepbody(pfn, parent, flog.read(fnode))
2522 grepbody(pfn, parent, flog.read(fnode))
2528 except error.LookupError:
2523 except error.LookupError:
2529 pass
2524 pass
2530
2525
2531 ui.pager('grep')
2526 ui.pager('grep')
2532 fm = ui.formatter('grep', opts)
2527 fm = ui.formatter('grep', opts)
2533 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2528 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
2534 rev = ctx.rev()
2529 rev = ctx.rev()
2535 parent = ctx.p1().rev()
2530 parent = ctx.p1().rev()
2536 for fn in sorted(revfiles.get(rev, [])):
2531 for fn in sorted(revfiles.get(rev, [])):
2537 states = matches[rev][fn]
2532 states = matches[rev][fn]
2538 copy = copies.get(rev, {}).get(fn)
2533 copy = copies.get(rev, {}).get(fn)
2539 if fn in skip:
2534 if fn in skip:
2540 if copy:
2535 if copy:
2541 skip[copy] = True
2536 skip[copy] = True
2542 continue
2537 continue
2543 pstates = matches.get(parent, {}).get(copy or fn, [])
2538 pstates = matches.get(parent, {}).get(copy or fn, [])
2544 if pstates or states:
2539 if pstates or states:
2545 r = display(fm, fn, ctx, pstates, states)
2540 r = display(fm, fn, ctx, pstates, states)
2546 found = found or r
2541 found = found or r
2547 if r and not opts.get('all'):
2542 if r and not opts.get('all'):
2548 skip[fn] = True
2543 skip[fn] = True
2549 if copy:
2544 if copy:
2550 skip[copy] = True
2545 skip[copy] = True
2551 del matches[rev]
2546 del matches[rev]
2552 del revfiles[rev]
2547 del revfiles[rev]
2553 fm.end()
2548 fm.end()
2554
2549
2555 return not found
2550 return not found
2556
2551
2557 @command('heads',
2552 @command('heads',
2558 [('r', 'rev', '',
2553 [('r', 'rev', '',
2559 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2554 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2560 ('t', 'topo', False, _('show topological heads only')),
2555 ('t', 'topo', False, _('show topological heads only')),
2561 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2556 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2562 ('c', 'closed', False, _('show normal and closed branch heads')),
2557 ('c', 'closed', False, _('show normal and closed branch heads')),
2563 ] + templateopts,
2558 ] + templateopts,
2564 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2559 _('[-ct] [-r STARTREV] [REV]...'), cmdtype=readonly)
2565 def heads(ui, repo, *branchrevs, **opts):
2560 def heads(ui, repo, *branchrevs, **opts):
2566 """show branch heads
2561 """show branch heads
2567
2562
2568 With no arguments, show all open branch heads in the repository.
2563 With no arguments, show all open branch heads in the repository.
2569 Branch heads are changesets that have no descendants on the
2564 Branch heads are changesets that have no descendants on the
2570 same branch. They are where development generally takes place and
2565 same branch. They are where development generally takes place and
2571 are the usual targets for update and merge operations.
2566 are the usual targets for update and merge operations.
2572
2567
2573 If one or more REVs are given, only open branch heads on the
2568 If one or more REVs are given, only open branch heads on the
2574 branches associated with the specified changesets are shown. This
2569 branches associated with the specified changesets are shown. This
2575 means that you can use :hg:`heads .` to see the heads on the
2570 means that you can use :hg:`heads .` to see the heads on the
2576 currently checked-out branch.
2571 currently checked-out branch.
2577
2572
2578 If -c/--closed is specified, also show branch heads marked closed
2573 If -c/--closed is specified, also show branch heads marked closed
2579 (see :hg:`commit --close-branch`).
2574 (see :hg:`commit --close-branch`).
2580
2575
2581 If STARTREV is specified, only those heads that are descendants of
2576 If STARTREV is specified, only those heads that are descendants of
2582 STARTREV will be displayed.
2577 STARTREV will be displayed.
2583
2578
2584 If -t/--topo is specified, named branch mechanics will be ignored and only
2579 If -t/--topo is specified, named branch mechanics will be ignored and only
2585 topological heads (changesets with no children) will be shown.
2580 topological heads (changesets with no children) will be shown.
2586
2581
2587 Returns 0 if matching heads are found, 1 if not.
2582 Returns 0 if matching heads are found, 1 if not.
2588 """
2583 """
2589
2584
2590 opts = pycompat.byteskwargs(opts)
2585 opts = pycompat.byteskwargs(opts)
2591 start = None
2586 start = None
2592 if 'rev' in opts:
2587 if 'rev' in opts:
2593 start = scmutil.revsingle(repo, opts['rev'], None).node()
2588 start = scmutil.revsingle(repo, opts['rev'], None).node()
2594
2589
2595 if opts.get('topo'):
2590 if opts.get('topo'):
2596 heads = [repo[h] for h in repo.heads(start)]
2591 heads = [repo[h] for h in repo.heads(start)]
2597 else:
2592 else:
2598 heads = []
2593 heads = []
2599 for branch in repo.branchmap():
2594 for branch in repo.branchmap():
2600 heads += repo.branchheads(branch, start, opts.get('closed'))
2595 heads += repo.branchheads(branch, start, opts.get('closed'))
2601 heads = [repo[h] for h in heads]
2596 heads = [repo[h] for h in heads]
2602
2597
2603 if branchrevs:
2598 if branchrevs:
2604 branches = set(repo[br].branch() for br in branchrevs)
2599 branches = set(repo[br].branch() for br in branchrevs)
2605 heads = [h for h in heads if h.branch() in branches]
2600 heads = [h for h in heads if h.branch() in branches]
2606
2601
2607 if opts.get('active') and branchrevs:
2602 if opts.get('active') and branchrevs:
2608 dagheads = repo.heads(start)
2603 dagheads = repo.heads(start)
2609 heads = [h for h in heads if h.node() in dagheads]
2604 heads = [h for h in heads if h.node() in dagheads]
2610
2605
2611 if branchrevs:
2606 if branchrevs:
2612 haveheads = set(h.branch() for h in heads)
2607 haveheads = set(h.branch() for h in heads)
2613 if branches - haveheads:
2608 if branches - haveheads:
2614 headless = ', '.join(b for b in branches - haveheads)
2609 headless = ', '.join(b for b in branches - haveheads)
2615 msg = _('no open branch heads found on branches %s')
2610 msg = _('no open branch heads found on branches %s')
2616 if opts.get('rev'):
2611 if opts.get('rev'):
2617 msg += _(' (started at %s)') % opts['rev']
2612 msg += _(' (started at %s)') % opts['rev']
2618 ui.warn((msg + '\n') % headless)
2613 ui.warn((msg + '\n') % headless)
2619
2614
2620 if not heads:
2615 if not heads:
2621 return 1
2616 return 1
2622
2617
2623 ui.pager('heads')
2618 ui.pager('heads')
2624 heads = sorted(heads, key=lambda x: -x.rev())
2619 heads = sorted(heads, key=lambda x: -x.rev())
2625 displayer = cmdutil.show_changeset(ui, repo, opts)
2620 displayer = cmdutil.show_changeset(ui, repo, opts)
2626 for ctx in heads:
2621 for ctx in heads:
2627 displayer.show(ctx)
2622 displayer.show(ctx)
2628 displayer.close()
2623 displayer.close()
2629
2624
2630 @command('help',
2625 @command('help',
2631 [('e', 'extension', None, _('show only help for extensions')),
2626 [('e', 'extension', None, _('show only help for extensions')),
2632 ('c', 'command', None, _('show only help for commands')),
2627 ('c', 'command', None, _('show only help for commands')),
2633 ('k', 'keyword', None, _('show topics matching keyword')),
2628 ('k', 'keyword', None, _('show topics matching keyword')),
2634 ('s', 'system', [], _('show help for specific platform(s)')),
2629 ('s', 'system', [], _('show help for specific platform(s)')),
2635 ],
2630 ],
2636 _('[-ecks] [TOPIC]'),
2631 _('[-ecks] [TOPIC]'),
2637 norepo=True, cmdtype=readonly)
2632 norepo=True, cmdtype=readonly)
2638 def help_(ui, name=None, **opts):
2633 def help_(ui, name=None, **opts):
2639 """show help for a given topic or a help overview
2634 """show help for a given topic or a help overview
2640
2635
2641 With no arguments, print a list of commands with short help messages.
2636 With no arguments, print a list of commands with short help messages.
2642
2637
2643 Given a topic, extension, or command name, print help for that
2638 Given a topic, extension, or command name, print help for that
2644 topic.
2639 topic.
2645
2640
2646 Returns 0 if successful.
2641 Returns 0 if successful.
2647 """
2642 """
2648
2643
2649 keep = opts.get(r'system') or []
2644 keep = opts.get(r'system') or []
2650 if len(keep) == 0:
2645 if len(keep) == 0:
2651 if pycompat.sysplatform.startswith('win'):
2646 if pycompat.sysplatform.startswith('win'):
2652 keep.append('windows')
2647 keep.append('windows')
2653 elif pycompat.sysplatform == 'OpenVMS':
2648 elif pycompat.sysplatform == 'OpenVMS':
2654 keep.append('vms')
2649 keep.append('vms')
2655 elif pycompat.sysplatform == 'plan9':
2650 elif pycompat.sysplatform == 'plan9':
2656 keep.append('plan9')
2651 keep.append('plan9')
2657 else:
2652 else:
2658 keep.append('unix')
2653 keep.append('unix')
2659 keep.append(pycompat.sysplatform.lower())
2654 keep.append(pycompat.sysplatform.lower())
2660 if ui.verbose:
2655 if ui.verbose:
2661 keep.append('verbose')
2656 keep.append('verbose')
2662
2657
2663 commands = sys.modules[__name__]
2658 commands = sys.modules[__name__]
2664 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2659 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
2665 ui.pager('help')
2660 ui.pager('help')
2666 ui.write(formatted)
2661 ui.write(formatted)
2667
2662
2668
2663
2669 @command('identify|id',
2664 @command('identify|id',
2670 [('r', 'rev', '',
2665 [('r', 'rev', '',
2671 _('identify the specified revision'), _('REV')),
2666 _('identify the specified revision'), _('REV')),
2672 ('n', 'num', None, _('show local revision number')),
2667 ('n', 'num', None, _('show local revision number')),
2673 ('i', 'id', None, _('show global revision id')),
2668 ('i', 'id', None, _('show global revision id')),
2674 ('b', 'branch', None, _('show branch')),
2669 ('b', 'branch', None, _('show branch')),
2675 ('t', 'tags', None, _('show tags')),
2670 ('t', 'tags', None, _('show tags')),
2676 ('B', 'bookmarks', None, _('show bookmarks')),
2671 ('B', 'bookmarks', None, _('show bookmarks')),
2677 ] + remoteopts + formatteropts,
2672 ] + remoteopts + formatteropts,
2678 _('[-nibtB] [-r REV] [SOURCE]'),
2673 _('[-nibtB] [-r REV] [SOURCE]'),
2679 optionalrepo=True, cmdtype=readonly)
2674 optionalrepo=True, cmdtype=readonly)
2680 def identify(ui, repo, source=None, rev=None,
2675 def identify(ui, repo, source=None, rev=None,
2681 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2676 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2682 """identify the working directory or specified revision
2677 """identify the working directory or specified revision
2683
2678
2684 Print a summary identifying the repository state at REV using one or
2679 Print a summary identifying the repository state at REV using one or
2685 two parent hash identifiers, followed by a "+" if the working
2680 two parent hash identifiers, followed by a "+" if the working
2686 directory has uncommitted changes, the branch name (if not default),
2681 directory has uncommitted changes, the branch name (if not default),
2687 a list of tags, and a list of bookmarks.
2682 a list of tags, and a list of bookmarks.
2688
2683
2689 When REV is not given, print a summary of the current state of the
2684 When REV is not given, print a summary of the current state of the
2690 repository.
2685 repository.
2691
2686
2692 Specifying a path to a repository root or Mercurial bundle will
2687 Specifying a path to a repository root or Mercurial bundle will
2693 cause lookup to operate on that repository/bundle.
2688 cause lookup to operate on that repository/bundle.
2694
2689
2695 .. container:: verbose
2690 .. container:: verbose
2696
2691
2697 Examples:
2692 Examples:
2698
2693
2699 - generate a build identifier for the working directory::
2694 - generate a build identifier for the working directory::
2700
2695
2701 hg id --id > build-id.dat
2696 hg id --id > build-id.dat
2702
2697
2703 - find the revision corresponding to a tag::
2698 - find the revision corresponding to a tag::
2704
2699
2705 hg id -n -r 1.3
2700 hg id -n -r 1.3
2706
2701
2707 - check the most recent revision of a remote repository::
2702 - check the most recent revision of a remote repository::
2708
2703
2709 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2704 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2710
2705
2711 See :hg:`log` for generating more information about specific revisions,
2706 See :hg:`log` for generating more information about specific revisions,
2712 including full hash identifiers.
2707 including full hash identifiers.
2713
2708
2714 Returns 0 if successful.
2709 Returns 0 if successful.
2715 """
2710 """
2716
2711
2717 opts = pycompat.byteskwargs(opts)
2712 opts = pycompat.byteskwargs(opts)
2718 if not repo and not source:
2713 if not repo and not source:
2719 raise error.Abort(_("there is no Mercurial repository here "
2714 raise error.Abort(_("there is no Mercurial repository here "
2720 "(.hg not found)"))
2715 "(.hg not found)"))
2721
2716
2722 if ui.debugflag:
2717 if ui.debugflag:
2723 hexfunc = hex
2718 hexfunc = hex
2724 else:
2719 else:
2725 hexfunc = short
2720 hexfunc = short
2726 default = not (num or id or branch or tags or bookmarks)
2721 default = not (num or id or branch or tags or bookmarks)
2727 output = []
2722 output = []
2728 revs = []
2723 revs = []
2729
2724
2730 if source:
2725 if source:
2731 source, branches = hg.parseurl(ui.expandpath(source))
2726 source, branches = hg.parseurl(ui.expandpath(source))
2732 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2727 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2733 repo = peer.local()
2728 repo = peer.local()
2734 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2729 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2735
2730
2736 fm = ui.formatter('identify', opts)
2731 fm = ui.formatter('identify', opts)
2737 fm.startitem()
2732 fm.startitem()
2738
2733
2739 if not repo:
2734 if not repo:
2740 if num or branch or tags:
2735 if num or branch or tags:
2741 raise error.Abort(
2736 raise error.Abort(
2742 _("can't query remote revision number, branch, or tags"))
2737 _("can't query remote revision number, branch, or tags"))
2743 if not rev and revs:
2738 if not rev and revs:
2744 rev = revs[0]
2739 rev = revs[0]
2745 if not rev:
2740 if not rev:
2746 rev = "tip"
2741 rev = "tip"
2747
2742
2748 remoterev = peer.lookup(rev)
2743 remoterev = peer.lookup(rev)
2749 hexrev = hexfunc(remoterev)
2744 hexrev = hexfunc(remoterev)
2750 if default or id:
2745 if default or id:
2751 output = [hexrev]
2746 output = [hexrev]
2752 fm.data(id=hexrev)
2747 fm.data(id=hexrev)
2753
2748
2754 def getbms():
2749 def getbms():
2755 bms = []
2750 bms = []
2756
2751
2757 if 'bookmarks' in peer.listkeys('namespaces'):
2752 if 'bookmarks' in peer.listkeys('namespaces'):
2758 hexremoterev = hex(remoterev)
2753 hexremoterev = hex(remoterev)
2759 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2754 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2760 if bmr == hexremoterev]
2755 if bmr == hexremoterev]
2761
2756
2762 return sorted(bms)
2757 return sorted(bms)
2763
2758
2764 bms = getbms()
2759 bms = getbms()
2765 if bookmarks:
2760 if bookmarks:
2766 output.extend(bms)
2761 output.extend(bms)
2767 elif default and not ui.quiet:
2762 elif default and not ui.quiet:
2768 # multiple bookmarks for a single parent separated by '/'
2763 # multiple bookmarks for a single parent separated by '/'
2769 bm = '/'.join(bms)
2764 bm = '/'.join(bms)
2770 if bm:
2765 if bm:
2771 output.append(bm)
2766 output.append(bm)
2772
2767
2773 fm.data(node=hex(remoterev))
2768 fm.data(node=hex(remoterev))
2774 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2769 fm.data(bookmarks=fm.formatlist(bms, name='bookmark'))
2775 else:
2770 else:
2776 ctx = scmutil.revsingle(repo, rev, None)
2771 ctx = scmutil.revsingle(repo, rev, None)
2777
2772
2778 if ctx.rev() is None:
2773 if ctx.rev() is None:
2779 ctx = repo[None]
2774 ctx = repo[None]
2780 parents = ctx.parents()
2775 parents = ctx.parents()
2781 taglist = []
2776 taglist = []
2782 for p in parents:
2777 for p in parents:
2783 taglist.extend(p.tags())
2778 taglist.extend(p.tags())
2784
2779
2785 dirty = ""
2780 dirty = ""
2786 if ctx.dirty(missing=True, merge=False, branch=False):
2781 if ctx.dirty(missing=True, merge=False, branch=False):
2787 dirty = '+'
2782 dirty = '+'
2788 fm.data(dirty=dirty)
2783 fm.data(dirty=dirty)
2789
2784
2790 hexoutput = [hexfunc(p.node()) for p in parents]
2785 hexoutput = [hexfunc(p.node()) for p in parents]
2791 if default or id:
2786 if default or id:
2792 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2787 output = ["%s%s" % ('+'.join(hexoutput), dirty)]
2793 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2788 fm.data(id="%s%s" % ('+'.join(hexoutput), dirty))
2794
2789
2795 if num:
2790 if num:
2796 numoutput = ["%d" % p.rev() for p in parents]
2791 numoutput = ["%d" % p.rev() for p in parents]
2797 output.append("%s%s" % ('+'.join(numoutput), dirty))
2792 output.append("%s%s" % ('+'.join(numoutput), dirty))
2798
2793
2799 fn = fm.nested('parents')
2794 fn = fm.nested('parents')
2800 for p in parents:
2795 for p in parents:
2801 fn.startitem()
2796 fn.startitem()
2802 fn.data(rev=p.rev())
2797 fn.data(rev=p.rev())
2803 fn.data(node=p.hex())
2798 fn.data(node=p.hex())
2804 fn.context(ctx=p)
2799 fn.context(ctx=p)
2805 fn.end()
2800 fn.end()
2806 else:
2801 else:
2807 hexoutput = hexfunc(ctx.node())
2802 hexoutput = hexfunc(ctx.node())
2808 if default or id:
2803 if default or id:
2809 output = [hexoutput]
2804 output = [hexoutput]
2810 fm.data(id=hexoutput)
2805 fm.data(id=hexoutput)
2811
2806
2812 if num:
2807 if num:
2813 output.append(pycompat.bytestr(ctx.rev()))
2808 output.append(pycompat.bytestr(ctx.rev()))
2814 taglist = ctx.tags()
2809 taglist = ctx.tags()
2815
2810
2816 if default and not ui.quiet:
2811 if default and not ui.quiet:
2817 b = ctx.branch()
2812 b = ctx.branch()
2818 if b != 'default':
2813 if b != 'default':
2819 output.append("(%s)" % b)
2814 output.append("(%s)" % b)
2820
2815
2821 # multiple tags for a single parent separated by '/'
2816 # multiple tags for a single parent separated by '/'
2822 t = '/'.join(taglist)
2817 t = '/'.join(taglist)
2823 if t:
2818 if t:
2824 output.append(t)
2819 output.append(t)
2825
2820
2826 # multiple bookmarks for a single parent separated by '/'
2821 # multiple bookmarks for a single parent separated by '/'
2827 bm = '/'.join(ctx.bookmarks())
2822 bm = '/'.join(ctx.bookmarks())
2828 if bm:
2823 if bm:
2829 output.append(bm)
2824 output.append(bm)
2830 else:
2825 else:
2831 if branch:
2826 if branch:
2832 output.append(ctx.branch())
2827 output.append(ctx.branch())
2833
2828
2834 if tags:
2829 if tags:
2835 output.extend(taglist)
2830 output.extend(taglist)
2836
2831
2837 if bookmarks:
2832 if bookmarks:
2838 output.extend(ctx.bookmarks())
2833 output.extend(ctx.bookmarks())
2839
2834
2840 fm.data(node=ctx.hex())
2835 fm.data(node=ctx.hex())
2841 fm.data(branch=ctx.branch())
2836 fm.data(branch=ctx.branch())
2842 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2837 fm.data(tags=fm.formatlist(taglist, name='tag', sep=':'))
2843 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2838 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'))
2844 fm.context(ctx=ctx)
2839 fm.context(ctx=ctx)
2845
2840
2846 fm.plain("%s\n" % ' '.join(output))
2841 fm.plain("%s\n" % ' '.join(output))
2847 fm.end()
2842 fm.end()
2848
2843
2849 @command('import|patch',
2844 @command('import|patch',
2850 [('p', 'strip', 1,
2845 [('p', 'strip', 1,
2851 _('directory strip option for patch. This has the same '
2846 _('directory strip option for patch. This has the same '
2852 'meaning as the corresponding patch option'), _('NUM')),
2847 'meaning as the corresponding patch option'), _('NUM')),
2853 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2848 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2854 ('e', 'edit', False, _('invoke editor on commit messages')),
2849 ('e', 'edit', False, _('invoke editor on commit messages')),
2855 ('f', 'force', None,
2850 ('f', 'force', None,
2856 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2851 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2857 ('', 'no-commit', None,
2852 ('', 'no-commit', None,
2858 _("don't commit, just update the working directory")),
2853 _("don't commit, just update the working directory")),
2859 ('', 'bypass', None,
2854 ('', 'bypass', None,
2860 _("apply patch without touching the working directory")),
2855 _("apply patch without touching the working directory")),
2861 ('', 'partial', None,
2856 ('', 'partial', None,
2862 _('commit even if some hunks fail')),
2857 _('commit even if some hunks fail')),
2863 ('', 'exact', None,
2858 ('', 'exact', None,
2864 _('abort if patch would apply lossily')),
2859 _('abort if patch would apply lossily')),
2865 ('', 'prefix', '',
2860 ('', 'prefix', '',
2866 _('apply patch to subdirectory'), _('DIR')),
2861 _('apply patch to subdirectory'), _('DIR')),
2867 ('', 'import-branch', None,
2862 ('', 'import-branch', None,
2868 _('use any branch information in patch (implied by --exact)'))] +
2863 _('use any branch information in patch (implied by --exact)'))] +
2869 commitopts + commitopts2 + similarityopts,
2864 commitopts + commitopts2 + similarityopts,
2870 _('[OPTION]... PATCH...'))
2865 _('[OPTION]... PATCH...'))
2871 def import_(ui, repo, patch1=None, *patches, **opts):
2866 def import_(ui, repo, patch1=None, *patches, **opts):
2872 """import an ordered set of patches
2867 """import an ordered set of patches
2873
2868
2874 Import a list of patches and commit them individually (unless
2869 Import a list of patches and commit them individually (unless
2875 --no-commit is specified).
2870 --no-commit is specified).
2876
2871
2877 To read a patch from standard input (stdin), use "-" as the patch
2872 To read a patch from standard input (stdin), use "-" as the patch
2878 name. If a URL is specified, the patch will be downloaded from
2873 name. If a URL is specified, the patch will be downloaded from
2879 there.
2874 there.
2880
2875
2881 Import first applies changes to the working directory (unless
2876 Import first applies changes to the working directory (unless
2882 --bypass is specified), import will abort if there are outstanding
2877 --bypass is specified), import will abort if there are outstanding
2883 changes.
2878 changes.
2884
2879
2885 Use --bypass to apply and commit patches directly to the
2880 Use --bypass to apply and commit patches directly to the
2886 repository, without affecting the working directory. Without
2881 repository, without affecting the working directory. Without
2887 --exact, patches will be applied on top of the working directory
2882 --exact, patches will be applied on top of the working directory
2888 parent revision.
2883 parent revision.
2889
2884
2890 You can import a patch straight from a mail message. Even patches
2885 You can import a patch straight from a mail message. Even patches
2891 as attachments work (to use the body part, it must have type
2886 as attachments work (to use the body part, it must have type
2892 text/plain or text/x-patch). From and Subject headers of email
2887 text/plain or text/x-patch). From and Subject headers of email
2893 message are used as default committer and commit message. All
2888 message are used as default committer and commit message. All
2894 text/plain body parts before first diff are added to the commit
2889 text/plain body parts before first diff are added to the commit
2895 message.
2890 message.
2896
2891
2897 If the imported patch was generated by :hg:`export`, user and
2892 If the imported patch was generated by :hg:`export`, user and
2898 description from patch override values from message headers and
2893 description from patch override values from message headers and
2899 body. Values given on command line with -m/--message and -u/--user
2894 body. Values given on command line with -m/--message and -u/--user
2900 override these.
2895 override these.
2901
2896
2902 If --exact is specified, import will set the working directory to
2897 If --exact is specified, import will set the working directory to
2903 the parent of each patch before applying it, and will abort if the
2898 the parent of each patch before applying it, and will abort if the
2904 resulting changeset has a different ID than the one recorded in
2899 resulting changeset has a different ID than the one recorded in
2905 the patch. This will guard against various ways that portable
2900 the patch. This will guard against various ways that portable
2906 patch formats and mail systems might fail to transfer Mercurial
2901 patch formats and mail systems might fail to transfer Mercurial
2907 data or metadata. See :hg:`bundle` for lossless transmission.
2902 data or metadata. See :hg:`bundle` for lossless transmission.
2908
2903
2909 Use --partial to ensure a changeset will be created from the patch
2904 Use --partial to ensure a changeset will be created from the patch
2910 even if some hunks fail to apply. Hunks that fail to apply will be
2905 even if some hunks fail to apply. Hunks that fail to apply will be
2911 written to a <target-file>.rej file. Conflicts can then be resolved
2906 written to a <target-file>.rej file. Conflicts can then be resolved
2912 by hand before :hg:`commit --amend` is run to update the created
2907 by hand before :hg:`commit --amend` is run to update the created
2913 changeset. This flag exists to let people import patches that
2908 changeset. This flag exists to let people import patches that
2914 partially apply without losing the associated metadata (author,
2909 partially apply without losing the associated metadata (author,
2915 date, description, ...).
2910 date, description, ...).
2916
2911
2917 .. note::
2912 .. note::
2918
2913
2919 When no hunks apply cleanly, :hg:`import --partial` will create
2914 When no hunks apply cleanly, :hg:`import --partial` will create
2920 an empty changeset, importing only the patch metadata.
2915 an empty changeset, importing only the patch metadata.
2921
2916
2922 With -s/--similarity, hg will attempt to discover renames and
2917 With -s/--similarity, hg will attempt to discover renames and
2923 copies in the patch in the same way as :hg:`addremove`.
2918 copies in the patch in the same way as :hg:`addremove`.
2924
2919
2925 It is possible to use external patch programs to perform the patch
2920 It is possible to use external patch programs to perform the patch
2926 by setting the ``ui.patch`` configuration option. For the default
2921 by setting the ``ui.patch`` configuration option. For the default
2927 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2922 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2928 See :hg:`help config` for more information about configuration
2923 See :hg:`help config` for more information about configuration
2929 files and how to use these options.
2924 files and how to use these options.
2930
2925
2931 See :hg:`help dates` for a list of formats valid for -d/--date.
2926 See :hg:`help dates` for a list of formats valid for -d/--date.
2932
2927
2933 .. container:: verbose
2928 .. container:: verbose
2934
2929
2935 Examples:
2930 Examples:
2936
2931
2937 - import a traditional patch from a website and detect renames::
2932 - import a traditional patch from a website and detect renames::
2938
2933
2939 hg import -s 80 http://example.com/bugfix.patch
2934 hg import -s 80 http://example.com/bugfix.patch
2940
2935
2941 - import a changeset from an hgweb server::
2936 - import a changeset from an hgweb server::
2942
2937
2943 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2938 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2944
2939
2945 - import all the patches in an Unix-style mbox::
2940 - import all the patches in an Unix-style mbox::
2946
2941
2947 hg import incoming-patches.mbox
2942 hg import incoming-patches.mbox
2948
2943
2949 - import patches from stdin::
2944 - import patches from stdin::
2950
2945
2951 hg import -
2946 hg import -
2952
2947
2953 - attempt to exactly restore an exported changeset (not always
2948 - attempt to exactly restore an exported changeset (not always
2954 possible)::
2949 possible)::
2955
2950
2956 hg import --exact proposed-fix.patch
2951 hg import --exact proposed-fix.patch
2957
2952
2958 - use an external tool to apply a patch which is too fuzzy for
2953 - use an external tool to apply a patch which is too fuzzy for
2959 the default internal tool.
2954 the default internal tool.
2960
2955
2961 hg import --config ui.patch="patch --merge" fuzzy.patch
2956 hg import --config ui.patch="patch --merge" fuzzy.patch
2962
2957
2963 - change the default fuzzing from 2 to a less strict 7
2958 - change the default fuzzing from 2 to a less strict 7
2964
2959
2965 hg import --config ui.fuzz=7 fuzz.patch
2960 hg import --config ui.fuzz=7 fuzz.patch
2966
2961
2967 Returns 0 on success, 1 on partial success (see --partial).
2962 Returns 0 on success, 1 on partial success (see --partial).
2968 """
2963 """
2969
2964
2970 opts = pycompat.byteskwargs(opts)
2965 opts = pycompat.byteskwargs(opts)
2971 if not patch1:
2966 if not patch1:
2972 raise error.Abort(_('need at least one patch to import'))
2967 raise error.Abort(_('need at least one patch to import'))
2973
2968
2974 patches = (patch1,) + patches
2969 patches = (patch1,) + patches
2975
2970
2976 date = opts.get('date')
2971 date = opts.get('date')
2977 if date:
2972 if date:
2978 opts['date'] = util.parsedate(date)
2973 opts['date'] = util.parsedate(date)
2979
2974
2980 exact = opts.get('exact')
2975 exact = opts.get('exact')
2981 update = not opts.get('bypass')
2976 update = not opts.get('bypass')
2982 if not update and opts.get('no_commit'):
2977 if not update and opts.get('no_commit'):
2983 raise error.Abort(_('cannot use --no-commit with --bypass'))
2978 raise error.Abort(_('cannot use --no-commit with --bypass'))
2984 try:
2979 try:
2985 sim = float(opts.get('similarity') or 0)
2980 sim = float(opts.get('similarity') or 0)
2986 except ValueError:
2981 except ValueError:
2987 raise error.Abort(_('similarity must be a number'))
2982 raise error.Abort(_('similarity must be a number'))
2988 if sim < 0 or sim > 100:
2983 if sim < 0 or sim > 100:
2989 raise error.Abort(_('similarity must be between 0 and 100'))
2984 raise error.Abort(_('similarity must be between 0 and 100'))
2990 if sim and not update:
2985 if sim and not update:
2991 raise error.Abort(_('cannot use --similarity with --bypass'))
2986 raise error.Abort(_('cannot use --similarity with --bypass'))
2992 if exact:
2987 if exact:
2993 if opts.get('edit'):
2988 if opts.get('edit'):
2994 raise error.Abort(_('cannot use --exact with --edit'))
2989 raise error.Abort(_('cannot use --exact with --edit'))
2995 if opts.get('prefix'):
2990 if opts.get('prefix'):
2996 raise error.Abort(_('cannot use --exact with --prefix'))
2991 raise error.Abort(_('cannot use --exact with --prefix'))
2997
2992
2998 base = opts["base"]
2993 base = opts["base"]
2999 wlock = dsguard = lock = tr = None
2994 wlock = dsguard = lock = tr = None
3000 msgs = []
2995 msgs = []
3001 ret = 0
2996 ret = 0
3002
2997
3003
2998
3004 try:
2999 try:
3005 wlock = repo.wlock()
3000 wlock = repo.wlock()
3006
3001
3007 if update:
3002 if update:
3008 cmdutil.checkunfinished(repo)
3003 cmdutil.checkunfinished(repo)
3009 if (exact or not opts.get('force')):
3004 if (exact or not opts.get('force')):
3010 cmdutil.bailifchanged(repo)
3005 cmdutil.bailifchanged(repo)
3011
3006
3012 if not opts.get('no_commit'):
3007 if not opts.get('no_commit'):
3013 lock = repo.lock()
3008 lock = repo.lock()
3014 tr = repo.transaction('import')
3009 tr = repo.transaction('import')
3015 else:
3010 else:
3016 dsguard = dirstateguard.dirstateguard(repo, 'import')
3011 dsguard = dirstateguard.dirstateguard(repo, 'import')
3017 parents = repo[None].parents()
3012 parents = repo[None].parents()
3018 for patchurl in patches:
3013 for patchurl in patches:
3019 if patchurl == '-':
3014 if patchurl == '-':
3020 ui.status(_('applying patch from stdin\n'))
3015 ui.status(_('applying patch from stdin\n'))
3021 patchfile = ui.fin
3016 patchfile = ui.fin
3022 patchurl = 'stdin' # for error message
3017 patchurl = 'stdin' # for error message
3023 else:
3018 else:
3024 patchurl = os.path.join(base, patchurl)
3019 patchurl = os.path.join(base, patchurl)
3025 ui.status(_('applying %s\n') % patchurl)
3020 ui.status(_('applying %s\n') % patchurl)
3026 patchfile = hg.openpath(ui, patchurl)
3021 patchfile = hg.openpath(ui, patchurl)
3027
3022
3028 haspatch = False
3023 haspatch = False
3029 for hunk in patch.split(patchfile):
3024 for hunk in patch.split(patchfile):
3030 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3025 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3031 parents, opts,
3026 parents, opts,
3032 msgs, hg.clean)
3027 msgs, hg.clean)
3033 if msg:
3028 if msg:
3034 haspatch = True
3029 haspatch = True
3035 ui.note(msg + '\n')
3030 ui.note(msg + '\n')
3036 if update or exact:
3031 if update or exact:
3037 parents = repo[None].parents()
3032 parents = repo[None].parents()
3038 else:
3033 else:
3039 parents = [repo[node]]
3034 parents = [repo[node]]
3040 if rej:
3035 if rej:
3041 ui.write_err(_("patch applied partially\n"))
3036 ui.write_err(_("patch applied partially\n"))
3042 ui.write_err(_("(fix the .rej files and run "
3037 ui.write_err(_("(fix the .rej files and run "
3043 "`hg commit --amend`)\n"))
3038 "`hg commit --amend`)\n"))
3044 ret = 1
3039 ret = 1
3045 break
3040 break
3046
3041
3047 if not haspatch:
3042 if not haspatch:
3048 raise error.Abort(_('%s: no diffs found') % patchurl)
3043 raise error.Abort(_('%s: no diffs found') % patchurl)
3049
3044
3050 if tr:
3045 if tr:
3051 tr.close()
3046 tr.close()
3052 if msgs:
3047 if msgs:
3053 repo.savecommitmessage('\n* * *\n'.join(msgs))
3048 repo.savecommitmessage('\n* * *\n'.join(msgs))
3054 if dsguard:
3049 if dsguard:
3055 dsguard.close()
3050 dsguard.close()
3056 return ret
3051 return ret
3057 finally:
3052 finally:
3058 if tr:
3053 if tr:
3059 tr.release()
3054 tr.release()
3060 release(lock, dsguard, wlock)
3055 release(lock, dsguard, wlock)
3061
3056
3062 @command('incoming|in',
3057 @command('incoming|in',
3063 [('f', 'force', None,
3058 [('f', 'force', None,
3064 _('run even if remote repository is unrelated')),
3059 _('run even if remote repository is unrelated')),
3065 ('n', 'newest-first', None, _('show newest record first')),
3060 ('n', 'newest-first', None, _('show newest record first')),
3066 ('', 'bundle', '',
3061 ('', 'bundle', '',
3067 _('file to store the bundles into'), _('FILE')),
3062 _('file to store the bundles into'), _('FILE')),
3068 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3063 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3069 ('B', 'bookmarks', False, _("compare bookmarks")),
3064 ('B', 'bookmarks', False, _("compare bookmarks")),
3070 ('b', 'branch', [],
3065 ('b', 'branch', [],
3071 _('a specific branch you would like to pull'), _('BRANCH')),
3066 _('a specific branch you would like to pull'), _('BRANCH')),
3072 ] + logopts + remoteopts + subrepoopts,
3067 ] + logopts + remoteopts + subrepoopts,
3073 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3068 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3074 def incoming(ui, repo, source="default", **opts):
3069 def incoming(ui, repo, source="default", **opts):
3075 """show new changesets found in source
3070 """show new changesets found in source
3076
3071
3077 Show new changesets found in the specified path/URL or the default
3072 Show new changesets found in the specified path/URL or the default
3078 pull location. These are the changesets that would have been pulled
3073 pull location. These are the changesets that would have been pulled
3079 by :hg:`pull` at the time you issued this command.
3074 by :hg:`pull` at the time you issued this command.
3080
3075
3081 See pull for valid source format details.
3076 See pull for valid source format details.
3082
3077
3083 .. container:: verbose
3078 .. container:: verbose
3084
3079
3085 With -B/--bookmarks, the result of bookmark comparison between
3080 With -B/--bookmarks, the result of bookmark comparison between
3086 local and remote repositories is displayed. With -v/--verbose,
3081 local and remote repositories is displayed. With -v/--verbose,
3087 status is also displayed for each bookmark like below::
3082 status is also displayed for each bookmark like below::
3088
3083
3089 BM1 01234567890a added
3084 BM1 01234567890a added
3090 BM2 1234567890ab advanced
3085 BM2 1234567890ab advanced
3091 BM3 234567890abc diverged
3086 BM3 234567890abc diverged
3092 BM4 34567890abcd changed
3087 BM4 34567890abcd changed
3093
3088
3094 The action taken locally when pulling depends on the
3089 The action taken locally when pulling depends on the
3095 status of each bookmark:
3090 status of each bookmark:
3096
3091
3097 :``added``: pull will create it
3092 :``added``: pull will create it
3098 :``advanced``: pull will update it
3093 :``advanced``: pull will update it
3099 :``diverged``: pull will create a divergent bookmark
3094 :``diverged``: pull will create a divergent bookmark
3100 :``changed``: result depends on remote changesets
3095 :``changed``: result depends on remote changesets
3101
3096
3102 From the point of view of pulling behavior, bookmark
3097 From the point of view of pulling behavior, bookmark
3103 existing only in the remote repository are treated as ``added``,
3098 existing only in the remote repository are treated as ``added``,
3104 even if it is in fact locally deleted.
3099 even if it is in fact locally deleted.
3105
3100
3106 .. container:: verbose
3101 .. container:: verbose
3107
3102
3108 For remote repository, using --bundle avoids downloading the
3103 For remote repository, using --bundle avoids downloading the
3109 changesets twice if the incoming is followed by a pull.
3104 changesets twice if the incoming is followed by a pull.
3110
3105
3111 Examples:
3106 Examples:
3112
3107
3113 - show incoming changes with patches and full description::
3108 - show incoming changes with patches and full description::
3114
3109
3115 hg incoming -vp
3110 hg incoming -vp
3116
3111
3117 - show incoming changes excluding merges, store a bundle::
3112 - show incoming changes excluding merges, store a bundle::
3118
3113
3119 hg in -vpM --bundle incoming.hg
3114 hg in -vpM --bundle incoming.hg
3120 hg pull incoming.hg
3115 hg pull incoming.hg
3121
3116
3122 - briefly list changes inside a bundle::
3117 - briefly list changes inside a bundle::
3123
3118
3124 hg in changes.hg -T "{desc|firstline}\\n"
3119 hg in changes.hg -T "{desc|firstline}\\n"
3125
3120
3126 Returns 0 if there are incoming changes, 1 otherwise.
3121 Returns 0 if there are incoming changes, 1 otherwise.
3127 """
3122 """
3128 opts = pycompat.byteskwargs(opts)
3123 opts = pycompat.byteskwargs(opts)
3129 if opts.get('graph'):
3124 if opts.get('graph'):
3130 cmdutil.checkunsupportedgraphflags([], opts)
3125 cmdutil.checkunsupportedgraphflags([], opts)
3131 def display(other, chlist, displayer):
3126 def display(other, chlist, displayer):
3132 revdag = cmdutil.graphrevs(other, chlist, opts)
3127 revdag = cmdutil.graphrevs(other, chlist, opts)
3133 cmdutil.displaygraph(ui, repo, revdag, displayer,
3128 cmdutil.displaygraph(ui, repo, revdag, displayer,
3134 graphmod.asciiedges)
3129 graphmod.asciiedges)
3135
3130
3136 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3131 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3137 return 0
3132 return 0
3138
3133
3139 if opts.get('bundle') and opts.get('subrepos'):
3134 if opts.get('bundle') and opts.get('subrepos'):
3140 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3135 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3141
3136
3142 if opts.get('bookmarks'):
3137 if opts.get('bookmarks'):
3143 source, branches = hg.parseurl(ui.expandpath(source),
3138 source, branches = hg.parseurl(ui.expandpath(source),
3144 opts.get('branch'))
3139 opts.get('branch'))
3145 other = hg.peer(repo, opts, source)
3140 other = hg.peer(repo, opts, source)
3146 if 'bookmarks' not in other.listkeys('namespaces'):
3141 if 'bookmarks' not in other.listkeys('namespaces'):
3147 ui.warn(_("remote doesn't support bookmarks\n"))
3142 ui.warn(_("remote doesn't support bookmarks\n"))
3148 return 0
3143 return 0
3149 ui.pager('incoming')
3144 ui.pager('incoming')
3150 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3145 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3151 return bookmarks.incoming(ui, repo, other)
3146 return bookmarks.incoming(ui, repo, other)
3152
3147
3153 repo._subtoppath = ui.expandpath(source)
3148 repo._subtoppath = ui.expandpath(source)
3154 try:
3149 try:
3155 return hg.incoming(ui, repo, source, opts)
3150 return hg.incoming(ui, repo, source, opts)
3156 finally:
3151 finally:
3157 del repo._subtoppath
3152 del repo._subtoppath
3158
3153
3159
3154
3160 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3155 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3161 norepo=True)
3156 norepo=True)
3162 def init(ui, dest=".", **opts):
3157 def init(ui, dest=".", **opts):
3163 """create a new repository in the given directory
3158 """create a new repository in the given directory
3164
3159
3165 Initialize a new repository in the given directory. If the given
3160 Initialize a new repository in the given directory. If the given
3166 directory does not exist, it will be created.
3161 directory does not exist, it will be created.
3167
3162
3168 If no directory is given, the current directory is used.
3163 If no directory is given, the current directory is used.
3169
3164
3170 It is possible to specify an ``ssh://`` URL as the destination.
3165 It is possible to specify an ``ssh://`` URL as the destination.
3171 See :hg:`help urls` for more information.
3166 See :hg:`help urls` for more information.
3172
3167
3173 Returns 0 on success.
3168 Returns 0 on success.
3174 """
3169 """
3175 opts = pycompat.byteskwargs(opts)
3170 opts = pycompat.byteskwargs(opts)
3176 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3171 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3177
3172
3178 @command('locate',
3173 @command('locate',
3179 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3174 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3180 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3175 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3181 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3176 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3182 ] + walkopts,
3177 ] + walkopts,
3183 _('[OPTION]... [PATTERN]...'))
3178 _('[OPTION]... [PATTERN]...'))
3184 def locate(ui, repo, *pats, **opts):
3179 def locate(ui, repo, *pats, **opts):
3185 """locate files matching specific patterns (DEPRECATED)
3180 """locate files matching specific patterns (DEPRECATED)
3186
3181
3187 Print files under Mercurial control in the working directory whose
3182 Print files under Mercurial control in the working directory whose
3188 names match the given patterns.
3183 names match the given patterns.
3189
3184
3190 By default, this command searches all directories in the working
3185 By default, this command searches all directories in the working
3191 directory. To search just the current directory and its
3186 directory. To search just the current directory and its
3192 subdirectories, use "--include .".
3187 subdirectories, use "--include .".
3193
3188
3194 If no patterns are given to match, this command prints the names
3189 If no patterns are given to match, this command prints the names
3195 of all files under Mercurial control in the working directory.
3190 of all files under Mercurial control in the working directory.
3196
3191
3197 If you want to feed the output of this command into the "xargs"
3192 If you want to feed the output of this command into the "xargs"
3198 command, use the -0 option to both this command and "xargs". This
3193 command, use the -0 option to both this command and "xargs". This
3199 will avoid the problem of "xargs" treating single filenames that
3194 will avoid the problem of "xargs" treating single filenames that
3200 contain whitespace as multiple filenames.
3195 contain whitespace as multiple filenames.
3201
3196
3202 See :hg:`help files` for a more versatile command.
3197 See :hg:`help files` for a more versatile command.
3203
3198
3204 Returns 0 if a match is found, 1 otherwise.
3199 Returns 0 if a match is found, 1 otherwise.
3205 """
3200 """
3206 opts = pycompat.byteskwargs(opts)
3201 opts = pycompat.byteskwargs(opts)
3207 if opts.get('print0'):
3202 if opts.get('print0'):
3208 end = '\0'
3203 end = '\0'
3209 else:
3204 else:
3210 end = '\n'
3205 end = '\n'
3211 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3206 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3212
3207
3213 ret = 1
3208 ret = 1
3214 ctx = repo[rev]
3209 ctx = repo[rev]
3215 m = scmutil.match(ctx, pats, opts, default='relglob',
3210 m = scmutil.match(ctx, pats, opts, default='relglob',
3216 badfn=lambda x, y: False)
3211 badfn=lambda x, y: False)
3217
3212
3218 ui.pager('locate')
3213 ui.pager('locate')
3219 for abs in ctx.matches(m):
3214 for abs in ctx.matches(m):
3220 if opts.get('fullpath'):
3215 if opts.get('fullpath'):
3221 ui.write(repo.wjoin(abs), end)
3216 ui.write(repo.wjoin(abs), end)
3222 else:
3217 else:
3223 ui.write(((pats and m.rel(abs)) or abs), end)
3218 ui.write(((pats and m.rel(abs)) or abs), end)
3224 ret = 0
3219 ret = 0
3225
3220
3226 return ret
3221 return ret
3227
3222
3228 @command('^log|history',
3223 @command('^log|history',
3229 [('f', 'follow', None,
3224 [('f', 'follow', None,
3230 _('follow changeset history, or file history across copies and renames')),
3225 _('follow changeset history, or file history across copies and renames')),
3231 ('', 'follow-first', None,
3226 ('', 'follow-first', None,
3232 _('only follow the first parent of merge changesets (DEPRECATED)')),
3227 _('only follow the first parent of merge changesets (DEPRECATED)')),
3233 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3228 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3234 ('C', 'copies', None, _('show copied files')),
3229 ('C', 'copies', None, _('show copied files')),
3235 ('k', 'keyword', [],
3230 ('k', 'keyword', [],
3236 _('do case-insensitive search for a given text'), _('TEXT')),
3231 _('do case-insensitive search for a given text'), _('TEXT')),
3237 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3232 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3238 ('L', 'line-range', [],
3233 ('L', 'line-range', [],
3239 _('follow line range of specified file (EXPERIMENTAL)'),
3234 _('follow line range of specified file (EXPERIMENTAL)'),
3240 _('FILE,RANGE')),
3235 _('FILE,RANGE')),
3241 ('', 'removed', None, _('include revisions where files were removed')),
3236 ('', 'removed', None, _('include revisions where files were removed')),
3242 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3237 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3243 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3238 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3244 ('', 'only-branch', [],
3239 ('', 'only-branch', [],
3245 _('show only changesets within the given named branch (DEPRECATED)'),
3240 _('show only changesets within the given named branch (DEPRECATED)'),
3246 _('BRANCH')),
3241 _('BRANCH')),
3247 ('b', 'branch', [],
3242 ('b', 'branch', [],
3248 _('show changesets within the given named branch'), _('BRANCH')),
3243 _('show changesets within the given named branch'), _('BRANCH')),
3249 ('P', 'prune', [],
3244 ('P', 'prune', [],
3250 _('do not display revision or any of its ancestors'), _('REV')),
3245 _('do not display revision or any of its ancestors'), _('REV')),
3251 ] + logopts + walkopts,
3246 ] + logopts + walkopts,
3252 _('[OPTION]... [FILE]'),
3247 _('[OPTION]... [FILE]'),
3253 inferrepo=True, cmdtype=readonly)
3248 inferrepo=True, cmdtype=readonly)
3254 def log(ui, repo, *pats, **opts):
3249 def log(ui, repo, *pats, **opts):
3255 """show revision history of entire repository or files
3250 """show revision history of entire repository or files
3256
3251
3257 Print the revision history of the specified files or the entire
3252 Print the revision history of the specified files or the entire
3258 project.
3253 project.
3259
3254
3260 If no revision range is specified, the default is ``tip:0`` unless
3255 If no revision range is specified, the default is ``tip:0`` unless
3261 --follow is set, in which case the working directory parent is
3256 --follow is set, in which case the working directory parent is
3262 used as the starting revision.
3257 used as the starting revision.
3263
3258
3264 File history is shown without following rename or copy history of
3259 File history is shown without following rename or copy history of
3265 files. Use -f/--follow with a filename to follow history across
3260 files. Use -f/--follow with a filename to follow history across
3266 renames and copies. --follow without a filename will only show
3261 renames and copies. --follow without a filename will only show
3267 ancestors or descendants of the starting revision.
3262 ancestors or descendants of the starting revision.
3268
3263
3269 By default this command prints revision number and changeset id,
3264 By default this command prints revision number and changeset id,
3270 tags, non-trivial parents, user, date and time, and a summary for
3265 tags, non-trivial parents, user, date and time, and a summary for
3271 each commit. When the -v/--verbose switch is used, the list of
3266 each commit. When the -v/--verbose switch is used, the list of
3272 changed files and full commit message are shown.
3267 changed files and full commit message are shown.
3273
3268
3274 With --graph the revisions are shown as an ASCII art DAG with the most
3269 With --graph the revisions are shown as an ASCII art DAG with the most
3275 recent changeset at the top.
3270 recent changeset at the top.
3276 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3271 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3277 and '+' represents a fork where the changeset from the lines below is a
3272 and '+' represents a fork where the changeset from the lines below is a
3278 parent of the 'o' merge on the same line.
3273 parent of the 'o' merge on the same line.
3279 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3274 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3280 of a '|' indicates one or more revisions in a path are omitted.
3275 of a '|' indicates one or more revisions in a path are omitted.
3281
3276
3282 .. container:: verbose
3277 .. container:: verbose
3283
3278
3284 Use -L/--line-range FILE,M:N options to follow the history of lines
3279 Use -L/--line-range FILE,M:N options to follow the history of lines
3285 from M to N in FILE. With -p/--patch only diff hunks affecting
3280 from M to N in FILE. With -p/--patch only diff hunks affecting
3286 specified line range will be shown. This option requires --follow;
3281 specified line range will be shown. This option requires --follow;
3287 it can be specified multiple times. Currently, this option is not
3282 it can be specified multiple times. Currently, this option is not
3288 compatible with --graph. This option is experimental.
3283 compatible with --graph. This option is experimental.
3289
3284
3290 .. note::
3285 .. note::
3291
3286
3292 :hg:`log --patch` may generate unexpected diff output for merge
3287 :hg:`log --patch` may generate unexpected diff output for merge
3293 changesets, as it will only compare the merge changeset against
3288 changesets, as it will only compare the merge changeset against
3294 its first parent. Also, only files different from BOTH parents
3289 its first parent. Also, only files different from BOTH parents
3295 will appear in files:.
3290 will appear in files:.
3296
3291
3297 .. note::
3292 .. note::
3298
3293
3299 For performance reasons, :hg:`log FILE` may omit duplicate changes
3294 For performance reasons, :hg:`log FILE` may omit duplicate changes
3300 made on branches and will not show removals or mode changes. To
3295 made on branches and will not show removals or mode changes. To
3301 see all such changes, use the --removed switch.
3296 see all such changes, use the --removed switch.
3302
3297
3303 .. container:: verbose
3298 .. container:: verbose
3304
3299
3305 .. note::
3300 .. note::
3306
3301
3307 The history resulting from -L/--line-range options depends on diff
3302 The history resulting from -L/--line-range options depends on diff
3308 options; for instance if white-spaces are ignored, respective changes
3303 options; for instance if white-spaces are ignored, respective changes
3309 with only white-spaces in specified line range will not be listed.
3304 with only white-spaces in specified line range will not be listed.
3310
3305
3311 .. container:: verbose
3306 .. container:: verbose
3312
3307
3313 Some examples:
3308 Some examples:
3314
3309
3315 - changesets with full descriptions and file lists::
3310 - changesets with full descriptions and file lists::
3316
3311
3317 hg log -v
3312 hg log -v
3318
3313
3319 - changesets ancestral to the working directory::
3314 - changesets ancestral to the working directory::
3320
3315
3321 hg log -f
3316 hg log -f
3322
3317
3323 - last 10 commits on the current branch::
3318 - last 10 commits on the current branch::
3324
3319
3325 hg log -l 10 -b .
3320 hg log -l 10 -b .
3326
3321
3327 - changesets showing all modifications of a file, including removals::
3322 - changesets showing all modifications of a file, including removals::
3328
3323
3329 hg log --removed file.c
3324 hg log --removed file.c
3330
3325
3331 - all changesets that touch a directory, with diffs, excluding merges::
3326 - all changesets that touch a directory, with diffs, excluding merges::
3332
3327
3333 hg log -Mp lib/
3328 hg log -Mp lib/
3334
3329
3335 - all revision numbers that match a keyword::
3330 - all revision numbers that match a keyword::
3336
3331
3337 hg log -k bug --template "{rev}\\n"
3332 hg log -k bug --template "{rev}\\n"
3338
3333
3339 - the full hash identifier of the working directory parent::
3334 - the full hash identifier of the working directory parent::
3340
3335
3341 hg log -r . --template "{node}\\n"
3336 hg log -r . --template "{node}\\n"
3342
3337
3343 - list available log templates::
3338 - list available log templates::
3344
3339
3345 hg log -T list
3340 hg log -T list
3346
3341
3347 - check if a given changeset is included in a tagged release::
3342 - check if a given changeset is included in a tagged release::
3348
3343
3349 hg log -r "a21ccf and ancestor(1.9)"
3344 hg log -r "a21ccf and ancestor(1.9)"
3350
3345
3351 - find all changesets by some user in a date range::
3346 - find all changesets by some user in a date range::
3352
3347
3353 hg log -k alice -d "may 2008 to jul 2008"
3348 hg log -k alice -d "may 2008 to jul 2008"
3354
3349
3355 - summary of all changesets after the last tag::
3350 - summary of all changesets after the last tag::
3356
3351
3357 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3352 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3358
3353
3359 - changesets touching lines 13 to 23 for file.c::
3354 - changesets touching lines 13 to 23 for file.c::
3360
3355
3361 hg log -L file.c,13:23
3356 hg log -L file.c,13:23
3362
3357
3363 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3358 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
3364 main.c with patch::
3359 main.c with patch::
3365
3360
3366 hg log -L file.c,13:23 -L main.c,2:6 -p
3361 hg log -L file.c,13:23 -L main.c,2:6 -p
3367
3362
3368 See :hg:`help dates` for a list of formats valid for -d/--date.
3363 See :hg:`help dates` for a list of formats valid for -d/--date.
3369
3364
3370 See :hg:`help revisions` for more about specifying and ordering
3365 See :hg:`help revisions` for more about specifying and ordering
3371 revisions.
3366 revisions.
3372
3367
3373 See :hg:`help templates` for more about pre-packaged styles and
3368 See :hg:`help templates` for more about pre-packaged styles and
3374 specifying custom templates. The default template used by the log
3369 specifying custom templates. The default template used by the log
3375 command can be customized via the ``ui.logtemplate`` configuration
3370 command can be customized via the ``ui.logtemplate`` configuration
3376 setting.
3371 setting.
3377
3372
3378 Returns 0 on success.
3373 Returns 0 on success.
3379
3374
3380 """
3375 """
3381 opts = pycompat.byteskwargs(opts)
3376 opts = pycompat.byteskwargs(opts)
3382 linerange = opts.get('line_range')
3377 linerange = opts.get('line_range')
3383
3378
3384 if linerange and not opts.get('follow'):
3379 if linerange and not opts.get('follow'):
3385 raise error.Abort(_('--line-range requires --follow'))
3380 raise error.Abort(_('--line-range requires --follow'))
3386
3381
3387 if linerange and pats:
3382 if linerange and pats:
3388 raise error.Abort(
3383 raise error.Abort(
3389 _('FILE arguments are not compatible with --line-range option')
3384 _('FILE arguments are not compatible with --line-range option')
3390 )
3385 )
3391
3386
3392 if opts.get('follow') and opts.get('rev'):
3387 if opts.get('follow') and opts.get('rev'):
3393 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3388 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3394 del opts['follow']
3389 del opts['follow']
3395
3390
3396 if opts.get('graph'):
3391 if opts.get('graph'):
3397 if linerange:
3392 if linerange:
3398 raise error.Abort(_('graph not supported with line range patterns'))
3393 raise error.Abort(_('graph not supported with line range patterns'))
3399 return cmdutil.graphlog(ui, repo, pats, opts)
3394 return cmdutil.graphlog(ui, repo, pats, opts)
3400
3395
3401 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3396 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3402 hunksfilter = None
3397 hunksfilter = None
3403
3398
3404 if linerange:
3399 if linerange:
3405 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3400 revs, lrfilematcher, hunksfilter = cmdutil.getloglinerangerevs(
3406 repo, revs, opts)
3401 repo, revs, opts)
3407
3402
3408 if filematcher is not None and lrfilematcher is not None:
3403 if filematcher is not None and lrfilematcher is not None:
3409 basefilematcher = filematcher
3404 basefilematcher = filematcher
3410
3405
3411 def filematcher(rev):
3406 def filematcher(rev):
3412 files = (basefilematcher(rev).files()
3407 files = (basefilematcher(rev).files()
3413 + lrfilematcher(rev).files())
3408 + lrfilematcher(rev).files())
3414 return scmutil.matchfiles(repo, files)
3409 return scmutil.matchfiles(repo, files)
3415
3410
3416 elif filematcher is None:
3411 elif filematcher is None:
3417 filematcher = lrfilematcher
3412 filematcher = lrfilematcher
3418
3413
3419 limit = cmdutil.loglimit(opts)
3414 limit = cmdutil.loglimit(opts)
3420 count = 0
3415 count = 0
3421
3416
3422 getrenamed = None
3417 getrenamed = None
3423 if opts.get('copies'):
3418 if opts.get('copies'):
3424 endrev = None
3419 endrev = None
3425 if opts.get('rev'):
3420 if opts.get('rev'):
3426 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3421 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3427 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3422 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3428
3423
3429 ui.pager('log')
3424 ui.pager('log')
3430 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3425 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3431 for rev in revs:
3426 for rev in revs:
3432 if count == limit:
3427 if count == limit:
3433 break
3428 break
3434 ctx = repo[rev]
3429 ctx = repo[rev]
3435 copies = None
3430 copies = None
3436 if getrenamed is not None and rev:
3431 if getrenamed is not None and rev:
3437 copies = []
3432 copies = []
3438 for fn in ctx.files():
3433 for fn in ctx.files():
3439 rename = getrenamed(fn, rev)
3434 rename = getrenamed(fn, rev)
3440 if rename:
3435 if rename:
3441 copies.append((fn, rename[0]))
3436 copies.append((fn, rename[0]))
3442 if filematcher:
3437 if filematcher:
3443 revmatchfn = filematcher(ctx.rev())
3438 revmatchfn = filematcher(ctx.rev())
3444 else:
3439 else:
3445 revmatchfn = None
3440 revmatchfn = None
3446 if hunksfilter:
3441 if hunksfilter:
3447 revhunksfilter = hunksfilter(rev)
3442 revhunksfilter = hunksfilter(rev)
3448 else:
3443 else:
3449 revhunksfilter = None
3444 revhunksfilter = None
3450 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3445 displayer.show(ctx, copies=copies, matchfn=revmatchfn,
3451 hunksfilterfn=revhunksfilter)
3446 hunksfilterfn=revhunksfilter)
3452 if displayer.flush(ctx):
3447 if displayer.flush(ctx):
3453 count += 1
3448 count += 1
3454
3449
3455 displayer.close()
3450 displayer.close()
3456
3451
3457 @command('manifest',
3452 @command('manifest',
3458 [('r', 'rev', '', _('revision to display'), _('REV')),
3453 [('r', 'rev', '', _('revision to display'), _('REV')),
3459 ('', 'all', False, _("list files from all revisions"))]
3454 ('', 'all', False, _("list files from all revisions"))]
3460 + formatteropts,
3455 + formatteropts,
3461 _('[-r REV]'), cmdtype=readonly)
3456 _('[-r REV]'), cmdtype=readonly)
3462 def manifest(ui, repo, node=None, rev=None, **opts):
3457 def manifest(ui, repo, node=None, rev=None, **opts):
3463 """output the current or given revision of the project manifest
3458 """output the current or given revision of the project manifest
3464
3459
3465 Print a list of version controlled files for the given revision.
3460 Print a list of version controlled files for the given revision.
3466 If no revision is given, the first parent of the working directory
3461 If no revision is given, the first parent of the working directory
3467 is used, or the null revision if no revision is checked out.
3462 is used, or the null revision if no revision is checked out.
3468
3463
3469 With -v, print file permissions, symlink and executable bits.
3464 With -v, print file permissions, symlink and executable bits.
3470 With --debug, print file revision hashes.
3465 With --debug, print file revision hashes.
3471
3466
3472 If option --all is specified, the list of all files from all revisions
3467 If option --all is specified, the list of all files from all revisions
3473 is printed. This includes deleted and renamed files.
3468 is printed. This includes deleted and renamed files.
3474
3469
3475 Returns 0 on success.
3470 Returns 0 on success.
3476 """
3471 """
3477 opts = pycompat.byteskwargs(opts)
3472 opts = pycompat.byteskwargs(opts)
3478 fm = ui.formatter('manifest', opts)
3473 fm = ui.formatter('manifest', opts)
3479
3474
3480 if opts.get('all'):
3475 if opts.get('all'):
3481 if rev or node:
3476 if rev or node:
3482 raise error.Abort(_("can't specify a revision with --all"))
3477 raise error.Abort(_("can't specify a revision with --all"))
3483
3478
3484 res = []
3479 res = []
3485 prefix = "data/"
3480 prefix = "data/"
3486 suffix = ".i"
3481 suffix = ".i"
3487 plen = len(prefix)
3482 plen = len(prefix)
3488 slen = len(suffix)
3483 slen = len(suffix)
3489 with repo.lock():
3484 with repo.lock():
3490 for fn, b, size in repo.store.datafiles():
3485 for fn, b, size in repo.store.datafiles():
3491 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3486 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3492 res.append(fn[plen:-slen])
3487 res.append(fn[plen:-slen])
3493 ui.pager('manifest')
3488 ui.pager('manifest')
3494 for f in res:
3489 for f in res:
3495 fm.startitem()
3490 fm.startitem()
3496 fm.write("path", '%s\n', f)
3491 fm.write("path", '%s\n', f)
3497 fm.end()
3492 fm.end()
3498 return
3493 return
3499
3494
3500 if rev and node:
3495 if rev and node:
3501 raise error.Abort(_("please specify just one revision"))
3496 raise error.Abort(_("please specify just one revision"))
3502
3497
3503 if not node:
3498 if not node:
3504 node = rev
3499 node = rev
3505
3500
3506 char = {'l': '@', 'x': '*', '': ''}
3501 char = {'l': '@', 'x': '*', '': ''}
3507 mode = {'l': '644', 'x': '755', '': '644'}
3502 mode = {'l': '644', 'x': '755', '': '644'}
3508 ctx = scmutil.revsingle(repo, node)
3503 ctx = scmutil.revsingle(repo, node)
3509 mf = ctx.manifest()
3504 mf = ctx.manifest()
3510 ui.pager('manifest')
3505 ui.pager('manifest')
3511 for f in ctx:
3506 for f in ctx:
3512 fm.startitem()
3507 fm.startitem()
3513 fl = ctx[f].flags()
3508 fl = ctx[f].flags()
3514 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3509 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3515 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3510 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3516 fm.write('path', '%s\n', f)
3511 fm.write('path', '%s\n', f)
3517 fm.end()
3512 fm.end()
3518
3513
3519 @command('^merge',
3514 @command('^merge',
3520 [('f', 'force', None,
3515 [('f', 'force', None,
3521 _('force a merge including outstanding changes (DEPRECATED)')),
3516 _('force a merge including outstanding changes (DEPRECATED)')),
3522 ('r', 'rev', '', _('revision to merge'), _('REV')),
3517 ('r', 'rev', '', _('revision to merge'), _('REV')),
3523 ('P', 'preview', None,
3518 ('P', 'preview', None,
3524 _('review revisions to merge (no merge is performed)'))
3519 _('review revisions to merge (no merge is performed)'))
3525 ] + mergetoolopts,
3520 ] + mergetoolopts,
3526 _('[-P] [[-r] REV]'))
3521 _('[-P] [[-r] REV]'))
3527 def merge(ui, repo, node=None, **opts):
3522 def merge(ui, repo, node=None, **opts):
3528 """merge another revision into working directory
3523 """merge another revision into working directory
3529
3524
3530 The current working directory is updated with all changes made in
3525 The current working directory is updated with all changes made in
3531 the requested revision since the last common predecessor revision.
3526 the requested revision since the last common predecessor revision.
3532
3527
3533 Files that changed between either parent are marked as changed for
3528 Files that changed between either parent are marked as changed for
3534 the next commit and a commit must be performed before any further
3529 the next commit and a commit must be performed before any further
3535 updates to the repository are allowed. The next commit will have
3530 updates to the repository are allowed. The next commit will have
3536 two parents.
3531 two parents.
3537
3532
3538 ``--tool`` can be used to specify the merge tool used for file
3533 ``--tool`` can be used to specify the merge tool used for file
3539 merges. It overrides the HGMERGE environment variable and your
3534 merges. It overrides the HGMERGE environment variable and your
3540 configuration files. See :hg:`help merge-tools` for options.
3535 configuration files. See :hg:`help merge-tools` for options.
3541
3536
3542 If no revision is specified, the working directory's parent is a
3537 If no revision is specified, the working directory's parent is a
3543 head revision, and the current branch contains exactly one other
3538 head revision, and the current branch contains exactly one other
3544 head, the other head is merged with by default. Otherwise, an
3539 head, the other head is merged with by default. Otherwise, an
3545 explicit revision with which to merge with must be provided.
3540 explicit revision with which to merge with must be provided.
3546
3541
3547 See :hg:`help resolve` for information on handling file conflicts.
3542 See :hg:`help resolve` for information on handling file conflicts.
3548
3543
3549 To undo an uncommitted merge, use :hg:`update --clean .` which
3544 To undo an uncommitted merge, use :hg:`update --clean .` which
3550 will check out a clean copy of the original merge parent, losing
3545 will check out a clean copy of the original merge parent, losing
3551 all changes.
3546 all changes.
3552
3547
3553 Returns 0 on success, 1 if there are unresolved files.
3548 Returns 0 on success, 1 if there are unresolved files.
3554 """
3549 """
3555
3550
3556 opts = pycompat.byteskwargs(opts)
3551 opts = pycompat.byteskwargs(opts)
3557 if opts.get('rev') and node:
3552 if opts.get('rev') and node:
3558 raise error.Abort(_("please specify just one revision"))
3553 raise error.Abort(_("please specify just one revision"))
3559 if not node:
3554 if not node:
3560 node = opts.get('rev')
3555 node = opts.get('rev')
3561
3556
3562 if node:
3557 if node:
3563 node = scmutil.revsingle(repo, node).node()
3558 node = scmutil.revsingle(repo, node).node()
3564
3559
3565 if not node:
3560 if not node:
3566 node = repo[destutil.destmerge(repo)].node()
3561 node = repo[destutil.destmerge(repo)].node()
3567
3562
3568 if opts.get('preview'):
3563 if opts.get('preview'):
3569 # find nodes that are ancestors of p2 but not of p1
3564 # find nodes that are ancestors of p2 but not of p1
3570 p1 = repo.lookup('.')
3565 p1 = repo.lookup('.')
3571 p2 = repo.lookup(node)
3566 p2 = repo.lookup(node)
3572 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3567 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3573
3568
3574 displayer = cmdutil.show_changeset(ui, repo, opts)
3569 displayer = cmdutil.show_changeset(ui, repo, opts)
3575 for node in nodes:
3570 for node in nodes:
3576 displayer.show(repo[node])
3571 displayer.show(repo[node])
3577 displayer.close()
3572 displayer.close()
3578 return 0
3573 return 0
3579
3574
3580 try:
3575 try:
3581 # ui.forcemerge is an internal variable, do not document
3576 # ui.forcemerge is an internal variable, do not document
3582 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3577 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3583 force = opts.get('force')
3578 force = opts.get('force')
3584 labels = ['working copy', 'merge rev']
3579 labels = ['working copy', 'merge rev']
3585 return hg.merge(repo, node, force=force, mergeforce=force,
3580 return hg.merge(repo, node, force=force, mergeforce=force,
3586 labels=labels)
3581 labels=labels)
3587 finally:
3582 finally:
3588 ui.setconfig('ui', 'forcemerge', '', 'merge')
3583 ui.setconfig('ui', 'forcemerge', '', 'merge')
3589
3584
3590 @command('outgoing|out',
3585 @command('outgoing|out',
3591 [('f', 'force', None, _('run even when the destination is unrelated')),
3586 [('f', 'force', None, _('run even when the destination is unrelated')),
3592 ('r', 'rev', [],
3587 ('r', 'rev', [],
3593 _('a changeset intended to be included in the destination'), _('REV')),
3588 _('a changeset intended to be included in the destination'), _('REV')),
3594 ('n', 'newest-first', None, _('show newest record first')),
3589 ('n', 'newest-first', None, _('show newest record first')),
3595 ('B', 'bookmarks', False, _('compare bookmarks')),
3590 ('B', 'bookmarks', False, _('compare bookmarks')),
3596 ('b', 'branch', [], _('a specific branch you would like to push'),
3591 ('b', 'branch', [], _('a specific branch you would like to push'),
3597 _('BRANCH')),
3592 _('BRANCH')),
3598 ] + logopts + remoteopts + subrepoopts,
3593 ] + logopts + remoteopts + subrepoopts,
3599 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3594 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3600 def outgoing(ui, repo, dest=None, **opts):
3595 def outgoing(ui, repo, dest=None, **opts):
3601 """show changesets not found in the destination
3596 """show changesets not found in the destination
3602
3597
3603 Show changesets not found in the specified destination repository
3598 Show changesets not found in the specified destination repository
3604 or the default push location. These are the changesets that would
3599 or the default push location. These are the changesets that would
3605 be pushed if a push was requested.
3600 be pushed if a push was requested.
3606
3601
3607 See pull for details of valid destination formats.
3602 See pull for details of valid destination formats.
3608
3603
3609 .. container:: verbose
3604 .. container:: verbose
3610
3605
3611 With -B/--bookmarks, the result of bookmark comparison between
3606 With -B/--bookmarks, the result of bookmark comparison between
3612 local and remote repositories is displayed. With -v/--verbose,
3607 local and remote repositories is displayed. With -v/--verbose,
3613 status is also displayed for each bookmark like below::
3608 status is also displayed for each bookmark like below::
3614
3609
3615 BM1 01234567890a added
3610 BM1 01234567890a added
3616 BM2 deleted
3611 BM2 deleted
3617 BM3 234567890abc advanced
3612 BM3 234567890abc advanced
3618 BM4 34567890abcd diverged
3613 BM4 34567890abcd diverged
3619 BM5 4567890abcde changed
3614 BM5 4567890abcde changed
3620
3615
3621 The action taken when pushing depends on the
3616 The action taken when pushing depends on the
3622 status of each bookmark:
3617 status of each bookmark:
3623
3618
3624 :``added``: push with ``-B`` will create it
3619 :``added``: push with ``-B`` will create it
3625 :``deleted``: push with ``-B`` will delete it
3620 :``deleted``: push with ``-B`` will delete it
3626 :``advanced``: push will update it
3621 :``advanced``: push will update it
3627 :``diverged``: push with ``-B`` will update it
3622 :``diverged``: push with ``-B`` will update it
3628 :``changed``: push with ``-B`` will update it
3623 :``changed``: push with ``-B`` will update it
3629
3624
3630 From the point of view of pushing behavior, bookmarks
3625 From the point of view of pushing behavior, bookmarks
3631 existing only in the remote repository are treated as
3626 existing only in the remote repository are treated as
3632 ``deleted``, even if it is in fact added remotely.
3627 ``deleted``, even if it is in fact added remotely.
3633
3628
3634 Returns 0 if there are outgoing changes, 1 otherwise.
3629 Returns 0 if there are outgoing changes, 1 otherwise.
3635 """
3630 """
3636 opts = pycompat.byteskwargs(opts)
3631 opts = pycompat.byteskwargs(opts)
3637 if opts.get('graph'):
3632 if opts.get('graph'):
3638 cmdutil.checkunsupportedgraphflags([], opts)
3633 cmdutil.checkunsupportedgraphflags([], opts)
3639 o, other = hg._outgoing(ui, repo, dest, opts)
3634 o, other = hg._outgoing(ui, repo, dest, opts)
3640 if not o:
3635 if not o:
3641 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3636 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3642 return
3637 return
3643
3638
3644 revdag = cmdutil.graphrevs(repo, o, opts)
3639 revdag = cmdutil.graphrevs(repo, o, opts)
3645 ui.pager('outgoing')
3640 ui.pager('outgoing')
3646 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3641 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3647 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3642 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3648 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3643 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3649 return 0
3644 return 0
3650
3645
3651 if opts.get('bookmarks'):
3646 if opts.get('bookmarks'):
3652 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3647 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3653 dest, branches = hg.parseurl(dest, opts.get('branch'))
3648 dest, branches = hg.parseurl(dest, opts.get('branch'))
3654 other = hg.peer(repo, opts, dest)
3649 other = hg.peer(repo, opts, dest)
3655 if 'bookmarks' not in other.listkeys('namespaces'):
3650 if 'bookmarks' not in other.listkeys('namespaces'):
3656 ui.warn(_("remote doesn't support bookmarks\n"))
3651 ui.warn(_("remote doesn't support bookmarks\n"))
3657 return 0
3652 return 0
3658 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3653 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3659 ui.pager('outgoing')
3654 ui.pager('outgoing')
3660 return bookmarks.outgoing(ui, repo, other)
3655 return bookmarks.outgoing(ui, repo, other)
3661
3656
3662 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3657 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3663 try:
3658 try:
3664 return hg.outgoing(ui, repo, dest, opts)
3659 return hg.outgoing(ui, repo, dest, opts)
3665 finally:
3660 finally:
3666 del repo._subtoppath
3661 del repo._subtoppath
3667
3662
3668 @command('parents',
3663 @command('parents',
3669 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3664 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3670 ] + templateopts,
3665 ] + templateopts,
3671 _('[-r REV] [FILE]'),
3666 _('[-r REV] [FILE]'),
3672 inferrepo=True)
3667 inferrepo=True)
3673 def parents(ui, repo, file_=None, **opts):
3668 def parents(ui, repo, file_=None, **opts):
3674 """show the parents of the working directory or revision (DEPRECATED)
3669 """show the parents of the working directory or revision (DEPRECATED)
3675
3670
3676 Print the working directory's parent revisions. If a revision is
3671 Print the working directory's parent revisions. If a revision is
3677 given via -r/--rev, the parent of that revision will be printed.
3672 given via -r/--rev, the parent of that revision will be printed.
3678 If a file argument is given, the revision in which the file was
3673 If a file argument is given, the revision in which the file was
3679 last changed (before the working directory revision or the
3674 last changed (before the working directory revision or the
3680 argument to --rev if given) is printed.
3675 argument to --rev if given) is printed.
3681
3676
3682 This command is equivalent to::
3677 This command is equivalent to::
3683
3678
3684 hg log -r "p1()+p2()" or
3679 hg log -r "p1()+p2()" or
3685 hg log -r "p1(REV)+p2(REV)" or
3680 hg log -r "p1(REV)+p2(REV)" or
3686 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3681 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3687 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3682 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3688
3683
3689 See :hg:`summary` and :hg:`help revsets` for related information.
3684 See :hg:`summary` and :hg:`help revsets` for related information.
3690
3685
3691 Returns 0 on success.
3686 Returns 0 on success.
3692 """
3687 """
3693
3688
3694 opts = pycompat.byteskwargs(opts)
3689 opts = pycompat.byteskwargs(opts)
3695 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3690 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3696
3691
3697 if file_:
3692 if file_:
3698 m = scmutil.match(ctx, (file_,), opts)
3693 m = scmutil.match(ctx, (file_,), opts)
3699 if m.anypats() or len(m.files()) != 1:
3694 if m.anypats() or len(m.files()) != 1:
3700 raise error.Abort(_('can only specify an explicit filename'))
3695 raise error.Abort(_('can only specify an explicit filename'))
3701 file_ = m.files()[0]
3696 file_ = m.files()[0]
3702 filenodes = []
3697 filenodes = []
3703 for cp in ctx.parents():
3698 for cp in ctx.parents():
3704 if not cp:
3699 if not cp:
3705 continue
3700 continue
3706 try:
3701 try:
3707 filenodes.append(cp.filenode(file_))
3702 filenodes.append(cp.filenode(file_))
3708 except error.LookupError:
3703 except error.LookupError:
3709 pass
3704 pass
3710 if not filenodes:
3705 if not filenodes:
3711 raise error.Abort(_("'%s' not found in manifest!") % file_)
3706 raise error.Abort(_("'%s' not found in manifest!") % file_)
3712 p = []
3707 p = []
3713 for fn in filenodes:
3708 for fn in filenodes:
3714 fctx = repo.filectx(file_, fileid=fn)
3709 fctx = repo.filectx(file_, fileid=fn)
3715 p.append(fctx.node())
3710 p.append(fctx.node())
3716 else:
3711 else:
3717 p = [cp.node() for cp in ctx.parents()]
3712 p = [cp.node() for cp in ctx.parents()]
3718
3713
3719 displayer = cmdutil.show_changeset(ui, repo, opts)
3714 displayer = cmdutil.show_changeset(ui, repo, opts)
3720 for n in p:
3715 for n in p:
3721 if n != nullid:
3716 if n != nullid:
3722 displayer.show(repo[n])
3717 displayer.show(repo[n])
3723 displayer.close()
3718 displayer.close()
3724
3719
3725 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3720 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True,
3726 cmdtype=readonly)
3721 cmdtype=readonly)
3727 def paths(ui, repo, search=None, **opts):
3722 def paths(ui, repo, search=None, **opts):
3728 """show aliases for remote repositories
3723 """show aliases for remote repositories
3729
3724
3730 Show definition of symbolic path name NAME. If no name is given,
3725 Show definition of symbolic path name NAME. If no name is given,
3731 show definition of all available names.
3726 show definition of all available names.
3732
3727
3733 Option -q/--quiet suppresses all output when searching for NAME
3728 Option -q/--quiet suppresses all output when searching for NAME
3734 and shows only the path names when listing all definitions.
3729 and shows only the path names when listing all definitions.
3735
3730
3736 Path names are defined in the [paths] section of your
3731 Path names are defined in the [paths] section of your
3737 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3732 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3738 repository, ``.hg/hgrc`` is used, too.
3733 repository, ``.hg/hgrc`` is used, too.
3739
3734
3740 The path names ``default`` and ``default-push`` have a special
3735 The path names ``default`` and ``default-push`` have a special
3741 meaning. When performing a push or pull operation, they are used
3736 meaning. When performing a push or pull operation, they are used
3742 as fallbacks if no location is specified on the command-line.
3737 as fallbacks if no location is specified on the command-line.
3743 When ``default-push`` is set, it will be used for push and
3738 When ``default-push`` is set, it will be used for push and
3744 ``default`` will be used for pull; otherwise ``default`` is used
3739 ``default`` will be used for pull; otherwise ``default`` is used
3745 as the fallback for both. When cloning a repository, the clone
3740 as the fallback for both. When cloning a repository, the clone
3746 source is written as ``default`` in ``.hg/hgrc``.
3741 source is written as ``default`` in ``.hg/hgrc``.
3747
3742
3748 .. note::
3743 .. note::
3749
3744
3750 ``default`` and ``default-push`` apply to all inbound (e.g.
3745 ``default`` and ``default-push`` apply to all inbound (e.g.
3751 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3746 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3752 and :hg:`bundle`) operations.
3747 and :hg:`bundle`) operations.
3753
3748
3754 See :hg:`help urls` for more information.
3749 See :hg:`help urls` for more information.
3755
3750
3756 Returns 0 on success.
3751 Returns 0 on success.
3757 """
3752 """
3758
3753
3759 opts = pycompat.byteskwargs(opts)
3754 opts = pycompat.byteskwargs(opts)
3760 ui.pager('paths')
3755 ui.pager('paths')
3761 if search:
3756 if search:
3762 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3757 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3763 if name == search]
3758 if name == search]
3764 else:
3759 else:
3765 pathitems = sorted(ui.paths.iteritems())
3760 pathitems = sorted(ui.paths.iteritems())
3766
3761
3767 fm = ui.formatter('paths', opts)
3762 fm = ui.formatter('paths', opts)
3768 if fm.isplain():
3763 if fm.isplain():
3769 hidepassword = util.hidepassword
3764 hidepassword = util.hidepassword
3770 else:
3765 else:
3771 hidepassword = str
3766 hidepassword = str
3772 if ui.quiet:
3767 if ui.quiet:
3773 namefmt = '%s\n'
3768 namefmt = '%s\n'
3774 else:
3769 else:
3775 namefmt = '%s = '
3770 namefmt = '%s = '
3776 showsubopts = not search and not ui.quiet
3771 showsubopts = not search and not ui.quiet
3777
3772
3778 for name, path in pathitems:
3773 for name, path in pathitems:
3779 fm.startitem()
3774 fm.startitem()
3780 fm.condwrite(not search, 'name', namefmt, name)
3775 fm.condwrite(not search, 'name', namefmt, name)
3781 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3776 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3782 for subopt, value in sorted(path.suboptions.items()):
3777 for subopt, value in sorted(path.suboptions.items()):
3783 assert subopt not in ('name', 'url')
3778 assert subopt not in ('name', 'url')
3784 if showsubopts:
3779 if showsubopts:
3785 fm.plain('%s:%s = ' % (name, subopt))
3780 fm.plain('%s:%s = ' % (name, subopt))
3786 fm.condwrite(showsubopts, subopt, '%s\n', value)
3781 fm.condwrite(showsubopts, subopt, '%s\n', value)
3787
3782
3788 fm.end()
3783 fm.end()
3789
3784
3790 if search and not pathitems:
3785 if search and not pathitems:
3791 if not ui.quiet:
3786 if not ui.quiet:
3792 ui.warn(_("not found!\n"))
3787 ui.warn(_("not found!\n"))
3793 return 1
3788 return 1
3794 else:
3789 else:
3795 return 0
3790 return 0
3796
3791
3797 @command('phase',
3792 @command('phase',
3798 [('p', 'public', False, _('set changeset phase to public')),
3793 [('p', 'public', False, _('set changeset phase to public')),
3799 ('d', 'draft', False, _('set changeset phase to draft')),
3794 ('d', 'draft', False, _('set changeset phase to draft')),
3800 ('s', 'secret', False, _('set changeset phase to secret')),
3795 ('s', 'secret', False, _('set changeset phase to secret')),
3801 ('f', 'force', False, _('allow to move boundary backward')),
3796 ('f', 'force', False, _('allow to move boundary backward')),
3802 ('r', 'rev', [], _('target revision'), _('REV')),
3797 ('r', 'rev', [], _('target revision'), _('REV')),
3803 ],
3798 ],
3804 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3799 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3805 def phase(ui, repo, *revs, **opts):
3800 def phase(ui, repo, *revs, **opts):
3806 """set or show the current phase name
3801 """set or show the current phase name
3807
3802
3808 With no argument, show the phase name of the current revision(s).
3803 With no argument, show the phase name of the current revision(s).
3809
3804
3810 With one of -p/--public, -d/--draft or -s/--secret, change the
3805 With one of -p/--public, -d/--draft or -s/--secret, change the
3811 phase value of the specified revisions.
3806 phase value of the specified revisions.
3812
3807
3813 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3808 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
3814 lower phase to a higher phase. Phases are ordered as follows::
3809 lower phase to a higher phase. Phases are ordered as follows::
3815
3810
3816 public < draft < secret
3811 public < draft < secret
3817
3812
3818 Returns 0 on success, 1 if some phases could not be changed.
3813 Returns 0 on success, 1 if some phases could not be changed.
3819
3814
3820 (For more information about the phases concept, see :hg:`help phases`.)
3815 (For more information about the phases concept, see :hg:`help phases`.)
3821 """
3816 """
3822 opts = pycompat.byteskwargs(opts)
3817 opts = pycompat.byteskwargs(opts)
3823 # search for a unique phase argument
3818 # search for a unique phase argument
3824 targetphase = None
3819 targetphase = None
3825 for idx, name in enumerate(phases.phasenames):
3820 for idx, name in enumerate(phases.phasenames):
3826 if opts[name]:
3821 if opts[name]:
3827 if targetphase is not None:
3822 if targetphase is not None:
3828 raise error.Abort(_('only one phase can be specified'))
3823 raise error.Abort(_('only one phase can be specified'))
3829 targetphase = idx
3824 targetphase = idx
3830
3825
3831 # look for specified revision
3826 # look for specified revision
3832 revs = list(revs)
3827 revs = list(revs)
3833 revs.extend(opts['rev'])
3828 revs.extend(opts['rev'])
3834 if not revs:
3829 if not revs:
3835 # display both parents as the second parent phase can influence
3830 # display both parents as the second parent phase can influence
3836 # the phase of a merge commit
3831 # the phase of a merge commit
3837 revs = [c.rev() for c in repo[None].parents()]
3832 revs = [c.rev() for c in repo[None].parents()]
3838
3833
3839 revs = scmutil.revrange(repo, revs)
3834 revs = scmutil.revrange(repo, revs)
3840
3835
3841 lock = None
3836 lock = None
3842 ret = 0
3837 ret = 0
3843 if targetphase is None:
3838 if targetphase is None:
3844 # display
3839 # display
3845 for r in revs:
3840 for r in revs:
3846 ctx = repo[r]
3841 ctx = repo[r]
3847 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3842 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3848 else:
3843 else:
3849 tr = None
3844 tr = None
3850 lock = repo.lock()
3845 lock = repo.lock()
3851 try:
3846 try:
3852 tr = repo.transaction("phase")
3847 tr = repo.transaction("phase")
3853 # set phase
3848 # set phase
3854 if not revs:
3849 if not revs:
3855 raise error.Abort(_('empty revision set'))
3850 raise error.Abort(_('empty revision set'))
3856 nodes = [repo[r].node() for r in revs]
3851 nodes = [repo[r].node() for r in revs]
3857 # moving revision from public to draft may hide them
3852 # moving revision from public to draft may hide them
3858 # We have to check result on an unfiltered repository
3853 # We have to check result on an unfiltered repository
3859 unfi = repo.unfiltered()
3854 unfi = repo.unfiltered()
3860 getphase = unfi._phasecache.phase
3855 getphase = unfi._phasecache.phase
3861 olddata = [getphase(unfi, r) for r in unfi]
3856 olddata = [getphase(unfi, r) for r in unfi]
3862 phases.advanceboundary(repo, tr, targetphase, nodes)
3857 phases.advanceboundary(repo, tr, targetphase, nodes)
3863 if opts['force']:
3858 if opts['force']:
3864 phases.retractboundary(repo, tr, targetphase, nodes)
3859 phases.retractboundary(repo, tr, targetphase, nodes)
3865 tr.close()
3860 tr.close()
3866 finally:
3861 finally:
3867 if tr is not None:
3862 if tr is not None:
3868 tr.release()
3863 tr.release()
3869 lock.release()
3864 lock.release()
3870 getphase = unfi._phasecache.phase
3865 getphase = unfi._phasecache.phase
3871 newdata = [getphase(unfi, r) for r in unfi]
3866 newdata = [getphase(unfi, r) for r in unfi]
3872 changes = sum(newdata[r] != olddata[r] for r in unfi)
3867 changes = sum(newdata[r] != olddata[r] for r in unfi)
3873 cl = unfi.changelog
3868 cl = unfi.changelog
3874 rejected = [n for n in nodes
3869 rejected = [n for n in nodes
3875 if newdata[cl.rev(n)] < targetphase]
3870 if newdata[cl.rev(n)] < targetphase]
3876 if rejected:
3871 if rejected:
3877 ui.warn(_('cannot move %i changesets to a higher '
3872 ui.warn(_('cannot move %i changesets to a higher '
3878 'phase, use --force\n') % len(rejected))
3873 'phase, use --force\n') % len(rejected))
3879 ret = 1
3874 ret = 1
3880 if changes:
3875 if changes:
3881 msg = _('phase changed for %i changesets\n') % changes
3876 msg = _('phase changed for %i changesets\n') % changes
3882 if ret:
3877 if ret:
3883 ui.status(msg)
3878 ui.status(msg)
3884 else:
3879 else:
3885 ui.note(msg)
3880 ui.note(msg)
3886 else:
3881 else:
3887 ui.warn(_('no phases changed\n'))
3882 ui.warn(_('no phases changed\n'))
3888 return ret
3883 return ret
3889
3884
3890 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3885 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3891 """Run after a changegroup has been added via pull/unbundle
3886 """Run after a changegroup has been added via pull/unbundle
3892
3887
3893 This takes arguments below:
3888 This takes arguments below:
3894
3889
3895 :modheads: change of heads by pull/unbundle
3890 :modheads: change of heads by pull/unbundle
3896 :optupdate: updating working directory is needed or not
3891 :optupdate: updating working directory is needed or not
3897 :checkout: update destination revision (or None to default destination)
3892 :checkout: update destination revision (or None to default destination)
3898 :brev: a name, which might be a bookmark to be activated after updating
3893 :brev: a name, which might be a bookmark to be activated after updating
3899 """
3894 """
3900 if modheads == 0:
3895 if modheads == 0:
3901 return
3896 return
3902 if optupdate:
3897 if optupdate:
3903 try:
3898 try:
3904 return hg.updatetotally(ui, repo, checkout, brev)
3899 return hg.updatetotally(ui, repo, checkout, brev)
3905 except error.UpdateAbort as inst:
3900 except error.UpdateAbort as inst:
3906 msg = _("not updating: %s") % str(inst)
3901 msg = _("not updating: %s") % str(inst)
3907 hint = inst.hint
3902 hint = inst.hint
3908 raise error.UpdateAbort(msg, hint=hint)
3903 raise error.UpdateAbort(msg, hint=hint)
3909 if modheads > 1:
3904 if modheads > 1:
3910 currentbranchheads = len(repo.branchheads())
3905 currentbranchheads = len(repo.branchheads())
3911 if currentbranchheads == modheads:
3906 if currentbranchheads == modheads:
3912 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3907 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3913 elif currentbranchheads > 1:
3908 elif currentbranchheads > 1:
3914 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3909 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3915 "merge)\n"))
3910 "merge)\n"))
3916 else:
3911 else:
3917 ui.status(_("(run 'hg heads' to see heads)\n"))
3912 ui.status(_("(run 'hg heads' to see heads)\n"))
3918 elif not ui.configbool('commands', 'update.requiredest'):
3913 elif not ui.configbool('commands', 'update.requiredest'):
3919 ui.status(_("(run 'hg update' to get a working copy)\n"))
3914 ui.status(_("(run 'hg update' to get a working copy)\n"))
3920
3915
3921 @command('^pull',
3916 @command('^pull',
3922 [('u', 'update', None,
3917 [('u', 'update', None,
3923 _('update to new branch head if new descendants were pulled')),
3918 _('update to new branch head if new descendants were pulled')),
3924 ('f', 'force', None, _('run even when remote repository is unrelated')),
3919 ('f', 'force', None, _('run even when remote repository is unrelated')),
3925 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3920 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3926 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3921 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3927 ('b', 'branch', [], _('a specific branch you would like to pull'),
3922 ('b', 'branch', [], _('a specific branch you would like to pull'),
3928 _('BRANCH')),
3923 _('BRANCH')),
3929 ] + remoteopts,
3924 ] + remoteopts,
3930 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3925 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3931 def pull(ui, repo, source="default", **opts):
3926 def pull(ui, repo, source="default", **opts):
3932 """pull changes from the specified source
3927 """pull changes from the specified source
3933
3928
3934 Pull changes from a remote repository to a local one.
3929 Pull changes from a remote repository to a local one.
3935
3930
3936 This finds all changes from the repository at the specified path
3931 This finds all changes from the repository at the specified path
3937 or URL and adds them to a local repository (the current one unless
3932 or URL and adds them to a local repository (the current one unless
3938 -R is specified). By default, this does not update the copy of the
3933 -R is specified). By default, this does not update the copy of the
3939 project in the working directory.
3934 project in the working directory.
3940
3935
3941 Use :hg:`incoming` if you want to see what would have been added
3936 Use :hg:`incoming` if you want to see what would have been added
3942 by a pull at the time you issued this command. If you then decide
3937 by a pull at the time you issued this command. If you then decide
3943 to add those changes to the repository, you should use :hg:`pull
3938 to add those changes to the repository, you should use :hg:`pull
3944 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3939 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3945
3940
3946 If SOURCE is omitted, the 'default' path will be used.
3941 If SOURCE is omitted, the 'default' path will be used.
3947 See :hg:`help urls` for more information.
3942 See :hg:`help urls` for more information.
3948
3943
3949 Specifying bookmark as ``.`` is equivalent to specifying the active
3944 Specifying bookmark as ``.`` is equivalent to specifying the active
3950 bookmark's name.
3945 bookmark's name.
3951
3946
3952 Returns 0 on success, 1 if an update had unresolved files.
3947 Returns 0 on success, 1 if an update had unresolved files.
3953 """
3948 """
3954
3949
3955 opts = pycompat.byteskwargs(opts)
3950 opts = pycompat.byteskwargs(opts)
3956 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3951 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3957 msg = _('update destination required by configuration')
3952 msg = _('update destination required by configuration')
3958 hint = _('use hg pull followed by hg update DEST')
3953 hint = _('use hg pull followed by hg update DEST')
3959 raise error.Abort(msg, hint=hint)
3954 raise error.Abort(msg, hint=hint)
3960
3955
3961 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3956 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3962 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3957 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3963 other = hg.peer(repo, opts, source)
3958 other = hg.peer(repo, opts, source)
3964 try:
3959 try:
3965 revs, checkout = hg.addbranchrevs(repo, other, branches,
3960 revs, checkout = hg.addbranchrevs(repo, other, branches,
3966 opts.get('rev'))
3961 opts.get('rev'))
3967
3962
3968
3963
3969 pullopargs = {}
3964 pullopargs = {}
3970 if opts.get('bookmark'):
3965 if opts.get('bookmark'):
3971 if not revs:
3966 if not revs:
3972 revs = []
3967 revs = []
3973 # The list of bookmark used here is not the one used to actually
3968 # The list of bookmark used here is not the one used to actually
3974 # update the bookmark name. This can result in the revision pulled
3969 # update the bookmark name. This can result in the revision pulled
3975 # not ending up with the name of the bookmark because of a race
3970 # not ending up with the name of the bookmark because of a race
3976 # condition on the server. (See issue 4689 for details)
3971 # condition on the server. (See issue 4689 for details)
3977 remotebookmarks = other.listkeys('bookmarks')
3972 remotebookmarks = other.listkeys('bookmarks')
3978 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3973 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
3979 pullopargs['remotebookmarks'] = remotebookmarks
3974 pullopargs['remotebookmarks'] = remotebookmarks
3980 for b in opts['bookmark']:
3975 for b in opts['bookmark']:
3981 b = repo._bookmarks.expandname(b)
3976 b = repo._bookmarks.expandname(b)
3982 if b not in remotebookmarks:
3977 if b not in remotebookmarks:
3983 raise error.Abort(_('remote bookmark %s not found!') % b)
3978 raise error.Abort(_('remote bookmark %s not found!') % b)
3984 revs.append(hex(remotebookmarks[b]))
3979 revs.append(hex(remotebookmarks[b]))
3985
3980
3986 if revs:
3981 if revs:
3987 try:
3982 try:
3988 # When 'rev' is a bookmark name, we cannot guarantee that it
3983 # When 'rev' is a bookmark name, we cannot guarantee that it
3989 # will be updated with that name because of a race condition
3984 # will be updated with that name because of a race condition
3990 # server side. (See issue 4689 for details)
3985 # server side. (See issue 4689 for details)
3991 oldrevs = revs
3986 oldrevs = revs
3992 revs = [] # actually, nodes
3987 revs = [] # actually, nodes
3993 for r in oldrevs:
3988 for r in oldrevs:
3994 node = other.lookup(r)
3989 node = other.lookup(r)
3995 revs.append(node)
3990 revs.append(node)
3996 if r == checkout:
3991 if r == checkout:
3997 checkout = node
3992 checkout = node
3998 except error.CapabilityError:
3993 except error.CapabilityError:
3999 err = _("other repository doesn't support revision lookup, "
3994 err = _("other repository doesn't support revision lookup, "
4000 "so a rev cannot be specified.")
3995 "so a rev cannot be specified.")
4001 raise error.Abort(err)
3996 raise error.Abort(err)
4002
3997
4003 pullopargs.update(opts.get('opargs', {}))
3998 pullopargs.update(opts.get('opargs', {}))
4004 modheads = exchange.pull(repo, other, heads=revs,
3999 modheads = exchange.pull(repo, other, heads=revs,
4005 force=opts.get('force'),
4000 force=opts.get('force'),
4006 bookmarks=opts.get('bookmark', ()),
4001 bookmarks=opts.get('bookmark', ()),
4007 opargs=pullopargs).cgresult
4002 opargs=pullopargs).cgresult
4008
4003
4009 # brev is a name, which might be a bookmark to be activated at
4004 # brev is a name, which might be a bookmark to be activated at
4010 # the end of the update. In other words, it is an explicit
4005 # the end of the update. In other words, it is an explicit
4011 # destination of the update
4006 # destination of the update
4012 brev = None
4007 brev = None
4013
4008
4014 if checkout:
4009 if checkout:
4015 checkout = str(repo.changelog.rev(checkout))
4010 checkout = str(repo.changelog.rev(checkout))
4016
4011
4017 # order below depends on implementation of
4012 # order below depends on implementation of
4018 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4013 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4019 # because 'checkout' is determined without it.
4014 # because 'checkout' is determined without it.
4020 if opts.get('rev'):
4015 if opts.get('rev'):
4021 brev = opts['rev'][0]
4016 brev = opts['rev'][0]
4022 elif opts.get('branch'):
4017 elif opts.get('branch'):
4023 brev = opts['branch'][0]
4018 brev = opts['branch'][0]
4024 else:
4019 else:
4025 brev = branches[0]
4020 brev = branches[0]
4026 repo._subtoppath = source
4021 repo._subtoppath = source
4027 try:
4022 try:
4028 ret = postincoming(ui, repo, modheads, opts.get('update'),
4023 ret = postincoming(ui, repo, modheads, opts.get('update'),
4029 checkout, brev)
4024 checkout, brev)
4030
4025
4031 finally:
4026 finally:
4032 del repo._subtoppath
4027 del repo._subtoppath
4033
4028
4034 finally:
4029 finally:
4035 other.close()
4030 other.close()
4036 return ret
4031 return ret
4037
4032
4038 @command('^push',
4033 @command('^push',
4039 [('f', 'force', None, _('force push')),
4034 [('f', 'force', None, _('force push')),
4040 ('r', 'rev', [],
4035 ('r', 'rev', [],
4041 _('a changeset intended to be included in the destination'),
4036 _('a changeset intended to be included in the destination'),
4042 _('REV')),
4037 _('REV')),
4043 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4038 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4044 ('b', 'branch', [],
4039 ('b', 'branch', [],
4045 _('a specific branch you would like to push'), _('BRANCH')),
4040 _('a specific branch you would like to push'), _('BRANCH')),
4046 ('', 'new-branch', False, _('allow pushing a new branch')),
4041 ('', 'new-branch', False, _('allow pushing a new branch')),
4047 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4042 ('', 'pushvars', [], _('variables that can be sent to server (ADVANCED)')),
4048 ] + remoteopts,
4043 ] + remoteopts,
4049 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4044 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4050 def push(ui, repo, dest=None, **opts):
4045 def push(ui, repo, dest=None, **opts):
4051 """push changes to the specified destination
4046 """push changes to the specified destination
4052
4047
4053 Push changesets from the local repository to the specified
4048 Push changesets from the local repository to the specified
4054 destination.
4049 destination.
4055
4050
4056 This operation is symmetrical to pull: it is identical to a pull
4051 This operation is symmetrical to pull: it is identical to a pull
4057 in the destination repository from the current one.
4052 in the destination repository from the current one.
4058
4053
4059 By default, push will not allow creation of new heads at the
4054 By default, push will not allow creation of new heads at the
4060 destination, since multiple heads would make it unclear which head
4055 destination, since multiple heads would make it unclear which head
4061 to use. In this situation, it is recommended to pull and merge
4056 to use. In this situation, it is recommended to pull and merge
4062 before pushing.
4057 before pushing.
4063
4058
4064 Use --new-branch if you want to allow push to create a new named
4059 Use --new-branch if you want to allow push to create a new named
4065 branch that is not present at the destination. This allows you to
4060 branch that is not present at the destination. This allows you to
4066 only create a new branch without forcing other changes.
4061 only create a new branch without forcing other changes.
4067
4062
4068 .. note::
4063 .. note::
4069
4064
4070 Extra care should be taken with the -f/--force option,
4065 Extra care should be taken with the -f/--force option,
4071 which will push all new heads on all branches, an action which will
4066 which will push all new heads on all branches, an action which will
4072 almost always cause confusion for collaborators.
4067 almost always cause confusion for collaborators.
4073
4068
4074 If -r/--rev is used, the specified revision and all its ancestors
4069 If -r/--rev is used, the specified revision and all its ancestors
4075 will be pushed to the remote repository.
4070 will be pushed to the remote repository.
4076
4071
4077 If -B/--bookmark is used, the specified bookmarked revision, its
4072 If -B/--bookmark is used, the specified bookmarked revision, its
4078 ancestors, and the bookmark will be pushed to the remote
4073 ancestors, and the bookmark will be pushed to the remote
4079 repository. Specifying ``.`` is equivalent to specifying the active
4074 repository. Specifying ``.`` is equivalent to specifying the active
4080 bookmark's name.
4075 bookmark's name.
4081
4076
4082 Please see :hg:`help urls` for important details about ``ssh://``
4077 Please see :hg:`help urls` for important details about ``ssh://``
4083 URLs. If DESTINATION is omitted, a default path will be used.
4078 URLs. If DESTINATION is omitted, a default path will be used.
4084
4079
4085 .. container:: verbose
4080 .. container:: verbose
4086
4081
4087 The --pushvars option sends strings to the server that become
4082 The --pushvars option sends strings to the server that become
4088 environment variables prepended with ``HG_USERVAR_``. For example,
4083 environment variables prepended with ``HG_USERVAR_``. For example,
4089 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4084 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
4090 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4085 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
4091
4086
4092 pushvars can provide for user-overridable hooks as well as set debug
4087 pushvars can provide for user-overridable hooks as well as set debug
4093 levels. One example is having a hook that blocks commits containing
4088 levels. One example is having a hook that blocks commits containing
4094 conflict markers, but enables the user to override the hook if the file
4089 conflict markers, but enables the user to override the hook if the file
4095 is using conflict markers for testing purposes or the file format has
4090 is using conflict markers for testing purposes or the file format has
4096 strings that look like conflict markers.
4091 strings that look like conflict markers.
4097
4092
4098 By default, servers will ignore `--pushvars`. To enable it add the
4093 By default, servers will ignore `--pushvars`. To enable it add the
4099 following to your configuration file::
4094 following to your configuration file::
4100
4095
4101 [push]
4096 [push]
4102 pushvars.server = true
4097 pushvars.server = true
4103
4098
4104 Returns 0 if push was successful, 1 if nothing to push.
4099 Returns 0 if push was successful, 1 if nothing to push.
4105 """
4100 """
4106
4101
4107 opts = pycompat.byteskwargs(opts)
4102 opts = pycompat.byteskwargs(opts)
4108 if opts.get('bookmark'):
4103 if opts.get('bookmark'):
4109 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4104 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4110 for b in opts['bookmark']:
4105 for b in opts['bookmark']:
4111 # translate -B options to -r so changesets get pushed
4106 # translate -B options to -r so changesets get pushed
4112 b = repo._bookmarks.expandname(b)
4107 b = repo._bookmarks.expandname(b)
4113 if b in repo._bookmarks:
4108 if b in repo._bookmarks:
4114 opts.setdefault('rev', []).append(b)
4109 opts.setdefault('rev', []).append(b)
4115 else:
4110 else:
4116 # if we try to push a deleted bookmark, translate it to null
4111 # if we try to push a deleted bookmark, translate it to null
4117 # this lets simultaneous -r, -b options continue working
4112 # this lets simultaneous -r, -b options continue working
4118 opts.setdefault('rev', []).append("null")
4113 opts.setdefault('rev', []).append("null")
4119
4114
4120 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4115 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4121 if not path:
4116 if not path:
4122 raise error.Abort(_('default repository not configured!'),
4117 raise error.Abort(_('default repository not configured!'),
4123 hint=_("see 'hg help config.paths'"))
4118 hint=_("see 'hg help config.paths'"))
4124 dest = path.pushloc or path.loc
4119 dest = path.pushloc or path.loc
4125 branches = (path.branch, opts.get('branch') or [])
4120 branches = (path.branch, opts.get('branch') or [])
4126 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4121 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4127 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4122 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4128 other = hg.peer(repo, opts, dest)
4123 other = hg.peer(repo, opts, dest)
4129
4124
4130 if revs:
4125 if revs:
4131 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4126 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4132 if not revs:
4127 if not revs:
4133 raise error.Abort(_("specified revisions evaluate to an empty set"),
4128 raise error.Abort(_("specified revisions evaluate to an empty set"),
4134 hint=_("use different revision arguments"))
4129 hint=_("use different revision arguments"))
4135 elif path.pushrev:
4130 elif path.pushrev:
4136 # It doesn't make any sense to specify ancestor revisions. So limit
4131 # It doesn't make any sense to specify ancestor revisions. So limit
4137 # to DAG heads to make discovery simpler.
4132 # to DAG heads to make discovery simpler.
4138 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4133 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4139 revs = scmutil.revrange(repo, [expr])
4134 revs = scmutil.revrange(repo, [expr])
4140 revs = [repo[rev].node() for rev in revs]
4135 revs = [repo[rev].node() for rev in revs]
4141 if not revs:
4136 if not revs:
4142 raise error.Abort(_('default push revset for path evaluates to an '
4137 raise error.Abort(_('default push revset for path evaluates to an '
4143 'empty set'))
4138 'empty set'))
4144
4139
4145 repo._subtoppath = dest
4140 repo._subtoppath = dest
4146 try:
4141 try:
4147 # push subrepos depth-first for coherent ordering
4142 # push subrepos depth-first for coherent ordering
4148 c = repo['']
4143 c = repo['']
4149 subs = c.substate # only repos that are committed
4144 subs = c.substate # only repos that are committed
4150 for s in sorted(subs):
4145 for s in sorted(subs):
4151 result = c.sub(s).push(opts)
4146 result = c.sub(s).push(opts)
4152 if result == 0:
4147 if result == 0:
4153 return not result
4148 return not result
4154 finally:
4149 finally:
4155 del repo._subtoppath
4150 del repo._subtoppath
4156
4151
4157 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4152 opargs = dict(opts.get('opargs', {})) # copy opargs since we may mutate it
4158 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4153 opargs.setdefault('pushvars', []).extend(opts.get('pushvars', []))
4159
4154
4160 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4155 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4161 newbranch=opts.get('new_branch'),
4156 newbranch=opts.get('new_branch'),
4162 bookmarks=opts.get('bookmark', ()),
4157 bookmarks=opts.get('bookmark', ()),
4163 opargs=opargs)
4158 opargs=opargs)
4164
4159
4165 result = not pushop.cgresult
4160 result = not pushop.cgresult
4166
4161
4167 if pushop.bkresult is not None:
4162 if pushop.bkresult is not None:
4168 if pushop.bkresult == 2:
4163 if pushop.bkresult == 2:
4169 result = 2
4164 result = 2
4170 elif not result and pushop.bkresult:
4165 elif not result and pushop.bkresult:
4171 result = 2
4166 result = 2
4172
4167
4173 return result
4168 return result
4174
4169
4175 @command('recover', [])
4170 @command('recover', [])
4176 def recover(ui, repo):
4171 def recover(ui, repo):
4177 """roll back an interrupted transaction
4172 """roll back an interrupted transaction
4178
4173
4179 Recover from an interrupted commit or pull.
4174 Recover from an interrupted commit or pull.
4180
4175
4181 This command tries to fix the repository status after an
4176 This command tries to fix the repository status after an
4182 interrupted operation. It should only be necessary when Mercurial
4177 interrupted operation. It should only be necessary when Mercurial
4183 suggests it.
4178 suggests it.
4184
4179
4185 Returns 0 if successful, 1 if nothing to recover or verify fails.
4180 Returns 0 if successful, 1 if nothing to recover or verify fails.
4186 """
4181 """
4187 if repo.recover():
4182 if repo.recover():
4188 return hg.verify(repo)
4183 return hg.verify(repo)
4189 return 1
4184 return 1
4190
4185
4191 @command('^remove|rm',
4186 @command('^remove|rm',
4192 [('A', 'after', None, _('record delete for missing files')),
4187 [('A', 'after', None, _('record delete for missing files')),
4193 ('f', 'force', None,
4188 ('f', 'force', None,
4194 _('forget added files, delete modified files')),
4189 _('forget added files, delete modified files')),
4195 ] + subrepoopts + walkopts,
4190 ] + subrepoopts + walkopts,
4196 _('[OPTION]... FILE...'),
4191 _('[OPTION]... FILE...'),
4197 inferrepo=True)
4192 inferrepo=True)
4198 def remove(ui, repo, *pats, **opts):
4193 def remove(ui, repo, *pats, **opts):
4199 """remove the specified files on the next commit
4194 """remove the specified files on the next commit
4200
4195
4201 Schedule the indicated files for removal from the current branch.
4196 Schedule the indicated files for removal from the current branch.
4202
4197
4203 This command schedules the files to be removed at the next commit.
4198 This command schedules the files to be removed at the next commit.
4204 To undo a remove before that, see :hg:`revert`. To undo added
4199 To undo a remove before that, see :hg:`revert`. To undo added
4205 files, see :hg:`forget`.
4200 files, see :hg:`forget`.
4206
4201
4207 .. container:: verbose
4202 .. container:: verbose
4208
4203
4209 -A/--after can be used to remove only files that have already
4204 -A/--after can be used to remove only files that have already
4210 been deleted, -f/--force can be used to force deletion, and -Af
4205 been deleted, -f/--force can be used to force deletion, and -Af
4211 can be used to remove files from the next revision without
4206 can be used to remove files from the next revision without
4212 deleting them from the working directory.
4207 deleting them from the working directory.
4213
4208
4214 The following table details the behavior of remove for different
4209 The following table details the behavior of remove for different
4215 file states (columns) and option combinations (rows). The file
4210 file states (columns) and option combinations (rows). The file
4216 states are Added [A], Clean [C], Modified [M] and Missing [!]
4211 states are Added [A], Clean [C], Modified [M] and Missing [!]
4217 (as reported by :hg:`status`). The actions are Warn, Remove
4212 (as reported by :hg:`status`). The actions are Warn, Remove
4218 (from branch) and Delete (from disk):
4213 (from branch) and Delete (from disk):
4219
4214
4220 ========= == == == ==
4215 ========= == == == ==
4221 opt/state A C M !
4216 opt/state A C M !
4222 ========= == == == ==
4217 ========= == == == ==
4223 none W RD W R
4218 none W RD W R
4224 -f R RD RD R
4219 -f R RD RD R
4225 -A W W W R
4220 -A W W W R
4226 -Af R R R R
4221 -Af R R R R
4227 ========= == == == ==
4222 ========= == == == ==
4228
4223
4229 .. note::
4224 .. note::
4230
4225
4231 :hg:`remove` never deletes files in Added [A] state from the
4226 :hg:`remove` never deletes files in Added [A] state from the
4232 working directory, not even if ``--force`` is specified.
4227 working directory, not even if ``--force`` is specified.
4233
4228
4234 Returns 0 on success, 1 if any warnings encountered.
4229 Returns 0 on success, 1 if any warnings encountered.
4235 """
4230 """
4236
4231
4237 opts = pycompat.byteskwargs(opts)
4232 opts = pycompat.byteskwargs(opts)
4238 after, force = opts.get('after'), opts.get('force')
4233 after, force = opts.get('after'), opts.get('force')
4239 if not pats and not after:
4234 if not pats and not after:
4240 raise error.Abort(_('no files specified'))
4235 raise error.Abort(_('no files specified'))
4241
4236
4242 m = scmutil.match(repo[None], pats, opts)
4237 m = scmutil.match(repo[None], pats, opts)
4243 subrepos = opts.get('subrepos')
4238 subrepos = opts.get('subrepos')
4244 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4239 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4245
4240
4246 @command('rename|move|mv',
4241 @command('rename|move|mv',
4247 [('A', 'after', None, _('record a rename that has already occurred')),
4242 [('A', 'after', None, _('record a rename that has already occurred')),
4248 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4243 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4249 ] + walkopts + dryrunopts,
4244 ] + walkopts + dryrunopts,
4250 _('[OPTION]... SOURCE... DEST'))
4245 _('[OPTION]... SOURCE... DEST'))
4251 def rename(ui, repo, *pats, **opts):
4246 def rename(ui, repo, *pats, **opts):
4252 """rename files; equivalent of copy + remove
4247 """rename files; equivalent of copy + remove
4253
4248
4254 Mark dest as copies of sources; mark sources for deletion. If dest
4249 Mark dest as copies of sources; mark sources for deletion. If dest
4255 is a directory, copies are put in that directory. If dest is a
4250 is a directory, copies are put in that directory. If dest is a
4256 file, there can only be one source.
4251 file, there can only be one source.
4257
4252
4258 By default, this command copies the contents of files as they
4253 By default, this command copies the contents of files as they
4259 exist in the working directory. If invoked with -A/--after, the
4254 exist in the working directory. If invoked with -A/--after, the
4260 operation is recorded, but no copying is performed.
4255 operation is recorded, but no copying is performed.
4261
4256
4262 This command takes effect at the next commit. To undo a rename
4257 This command takes effect at the next commit. To undo a rename
4263 before that, see :hg:`revert`.
4258 before that, see :hg:`revert`.
4264
4259
4265 Returns 0 on success, 1 if errors are encountered.
4260 Returns 0 on success, 1 if errors are encountered.
4266 """
4261 """
4267 opts = pycompat.byteskwargs(opts)
4262 opts = pycompat.byteskwargs(opts)
4268 with repo.wlock(False):
4263 with repo.wlock(False):
4269 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4264 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4270
4265
4271 @command('resolve',
4266 @command('resolve',
4272 [('a', 'all', None, _('select all unresolved files')),
4267 [('a', 'all', None, _('select all unresolved files')),
4273 ('l', 'list', None, _('list state of files needing merge')),
4268 ('l', 'list', None, _('list state of files needing merge')),
4274 ('m', 'mark', None, _('mark files as resolved')),
4269 ('m', 'mark', None, _('mark files as resolved')),
4275 ('u', 'unmark', None, _('mark files as unresolved')),
4270 ('u', 'unmark', None, _('mark files as unresolved')),
4276 ('n', 'no-status', None, _('hide status prefix'))]
4271 ('n', 'no-status', None, _('hide status prefix'))]
4277 + mergetoolopts + walkopts + formatteropts,
4272 + mergetoolopts + walkopts + formatteropts,
4278 _('[OPTION]... [FILE]...'),
4273 _('[OPTION]... [FILE]...'),
4279 inferrepo=True)
4274 inferrepo=True)
4280 def resolve(ui, repo, *pats, **opts):
4275 def resolve(ui, repo, *pats, **opts):
4281 """redo merges or set/view the merge status of files
4276 """redo merges or set/view the merge status of files
4282
4277
4283 Merges with unresolved conflicts are often the result of
4278 Merges with unresolved conflicts are often the result of
4284 non-interactive merging using the ``internal:merge`` configuration
4279 non-interactive merging using the ``internal:merge`` configuration
4285 setting, or a command-line merge tool like ``diff3``. The resolve
4280 setting, or a command-line merge tool like ``diff3``. The resolve
4286 command is used to manage the files involved in a merge, after
4281 command is used to manage the files involved in a merge, after
4287 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4282 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4288 working directory must have two parents). See :hg:`help
4283 working directory must have two parents). See :hg:`help
4289 merge-tools` for information on configuring merge tools.
4284 merge-tools` for information on configuring merge tools.
4290
4285
4291 The resolve command can be used in the following ways:
4286 The resolve command can be used in the following ways:
4292
4287
4293 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4288 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4294 files, discarding any previous merge attempts. Re-merging is not
4289 files, discarding any previous merge attempts. Re-merging is not
4295 performed for files already marked as resolved. Use ``--all/-a``
4290 performed for files already marked as resolved. Use ``--all/-a``
4296 to select all unresolved files. ``--tool`` can be used to specify
4291 to select all unresolved files. ``--tool`` can be used to specify
4297 the merge tool used for the given files. It overrides the HGMERGE
4292 the merge tool used for the given files. It overrides the HGMERGE
4298 environment variable and your configuration files. Previous file
4293 environment variable and your configuration files. Previous file
4299 contents are saved with a ``.orig`` suffix.
4294 contents are saved with a ``.orig`` suffix.
4300
4295
4301 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4296 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4302 (e.g. after having manually fixed-up the files). The default is
4297 (e.g. after having manually fixed-up the files). The default is
4303 to mark all unresolved files.
4298 to mark all unresolved files.
4304
4299
4305 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4300 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4306 default is to mark all resolved files.
4301 default is to mark all resolved files.
4307
4302
4308 - :hg:`resolve -l`: list files which had or still have conflicts.
4303 - :hg:`resolve -l`: list files which had or still have conflicts.
4309 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4304 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4310 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4305 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4311 the list. See :hg:`help filesets` for details.
4306 the list. See :hg:`help filesets` for details.
4312
4307
4313 .. note::
4308 .. note::
4314
4309
4315 Mercurial will not let you commit files with unresolved merge
4310 Mercurial will not let you commit files with unresolved merge
4316 conflicts. You must use :hg:`resolve -m ...` before you can
4311 conflicts. You must use :hg:`resolve -m ...` before you can
4317 commit after a conflicting merge.
4312 commit after a conflicting merge.
4318
4313
4319 Returns 0 on success, 1 if any files fail a resolve attempt.
4314 Returns 0 on success, 1 if any files fail a resolve attempt.
4320 """
4315 """
4321
4316
4322 opts = pycompat.byteskwargs(opts)
4317 opts = pycompat.byteskwargs(opts)
4323 flaglist = 'all mark unmark list no_status'.split()
4318 flaglist = 'all mark unmark list no_status'.split()
4324 all, mark, unmark, show, nostatus = \
4319 all, mark, unmark, show, nostatus = \
4325 [opts.get(o) for o in flaglist]
4320 [opts.get(o) for o in flaglist]
4326
4321
4327 if (show and (mark or unmark)) or (mark and unmark):
4322 if (show and (mark or unmark)) or (mark and unmark):
4328 raise error.Abort(_("too many options specified"))
4323 raise error.Abort(_("too many options specified"))
4329 if pats and all:
4324 if pats and all:
4330 raise error.Abort(_("can't specify --all and patterns"))
4325 raise error.Abort(_("can't specify --all and patterns"))
4331 if not (all or pats or show or mark or unmark):
4326 if not (all or pats or show or mark or unmark):
4332 raise error.Abort(_('no files or directories specified'),
4327 raise error.Abort(_('no files or directories specified'),
4333 hint=('use --all to re-merge all unresolved files'))
4328 hint=('use --all to re-merge all unresolved files'))
4334
4329
4335 if show:
4330 if show:
4336 ui.pager('resolve')
4331 ui.pager('resolve')
4337 fm = ui.formatter('resolve', opts)
4332 fm = ui.formatter('resolve', opts)
4338 ms = mergemod.mergestate.read(repo)
4333 ms = mergemod.mergestate.read(repo)
4339 m = scmutil.match(repo[None], pats, opts)
4334 m = scmutil.match(repo[None], pats, opts)
4340
4335
4341 # Labels and keys based on merge state. Unresolved path conflicts show
4336 # Labels and keys based on merge state. Unresolved path conflicts show
4342 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4337 # as 'P'. Resolved path conflicts show as 'R', the same as normal
4343 # resolved conflicts.
4338 # resolved conflicts.
4344 mergestateinfo = {
4339 mergestateinfo = {
4345 'u': ('resolve.unresolved', 'U'),
4340 'u': ('resolve.unresolved', 'U'),
4346 'r': ('resolve.resolved', 'R'),
4341 'r': ('resolve.resolved', 'R'),
4347 'pu': ('resolve.unresolved', 'P'),
4342 'pu': ('resolve.unresolved', 'P'),
4348 'pr': ('resolve.resolved', 'R'),
4343 'pr': ('resolve.resolved', 'R'),
4349 'd': ('resolve.driverresolved', 'D'),
4344 'd': ('resolve.driverresolved', 'D'),
4350 }
4345 }
4351
4346
4352 for f in ms:
4347 for f in ms:
4353 if not m(f):
4348 if not m(f):
4354 continue
4349 continue
4355
4350
4356 label, key = mergestateinfo[ms[f]]
4351 label, key = mergestateinfo[ms[f]]
4357 fm.startitem()
4352 fm.startitem()
4358 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4353 fm.condwrite(not nostatus, 'status', '%s ', key, label=label)
4359 fm.write('path', '%s\n', f, label=label)
4354 fm.write('path', '%s\n', f, label=label)
4360 fm.end()
4355 fm.end()
4361 return 0
4356 return 0
4362
4357
4363 with repo.wlock():
4358 with repo.wlock():
4364 ms = mergemod.mergestate.read(repo)
4359 ms = mergemod.mergestate.read(repo)
4365
4360
4366 if not (ms.active() or repo.dirstate.p2() != nullid):
4361 if not (ms.active() or repo.dirstate.p2() != nullid):
4367 raise error.Abort(
4362 raise error.Abort(
4368 _('resolve command not applicable when not merging'))
4363 _('resolve command not applicable when not merging'))
4369
4364
4370 wctx = repo[None]
4365 wctx = repo[None]
4371
4366
4372 if ms.mergedriver and ms.mdstate() == 'u':
4367 if ms.mergedriver and ms.mdstate() == 'u':
4373 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4368 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4374 ms.commit()
4369 ms.commit()
4375 # allow mark and unmark to go through
4370 # allow mark and unmark to go through
4376 if not mark and not unmark and not proceed:
4371 if not mark and not unmark and not proceed:
4377 return 1
4372 return 1
4378
4373
4379 m = scmutil.match(wctx, pats, opts)
4374 m = scmutil.match(wctx, pats, opts)
4380 ret = 0
4375 ret = 0
4381 didwork = False
4376 didwork = False
4382 runconclude = False
4377 runconclude = False
4383
4378
4384 tocomplete = []
4379 tocomplete = []
4385 for f in ms:
4380 for f in ms:
4386 if not m(f):
4381 if not m(f):
4387 continue
4382 continue
4388
4383
4389 didwork = True
4384 didwork = True
4390
4385
4391 # don't let driver-resolved files be marked, and run the conclude
4386 # don't let driver-resolved files be marked, and run the conclude
4392 # step if asked to resolve
4387 # step if asked to resolve
4393 if ms[f] == "d":
4388 if ms[f] == "d":
4394 exact = m.exact(f)
4389 exact = m.exact(f)
4395 if mark:
4390 if mark:
4396 if exact:
4391 if exact:
4397 ui.warn(_('not marking %s as it is driver-resolved\n')
4392 ui.warn(_('not marking %s as it is driver-resolved\n')
4398 % f)
4393 % f)
4399 elif unmark:
4394 elif unmark:
4400 if exact:
4395 if exact:
4401 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4396 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4402 % f)
4397 % f)
4403 else:
4398 else:
4404 runconclude = True
4399 runconclude = True
4405 continue
4400 continue
4406
4401
4407 # path conflicts must be resolved manually
4402 # path conflicts must be resolved manually
4408 if ms[f] in ("pu", "pr"):
4403 if ms[f] in ("pu", "pr"):
4409 if mark:
4404 if mark:
4410 ms.mark(f, "pr")
4405 ms.mark(f, "pr")
4411 elif unmark:
4406 elif unmark:
4412 ms.mark(f, "pu")
4407 ms.mark(f, "pu")
4413 elif ms[f] == "pu":
4408 elif ms[f] == "pu":
4414 ui.warn(_('%s: path conflict must be resolved manually\n')
4409 ui.warn(_('%s: path conflict must be resolved manually\n')
4415 % f)
4410 % f)
4416 continue
4411 continue
4417
4412
4418 if mark:
4413 if mark:
4419 ms.mark(f, "r")
4414 ms.mark(f, "r")
4420 elif unmark:
4415 elif unmark:
4421 ms.mark(f, "u")
4416 ms.mark(f, "u")
4422 else:
4417 else:
4423 # backup pre-resolve (merge uses .orig for its own purposes)
4418 # backup pre-resolve (merge uses .orig for its own purposes)
4424 a = repo.wjoin(f)
4419 a = repo.wjoin(f)
4425 try:
4420 try:
4426 util.copyfile(a, a + ".resolve")
4421 util.copyfile(a, a + ".resolve")
4427 except (IOError, OSError) as inst:
4422 except (IOError, OSError) as inst:
4428 if inst.errno != errno.ENOENT:
4423 if inst.errno != errno.ENOENT:
4429 raise
4424 raise
4430
4425
4431 try:
4426 try:
4432 # preresolve file
4427 # preresolve file
4433 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4428 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4434 'resolve')
4429 'resolve')
4435 complete, r = ms.preresolve(f, wctx)
4430 complete, r = ms.preresolve(f, wctx)
4436 if not complete:
4431 if not complete:
4437 tocomplete.append(f)
4432 tocomplete.append(f)
4438 elif r:
4433 elif r:
4439 ret = 1
4434 ret = 1
4440 finally:
4435 finally:
4441 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4436 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4442 ms.commit()
4437 ms.commit()
4443
4438
4444 # replace filemerge's .orig file with our resolve file, but only
4439 # replace filemerge's .orig file with our resolve file, but only
4445 # for merges that are complete
4440 # for merges that are complete
4446 if complete:
4441 if complete:
4447 try:
4442 try:
4448 util.rename(a + ".resolve",
4443 util.rename(a + ".resolve",
4449 scmutil.origpath(ui, repo, a))
4444 scmutil.origpath(ui, repo, a))
4450 except OSError as inst:
4445 except OSError as inst:
4451 if inst.errno != errno.ENOENT:
4446 if inst.errno != errno.ENOENT:
4452 raise
4447 raise
4453
4448
4454 for f in tocomplete:
4449 for f in tocomplete:
4455 try:
4450 try:
4456 # resolve file
4451 # resolve file
4457 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4452 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4458 'resolve')
4453 'resolve')
4459 r = ms.resolve(f, wctx)
4454 r = ms.resolve(f, wctx)
4460 if r:
4455 if r:
4461 ret = 1
4456 ret = 1
4462 finally:
4457 finally:
4463 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4458 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4464 ms.commit()
4459 ms.commit()
4465
4460
4466 # replace filemerge's .orig file with our resolve file
4461 # replace filemerge's .orig file with our resolve file
4467 a = repo.wjoin(f)
4462 a = repo.wjoin(f)
4468 try:
4463 try:
4469 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4464 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4470 except OSError as inst:
4465 except OSError as inst:
4471 if inst.errno != errno.ENOENT:
4466 if inst.errno != errno.ENOENT:
4472 raise
4467 raise
4473
4468
4474 ms.commit()
4469 ms.commit()
4475 ms.recordactions()
4470 ms.recordactions()
4476
4471
4477 if not didwork and pats:
4472 if not didwork and pats:
4478 hint = None
4473 hint = None
4479 if not any([p for p in pats if p.find(':') >= 0]):
4474 if not any([p for p in pats if p.find(':') >= 0]):
4480 pats = ['path:%s' % p for p in pats]
4475 pats = ['path:%s' % p for p in pats]
4481 m = scmutil.match(wctx, pats, opts)
4476 m = scmutil.match(wctx, pats, opts)
4482 for f in ms:
4477 for f in ms:
4483 if not m(f):
4478 if not m(f):
4484 continue
4479 continue
4485 flags = ''.join(['-%s ' % o[0] for o in flaglist
4480 flags = ''.join(['-%s ' % o[0] for o in flaglist
4486 if opts.get(o)])
4481 if opts.get(o)])
4487 hint = _("(try: hg resolve %s%s)\n") % (
4482 hint = _("(try: hg resolve %s%s)\n") % (
4488 flags,
4483 flags,
4489 ' '.join(pats))
4484 ' '.join(pats))
4490 break
4485 break
4491 ui.warn(_("arguments do not match paths that need resolving\n"))
4486 ui.warn(_("arguments do not match paths that need resolving\n"))
4492 if hint:
4487 if hint:
4493 ui.warn(hint)
4488 ui.warn(hint)
4494 elif ms.mergedriver and ms.mdstate() != 's':
4489 elif ms.mergedriver and ms.mdstate() != 's':
4495 # run conclude step when either a driver-resolved file is requested
4490 # run conclude step when either a driver-resolved file is requested
4496 # or there are no driver-resolved files
4491 # or there are no driver-resolved files
4497 # we can't use 'ret' to determine whether any files are unresolved
4492 # we can't use 'ret' to determine whether any files are unresolved
4498 # because we might not have tried to resolve some
4493 # because we might not have tried to resolve some
4499 if ((runconclude or not list(ms.driverresolved()))
4494 if ((runconclude or not list(ms.driverresolved()))
4500 and not list(ms.unresolved())):
4495 and not list(ms.unresolved())):
4501 proceed = mergemod.driverconclude(repo, ms, wctx)
4496 proceed = mergemod.driverconclude(repo, ms, wctx)
4502 ms.commit()
4497 ms.commit()
4503 if not proceed:
4498 if not proceed:
4504 return 1
4499 return 1
4505
4500
4506 # Nudge users into finishing an unfinished operation
4501 # Nudge users into finishing an unfinished operation
4507 unresolvedf = list(ms.unresolved())
4502 unresolvedf = list(ms.unresolved())
4508 driverresolvedf = list(ms.driverresolved())
4503 driverresolvedf = list(ms.driverresolved())
4509 if not unresolvedf and not driverresolvedf:
4504 if not unresolvedf and not driverresolvedf:
4510 ui.status(_('(no more unresolved files)\n'))
4505 ui.status(_('(no more unresolved files)\n'))
4511 cmdutil.checkafterresolved(repo)
4506 cmdutil.checkafterresolved(repo)
4512 elif not unresolvedf:
4507 elif not unresolvedf:
4513 ui.status(_('(no more unresolved files -- '
4508 ui.status(_('(no more unresolved files -- '
4514 'run "hg resolve --all" to conclude)\n'))
4509 'run "hg resolve --all" to conclude)\n'))
4515
4510
4516 return ret
4511 return ret
4517
4512
4518 @command('revert',
4513 @command('revert',
4519 [('a', 'all', None, _('revert all changes when no arguments given')),
4514 [('a', 'all', None, _('revert all changes when no arguments given')),
4520 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4515 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4521 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4516 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4522 ('C', 'no-backup', None, _('do not save backup copies of files')),
4517 ('C', 'no-backup', None, _('do not save backup copies of files')),
4523 ('i', 'interactive', None, _('interactively select the changes')),
4518 ('i', 'interactive', None, _('interactively select the changes')),
4524 ] + walkopts + dryrunopts,
4519 ] + walkopts + dryrunopts,
4525 _('[OPTION]... [-r REV] [NAME]...'))
4520 _('[OPTION]... [-r REV] [NAME]...'))
4526 def revert(ui, repo, *pats, **opts):
4521 def revert(ui, repo, *pats, **opts):
4527 """restore files to their checkout state
4522 """restore files to their checkout state
4528
4523
4529 .. note::
4524 .. note::
4530
4525
4531 To check out earlier revisions, you should use :hg:`update REV`.
4526 To check out earlier revisions, you should use :hg:`update REV`.
4532 To cancel an uncommitted merge (and lose your changes),
4527 To cancel an uncommitted merge (and lose your changes),
4533 use :hg:`update --clean .`.
4528 use :hg:`update --clean .`.
4534
4529
4535 With no revision specified, revert the specified files or directories
4530 With no revision specified, revert the specified files or directories
4536 to the contents they had in the parent of the working directory.
4531 to the contents they had in the parent of the working directory.
4537 This restores the contents of files to an unmodified
4532 This restores the contents of files to an unmodified
4538 state and unschedules adds, removes, copies, and renames. If the
4533 state and unschedules adds, removes, copies, and renames. If the
4539 working directory has two parents, you must explicitly specify a
4534 working directory has two parents, you must explicitly specify a
4540 revision.
4535 revision.
4541
4536
4542 Using the -r/--rev or -d/--date options, revert the given files or
4537 Using the -r/--rev or -d/--date options, revert the given files or
4543 directories to their states as of a specific revision. Because
4538 directories to their states as of a specific revision. Because
4544 revert does not change the working directory parents, this will
4539 revert does not change the working directory parents, this will
4545 cause these files to appear modified. This can be helpful to "back
4540 cause these files to appear modified. This can be helpful to "back
4546 out" some or all of an earlier change. See :hg:`backout` for a
4541 out" some or all of an earlier change. See :hg:`backout` for a
4547 related method.
4542 related method.
4548
4543
4549 Modified files are saved with a .orig suffix before reverting.
4544 Modified files are saved with a .orig suffix before reverting.
4550 To disable these backups, use --no-backup. It is possible to store
4545 To disable these backups, use --no-backup. It is possible to store
4551 the backup files in a custom directory relative to the root of the
4546 the backup files in a custom directory relative to the root of the
4552 repository by setting the ``ui.origbackuppath`` configuration
4547 repository by setting the ``ui.origbackuppath`` configuration
4553 option.
4548 option.
4554
4549
4555 See :hg:`help dates` for a list of formats valid for -d/--date.
4550 See :hg:`help dates` for a list of formats valid for -d/--date.
4556
4551
4557 See :hg:`help backout` for a way to reverse the effect of an
4552 See :hg:`help backout` for a way to reverse the effect of an
4558 earlier changeset.
4553 earlier changeset.
4559
4554
4560 Returns 0 on success.
4555 Returns 0 on success.
4561 """
4556 """
4562
4557
4563 opts = pycompat.byteskwargs(opts)
4558 opts = pycompat.byteskwargs(opts)
4564 if opts.get("date"):
4559 if opts.get("date"):
4565 if opts.get("rev"):
4560 if opts.get("rev"):
4566 raise error.Abort(_("you can't specify a revision and a date"))
4561 raise error.Abort(_("you can't specify a revision and a date"))
4567 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4562 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4568
4563
4569 parent, p2 = repo.dirstate.parents()
4564 parent, p2 = repo.dirstate.parents()
4570 if not opts.get('rev') and p2 != nullid:
4565 if not opts.get('rev') and p2 != nullid:
4571 # revert after merge is a trap for new users (issue2915)
4566 # revert after merge is a trap for new users (issue2915)
4572 raise error.Abort(_('uncommitted merge with no revision specified'),
4567 raise error.Abort(_('uncommitted merge with no revision specified'),
4573 hint=_("use 'hg update' or see 'hg help revert'"))
4568 hint=_("use 'hg update' or see 'hg help revert'"))
4574
4569
4575 ctx = scmutil.revsingle(repo, opts.get('rev'))
4570 ctx = scmutil.revsingle(repo, opts.get('rev'))
4576
4571
4577 if (not (pats or opts.get('include') or opts.get('exclude') or
4572 if (not (pats or opts.get('include') or opts.get('exclude') or
4578 opts.get('all') or opts.get('interactive'))):
4573 opts.get('all') or opts.get('interactive'))):
4579 msg = _("no files or directories specified")
4574 msg = _("no files or directories specified")
4580 if p2 != nullid:
4575 if p2 != nullid:
4581 hint = _("uncommitted merge, use --all to discard all changes,"
4576 hint = _("uncommitted merge, use --all to discard all changes,"
4582 " or 'hg update -C .' to abort the merge")
4577 " or 'hg update -C .' to abort the merge")
4583 raise error.Abort(msg, hint=hint)
4578 raise error.Abort(msg, hint=hint)
4584 dirty = any(repo.status())
4579 dirty = any(repo.status())
4585 node = ctx.node()
4580 node = ctx.node()
4586 if node != parent:
4581 if node != parent:
4587 if dirty:
4582 if dirty:
4588 hint = _("uncommitted changes, use --all to discard all"
4583 hint = _("uncommitted changes, use --all to discard all"
4589 " changes, or 'hg update %s' to update") % ctx.rev()
4584 " changes, or 'hg update %s' to update") % ctx.rev()
4590 else:
4585 else:
4591 hint = _("use --all to revert all files,"
4586 hint = _("use --all to revert all files,"
4592 " or 'hg update %s' to update") % ctx.rev()
4587 " or 'hg update %s' to update") % ctx.rev()
4593 elif dirty:
4588 elif dirty:
4594 hint = _("uncommitted changes, use --all to discard all changes")
4589 hint = _("uncommitted changes, use --all to discard all changes")
4595 else:
4590 else:
4596 hint = _("use --all to revert all files")
4591 hint = _("use --all to revert all files")
4597 raise error.Abort(msg, hint=hint)
4592 raise error.Abort(msg, hint=hint)
4598
4593
4599 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4594 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats,
4600 **pycompat.strkwargs(opts))
4595 **pycompat.strkwargs(opts))
4601
4596
4602 @command('rollback', dryrunopts +
4597 @command('rollback', dryrunopts +
4603 [('f', 'force', False, _('ignore safety measures'))])
4598 [('f', 'force', False, _('ignore safety measures'))])
4604 def rollback(ui, repo, **opts):
4599 def rollback(ui, repo, **opts):
4605 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4600 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4606
4601
4607 Please use :hg:`commit --amend` instead of rollback to correct
4602 Please use :hg:`commit --amend` instead of rollback to correct
4608 mistakes in the last commit.
4603 mistakes in the last commit.
4609
4604
4610 This command should be used with care. There is only one level of
4605 This command should be used with care. There is only one level of
4611 rollback, and there is no way to undo a rollback. It will also
4606 rollback, and there is no way to undo a rollback. It will also
4612 restore the dirstate at the time of the last transaction, losing
4607 restore the dirstate at the time of the last transaction, losing
4613 any dirstate changes since that time. This command does not alter
4608 any dirstate changes since that time. This command does not alter
4614 the working directory.
4609 the working directory.
4615
4610
4616 Transactions are used to encapsulate the effects of all commands
4611 Transactions are used to encapsulate the effects of all commands
4617 that create new changesets or propagate existing changesets into a
4612 that create new changesets or propagate existing changesets into a
4618 repository.
4613 repository.
4619
4614
4620 .. container:: verbose
4615 .. container:: verbose
4621
4616
4622 For example, the following commands are transactional, and their
4617 For example, the following commands are transactional, and their
4623 effects can be rolled back:
4618 effects can be rolled back:
4624
4619
4625 - commit
4620 - commit
4626 - import
4621 - import
4627 - pull
4622 - pull
4628 - push (with this repository as the destination)
4623 - push (with this repository as the destination)
4629 - unbundle
4624 - unbundle
4630
4625
4631 To avoid permanent data loss, rollback will refuse to rollback a
4626 To avoid permanent data loss, rollback will refuse to rollback a
4632 commit transaction if it isn't checked out. Use --force to
4627 commit transaction if it isn't checked out. Use --force to
4633 override this protection.
4628 override this protection.
4634
4629
4635 The rollback command can be entirely disabled by setting the
4630 The rollback command can be entirely disabled by setting the
4636 ``ui.rollback`` configuration setting to false. If you're here
4631 ``ui.rollback`` configuration setting to false. If you're here
4637 because you want to use rollback and it's disabled, you can
4632 because you want to use rollback and it's disabled, you can
4638 re-enable the command by setting ``ui.rollback`` to true.
4633 re-enable the command by setting ``ui.rollback`` to true.
4639
4634
4640 This command is not intended for use on public repositories. Once
4635 This command is not intended for use on public repositories. Once
4641 changes are visible for pull by other users, rolling a transaction
4636 changes are visible for pull by other users, rolling a transaction
4642 back locally is ineffective (someone else may already have pulled
4637 back locally is ineffective (someone else may already have pulled
4643 the changes). Furthermore, a race is possible with readers of the
4638 the changes). Furthermore, a race is possible with readers of the
4644 repository; for example an in-progress pull from the repository
4639 repository; for example an in-progress pull from the repository
4645 may fail if a rollback is performed.
4640 may fail if a rollback is performed.
4646
4641
4647 Returns 0 on success, 1 if no rollback data is available.
4642 Returns 0 on success, 1 if no rollback data is available.
4648 """
4643 """
4649 if not ui.configbool('ui', 'rollback'):
4644 if not ui.configbool('ui', 'rollback'):
4650 raise error.Abort(_('rollback is disabled because it is unsafe'),
4645 raise error.Abort(_('rollback is disabled because it is unsafe'),
4651 hint=('see `hg help -v rollback` for information'))
4646 hint=('see `hg help -v rollback` for information'))
4652 return repo.rollback(dryrun=opts.get(r'dry_run'),
4647 return repo.rollback(dryrun=opts.get(r'dry_run'),
4653 force=opts.get(r'force'))
4648 force=opts.get(r'force'))
4654
4649
4655 @command('root', [], cmdtype=readonly)
4650 @command('root', [], cmdtype=readonly)
4656 def root(ui, repo):
4651 def root(ui, repo):
4657 """print the root (top) of the current working directory
4652 """print the root (top) of the current working directory
4658
4653
4659 Print the root directory of the current repository.
4654 Print the root directory of the current repository.
4660
4655
4661 Returns 0 on success.
4656 Returns 0 on success.
4662 """
4657 """
4663 ui.write(repo.root + "\n")
4658 ui.write(repo.root + "\n")
4664
4659
4665 @command('^serve',
4660 @command('^serve',
4666 [('A', 'accesslog', '', _('name of access log file to write to'),
4661 [('A', 'accesslog', '', _('name of access log file to write to'),
4667 _('FILE')),
4662 _('FILE')),
4668 ('d', 'daemon', None, _('run server in background')),
4663 ('d', 'daemon', None, _('run server in background')),
4669 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4664 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4670 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4665 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4671 # use string type, then we can check if something was passed
4666 # use string type, then we can check if something was passed
4672 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4667 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4673 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4668 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4674 _('ADDR')),
4669 _('ADDR')),
4675 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4670 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4676 _('PREFIX')),
4671 _('PREFIX')),
4677 ('n', 'name', '',
4672 ('n', 'name', '',
4678 _('name to show in web pages (default: working directory)'), _('NAME')),
4673 _('name to show in web pages (default: working directory)'), _('NAME')),
4679 ('', 'web-conf', '',
4674 ('', 'web-conf', '',
4680 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4675 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4681 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4676 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4682 _('FILE')),
4677 _('FILE')),
4683 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4678 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4684 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4679 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4685 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4680 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4686 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4681 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4687 ('', 'style', '', _('template style to use'), _('STYLE')),
4682 ('', 'style', '', _('template style to use'), _('STYLE')),
4688 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4683 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4689 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4684 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4690 + subrepoopts,
4685 + subrepoopts,
4691 _('[OPTION]...'),
4686 _('[OPTION]...'),
4692 optionalrepo=True)
4687 optionalrepo=True)
4693 def serve(ui, repo, **opts):
4688 def serve(ui, repo, **opts):
4694 """start stand-alone webserver
4689 """start stand-alone webserver
4695
4690
4696 Start a local HTTP repository browser and pull server. You can use
4691 Start a local HTTP repository browser and pull server. You can use
4697 this for ad-hoc sharing and browsing of repositories. It is
4692 this for ad-hoc sharing and browsing of repositories. It is
4698 recommended to use a real web server to serve a repository for
4693 recommended to use a real web server to serve a repository for
4699 longer periods of time.
4694 longer periods of time.
4700
4695
4701 Please note that the server does not implement access control.
4696 Please note that the server does not implement access control.
4702 This means that, by default, anybody can read from the server and
4697 This means that, by default, anybody can read from the server and
4703 nobody can write to it by default. Set the ``web.allow-push``
4698 nobody can write to it by default. Set the ``web.allow-push``
4704 option to ``*`` to allow everybody to push to the server. You
4699 option to ``*`` to allow everybody to push to the server. You
4705 should use a real web server if you need to authenticate users.
4700 should use a real web server if you need to authenticate users.
4706
4701
4707 By default, the server logs accesses to stdout and errors to
4702 By default, the server logs accesses to stdout and errors to
4708 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4703 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4709 files.
4704 files.
4710
4705
4711 To have the server choose a free port number to listen on, specify
4706 To have the server choose a free port number to listen on, specify
4712 a port number of 0; in this case, the server will print the port
4707 a port number of 0; in this case, the server will print the port
4713 number it uses.
4708 number it uses.
4714
4709
4715 Returns 0 on success.
4710 Returns 0 on success.
4716 """
4711 """
4717
4712
4718 opts = pycompat.byteskwargs(opts)
4713 opts = pycompat.byteskwargs(opts)
4719 if opts["stdio"] and opts["cmdserver"]:
4714 if opts["stdio"] and opts["cmdserver"]:
4720 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4715 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4721
4716
4722 if opts["stdio"]:
4717 if opts["stdio"]:
4723 if repo is None:
4718 if repo is None:
4724 raise error.RepoError(_("there is no Mercurial repository here"
4719 raise error.RepoError(_("there is no Mercurial repository here"
4725 " (.hg not found)"))
4720 " (.hg not found)"))
4726 s = sshserver.sshserver(ui, repo)
4721 s = sshserver.sshserver(ui, repo)
4727 s.serve_forever()
4722 s.serve_forever()
4728
4723
4729 service = server.createservice(ui, repo, opts)
4724 service = server.createservice(ui, repo, opts)
4730 return server.runservice(opts, initfn=service.init, runfn=service.run)
4725 return server.runservice(opts, initfn=service.init, runfn=service.run)
4731
4726
4732 @command('^status|st',
4727 @command('^status|st',
4733 [('A', 'all', None, _('show status of all files')),
4728 [('A', 'all', None, _('show status of all files')),
4734 ('m', 'modified', None, _('show only modified files')),
4729 ('m', 'modified', None, _('show only modified files')),
4735 ('a', 'added', None, _('show only added files')),
4730 ('a', 'added', None, _('show only added files')),
4736 ('r', 'removed', None, _('show only removed files')),
4731 ('r', 'removed', None, _('show only removed files')),
4737 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4732 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4738 ('c', 'clean', None, _('show only files without changes')),
4733 ('c', 'clean', None, _('show only files without changes')),
4739 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4734 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4740 ('i', 'ignored', None, _('show only ignored files')),
4735 ('i', 'ignored', None, _('show only ignored files')),
4741 ('n', 'no-status', None, _('hide status prefix')),
4736 ('n', 'no-status', None, _('hide status prefix')),
4742 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4737 ('t', 'terse', '', _('show the terse output (EXPERIMENTAL)')),
4743 ('C', 'copies', None, _('show source of copied files')),
4738 ('C', 'copies', None, _('show source of copied files')),
4744 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4739 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4745 ('', 'rev', [], _('show difference from revision'), _('REV')),
4740 ('', 'rev', [], _('show difference from revision'), _('REV')),
4746 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4741 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4747 ] + walkopts + subrepoopts + formatteropts,
4742 ] + walkopts + subrepoopts + formatteropts,
4748 _('[OPTION]... [FILE]...'),
4743 _('[OPTION]... [FILE]...'),
4749 inferrepo=True, cmdtype=readonly)
4744 inferrepo=True, cmdtype=readonly)
4750 def status(ui, repo, *pats, **opts):
4745 def status(ui, repo, *pats, **opts):
4751 """show changed files in the working directory
4746 """show changed files in the working directory
4752
4747
4753 Show status of files in the repository. If names are given, only
4748 Show status of files in the repository. If names are given, only
4754 files that match are shown. Files that are clean or ignored or
4749 files that match are shown. Files that are clean or ignored or
4755 the source of a copy/move operation, are not listed unless
4750 the source of a copy/move operation, are not listed unless
4756 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4751 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4757 Unless options described with "show only ..." are given, the
4752 Unless options described with "show only ..." are given, the
4758 options -mardu are used.
4753 options -mardu are used.
4759
4754
4760 Option -q/--quiet hides untracked (unknown and ignored) files
4755 Option -q/--quiet hides untracked (unknown and ignored) files
4761 unless explicitly requested with -u/--unknown or -i/--ignored.
4756 unless explicitly requested with -u/--unknown or -i/--ignored.
4762
4757
4763 .. note::
4758 .. note::
4764
4759
4765 :hg:`status` may appear to disagree with diff if permissions have
4760 :hg:`status` may appear to disagree with diff if permissions have
4766 changed or a merge has occurred. The standard diff format does
4761 changed or a merge has occurred. The standard diff format does
4767 not report permission changes and diff only reports changes
4762 not report permission changes and diff only reports changes
4768 relative to one merge parent.
4763 relative to one merge parent.
4769
4764
4770 If one revision is given, it is used as the base revision.
4765 If one revision is given, it is used as the base revision.
4771 If two revisions are given, the differences between them are
4766 If two revisions are given, the differences between them are
4772 shown. The --change option can also be used as a shortcut to list
4767 shown. The --change option can also be used as a shortcut to list
4773 the changed files of a revision from its first parent.
4768 the changed files of a revision from its first parent.
4774
4769
4775 The codes used to show the status of files are::
4770 The codes used to show the status of files are::
4776
4771
4777 M = modified
4772 M = modified
4778 A = added
4773 A = added
4779 R = removed
4774 R = removed
4780 C = clean
4775 C = clean
4781 ! = missing (deleted by non-hg command, but still tracked)
4776 ! = missing (deleted by non-hg command, but still tracked)
4782 ? = not tracked
4777 ? = not tracked
4783 I = ignored
4778 I = ignored
4784 = origin of the previous file (with --copies)
4779 = origin of the previous file (with --copies)
4785
4780
4786 .. container:: verbose
4781 .. container:: verbose
4787
4782
4788 The -t/--terse option abbreviates the output by showing only the directory
4783 The -t/--terse option abbreviates the output by showing only the directory
4789 name if all the files in it share the same status. The option takes an
4784 name if all the files in it share the same status. The option takes an
4790 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4785 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
4791 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4786 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
4792 for 'ignored' and 'c' for clean.
4787 for 'ignored' and 'c' for clean.
4793
4788
4794 It abbreviates only those statuses which are passed. Note that clean and
4789 It abbreviates only those statuses which are passed. Note that clean and
4795 ignored files are not displayed with '--terse ic' unless the -c/--clean
4790 ignored files are not displayed with '--terse ic' unless the -c/--clean
4796 and -i/--ignored options are also used.
4791 and -i/--ignored options are also used.
4797
4792
4798 The -v/--verbose option shows information when the repository is in an
4793 The -v/--verbose option shows information when the repository is in an
4799 unfinished merge, shelve, rebase state etc. You can have this behavior
4794 unfinished merge, shelve, rebase state etc. You can have this behavior
4800 turned on by default by enabling the ``commands.status.verbose`` option.
4795 turned on by default by enabling the ``commands.status.verbose`` option.
4801
4796
4802 You can skip displaying some of these states by setting
4797 You can skip displaying some of these states by setting
4803 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4798 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
4804 'histedit', 'merge', 'rebase', or 'unshelve'.
4799 'histedit', 'merge', 'rebase', or 'unshelve'.
4805
4800
4806 Examples:
4801 Examples:
4807
4802
4808 - show changes in the working directory relative to a
4803 - show changes in the working directory relative to a
4809 changeset::
4804 changeset::
4810
4805
4811 hg status --rev 9353
4806 hg status --rev 9353
4812
4807
4813 - show changes in the working directory relative to the
4808 - show changes in the working directory relative to the
4814 current directory (see :hg:`help patterns` for more information)::
4809 current directory (see :hg:`help patterns` for more information)::
4815
4810
4816 hg status re:
4811 hg status re:
4817
4812
4818 - show all changes including copies in an existing changeset::
4813 - show all changes including copies in an existing changeset::
4819
4814
4820 hg status --copies --change 9353
4815 hg status --copies --change 9353
4821
4816
4822 - get a NUL separated list of added files, suitable for xargs::
4817 - get a NUL separated list of added files, suitable for xargs::
4823
4818
4824 hg status -an0
4819 hg status -an0
4825
4820
4826 - show more information about the repository status, abbreviating
4821 - show more information about the repository status, abbreviating
4827 added, removed, modified, deleted, and untracked paths::
4822 added, removed, modified, deleted, and untracked paths::
4828
4823
4829 hg status -v -t mardu
4824 hg status -v -t mardu
4830
4825
4831 Returns 0 on success.
4826 Returns 0 on success.
4832
4827
4833 """
4828 """
4834
4829
4835 opts = pycompat.byteskwargs(opts)
4830 opts = pycompat.byteskwargs(opts)
4836 revs = opts.get('rev')
4831 revs = opts.get('rev')
4837 change = opts.get('change')
4832 change = opts.get('change')
4838 terse = opts.get('terse')
4833 terse = opts.get('terse')
4839
4834
4840 if revs and change:
4835 if revs and change:
4841 msg = _('cannot specify --rev and --change at the same time')
4836 msg = _('cannot specify --rev and --change at the same time')
4842 raise error.Abort(msg)
4837 raise error.Abort(msg)
4843 elif revs and terse:
4838 elif revs and terse:
4844 msg = _('cannot use --terse with --rev')
4839 msg = _('cannot use --terse with --rev')
4845 raise error.Abort(msg)
4840 raise error.Abort(msg)
4846 elif change:
4841 elif change:
4847 node2 = scmutil.revsingle(repo, change, None).node()
4842 node2 = scmutil.revsingle(repo, change, None).node()
4848 node1 = repo[node2].p1().node()
4843 node1 = repo[node2].p1().node()
4849 else:
4844 else:
4850 node1, node2 = scmutil.revpair(repo, revs)
4845 node1, node2 = scmutil.revpair(repo, revs)
4851
4846
4852 if pats or ui.configbool('commands', 'status.relative'):
4847 if pats or ui.configbool('commands', 'status.relative'):
4853 cwd = repo.getcwd()
4848 cwd = repo.getcwd()
4854 else:
4849 else:
4855 cwd = ''
4850 cwd = ''
4856
4851
4857 if opts.get('print0'):
4852 if opts.get('print0'):
4858 end = '\0'
4853 end = '\0'
4859 else:
4854 else:
4860 end = '\n'
4855 end = '\n'
4861 copy = {}
4856 copy = {}
4862 states = 'modified added removed deleted unknown ignored clean'.split()
4857 states = 'modified added removed deleted unknown ignored clean'.split()
4863 show = [k for k in states if opts.get(k)]
4858 show = [k for k in states if opts.get(k)]
4864 if opts.get('all'):
4859 if opts.get('all'):
4865 show += ui.quiet and (states[:4] + ['clean']) or states
4860 show += ui.quiet and (states[:4] + ['clean']) or states
4866
4861
4867 if not show:
4862 if not show:
4868 if ui.quiet:
4863 if ui.quiet:
4869 show = states[:4]
4864 show = states[:4]
4870 else:
4865 else:
4871 show = states[:5]
4866 show = states[:5]
4872
4867
4873 m = scmutil.match(repo[node2], pats, opts)
4868 m = scmutil.match(repo[node2], pats, opts)
4874 if terse:
4869 if terse:
4875 # we need to compute clean and unknown to terse
4870 # we need to compute clean and unknown to terse
4876 stat = repo.status(node1, node2, m,
4871 stat = repo.status(node1, node2, m,
4877 'ignored' in show or 'i' in terse,
4872 'ignored' in show or 'i' in terse,
4878 True, True, opts.get('subrepos'))
4873 True, True, opts.get('subrepos'))
4879
4874
4880 stat = cmdutil.tersedir(stat, terse)
4875 stat = cmdutil.tersedir(stat, terse)
4881 else:
4876 else:
4882 stat = repo.status(node1, node2, m,
4877 stat = repo.status(node1, node2, m,
4883 'ignored' in show, 'clean' in show,
4878 'ignored' in show, 'clean' in show,
4884 'unknown' in show, opts.get('subrepos'))
4879 'unknown' in show, opts.get('subrepos'))
4885
4880
4886 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4881 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4887
4882
4888 if (opts.get('all') or opts.get('copies')
4883 if (opts.get('all') or opts.get('copies')
4889 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4884 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4890 copy = copies.pathcopies(repo[node1], repo[node2], m)
4885 copy = copies.pathcopies(repo[node1], repo[node2], m)
4891
4886
4892 ui.pager('status')
4887 ui.pager('status')
4893 fm = ui.formatter('status', opts)
4888 fm = ui.formatter('status', opts)
4894 fmt = '%s' + end
4889 fmt = '%s' + end
4895 showchar = not opts.get('no_status')
4890 showchar = not opts.get('no_status')
4896
4891
4897 for state, char, files in changestates:
4892 for state, char, files in changestates:
4898 if state in show:
4893 if state in show:
4899 label = 'status.' + state
4894 label = 'status.' + state
4900 for f in files:
4895 for f in files:
4901 fm.startitem()
4896 fm.startitem()
4902 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4897 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4903 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4898 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4904 if f in copy:
4899 if f in copy:
4905 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4900 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4906 label='status.copied')
4901 label='status.copied')
4907
4902
4908 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4903 if ((ui.verbose or ui.configbool('commands', 'status.verbose'))
4909 and not ui.plain()):
4904 and not ui.plain()):
4910 cmdutil.morestatus(repo, fm)
4905 cmdutil.morestatus(repo, fm)
4911 fm.end()
4906 fm.end()
4912
4907
4913 @command('^summary|sum',
4908 @command('^summary|sum',
4914 [('', 'remote', None, _('check for push and pull'))],
4909 [('', 'remote', None, _('check for push and pull'))],
4915 '[--remote]', cmdtype=readonly)
4910 '[--remote]', cmdtype=readonly)
4916 def summary(ui, repo, **opts):
4911 def summary(ui, repo, **opts):
4917 """summarize working directory state
4912 """summarize working directory state
4918
4913
4919 This generates a brief summary of the working directory state,
4914 This generates a brief summary of the working directory state,
4920 including parents, branch, commit status, phase and available updates.
4915 including parents, branch, commit status, phase and available updates.
4921
4916
4922 With the --remote option, this will check the default paths for
4917 With the --remote option, this will check the default paths for
4923 incoming and outgoing changes. This can be time-consuming.
4918 incoming and outgoing changes. This can be time-consuming.
4924
4919
4925 Returns 0 on success.
4920 Returns 0 on success.
4926 """
4921 """
4927
4922
4928 opts = pycompat.byteskwargs(opts)
4923 opts = pycompat.byteskwargs(opts)
4929 ui.pager('summary')
4924 ui.pager('summary')
4930 ctx = repo[None]
4925 ctx = repo[None]
4931 parents = ctx.parents()
4926 parents = ctx.parents()
4932 pnode = parents[0].node()
4927 pnode = parents[0].node()
4933 marks = []
4928 marks = []
4934
4929
4935 ms = None
4930 ms = None
4936 try:
4931 try:
4937 ms = mergemod.mergestate.read(repo)
4932 ms = mergemod.mergestate.read(repo)
4938 except error.UnsupportedMergeRecords as e:
4933 except error.UnsupportedMergeRecords as e:
4939 s = ' '.join(e.recordtypes)
4934 s = ' '.join(e.recordtypes)
4940 ui.warn(
4935 ui.warn(
4941 _('warning: merge state has unsupported record types: %s\n') % s)
4936 _('warning: merge state has unsupported record types: %s\n') % s)
4942 unresolved = []
4937 unresolved = []
4943 else:
4938 else:
4944 unresolved = list(ms.unresolved())
4939 unresolved = list(ms.unresolved())
4945
4940
4946 for p in parents:
4941 for p in parents:
4947 # label with log.changeset (instead of log.parent) since this
4942 # label with log.changeset (instead of log.parent) since this
4948 # shows a working directory parent *changeset*:
4943 # shows a working directory parent *changeset*:
4949 # i18n: column positioning for "hg summary"
4944 # i18n: column positioning for "hg summary"
4950 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4945 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4951 label=cmdutil._changesetlabels(p))
4946 label=cmdutil._changesetlabels(p))
4952 ui.write(' '.join(p.tags()), label='log.tag')
4947 ui.write(' '.join(p.tags()), label='log.tag')
4953 if p.bookmarks():
4948 if p.bookmarks():
4954 marks.extend(p.bookmarks())
4949 marks.extend(p.bookmarks())
4955 if p.rev() == -1:
4950 if p.rev() == -1:
4956 if not len(repo):
4951 if not len(repo):
4957 ui.write(_(' (empty repository)'))
4952 ui.write(_(' (empty repository)'))
4958 else:
4953 else:
4959 ui.write(_(' (no revision checked out)'))
4954 ui.write(_(' (no revision checked out)'))
4960 if p.obsolete():
4955 if p.obsolete():
4961 ui.write(_(' (obsolete)'))
4956 ui.write(_(' (obsolete)'))
4962 if p.isunstable():
4957 if p.isunstable():
4963 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4958 instabilities = (ui.label(instability, 'trouble.%s' % instability)
4964 for instability in p.instabilities())
4959 for instability in p.instabilities())
4965 ui.write(' ('
4960 ui.write(' ('
4966 + ', '.join(instabilities)
4961 + ', '.join(instabilities)
4967 + ')')
4962 + ')')
4968 ui.write('\n')
4963 ui.write('\n')
4969 if p.description():
4964 if p.description():
4970 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4965 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4971 label='log.summary')
4966 label='log.summary')
4972
4967
4973 branch = ctx.branch()
4968 branch = ctx.branch()
4974 bheads = repo.branchheads(branch)
4969 bheads = repo.branchheads(branch)
4975 # i18n: column positioning for "hg summary"
4970 # i18n: column positioning for "hg summary"
4976 m = _('branch: %s\n') % branch
4971 m = _('branch: %s\n') % branch
4977 if branch != 'default':
4972 if branch != 'default':
4978 ui.write(m, label='log.branch')
4973 ui.write(m, label='log.branch')
4979 else:
4974 else:
4980 ui.status(m, label='log.branch')
4975 ui.status(m, label='log.branch')
4981
4976
4982 if marks:
4977 if marks:
4983 active = repo._activebookmark
4978 active = repo._activebookmark
4984 # i18n: column positioning for "hg summary"
4979 # i18n: column positioning for "hg summary"
4985 ui.write(_('bookmarks:'), label='log.bookmark')
4980 ui.write(_('bookmarks:'), label='log.bookmark')
4986 if active is not None:
4981 if active is not None:
4987 if active in marks:
4982 if active in marks:
4988 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4983 ui.write(' *' + active, label=bookmarks.activebookmarklabel)
4989 marks.remove(active)
4984 marks.remove(active)
4990 else:
4985 else:
4991 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4986 ui.write(' [%s]' % active, label=bookmarks.activebookmarklabel)
4992 for m in marks:
4987 for m in marks:
4993 ui.write(' ' + m, label='log.bookmark')
4988 ui.write(' ' + m, label='log.bookmark')
4994 ui.write('\n', label='log.bookmark')
4989 ui.write('\n', label='log.bookmark')
4995
4990
4996 status = repo.status(unknown=True)
4991 status = repo.status(unknown=True)
4997
4992
4998 c = repo.dirstate.copies()
4993 c = repo.dirstate.copies()
4999 copied, renamed = [], []
4994 copied, renamed = [], []
5000 for d, s in c.iteritems():
4995 for d, s in c.iteritems():
5001 if s in status.removed:
4996 if s in status.removed:
5002 status.removed.remove(s)
4997 status.removed.remove(s)
5003 renamed.append(d)
4998 renamed.append(d)
5004 else:
4999 else:
5005 copied.append(d)
5000 copied.append(d)
5006 if d in status.added:
5001 if d in status.added:
5007 status.added.remove(d)
5002 status.added.remove(d)
5008
5003
5009 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5004 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5010
5005
5011 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5006 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5012 (ui.label(_('%d added'), 'status.added'), status.added),
5007 (ui.label(_('%d added'), 'status.added'), status.added),
5013 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5008 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5014 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5009 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5015 (ui.label(_('%d copied'), 'status.copied'), copied),
5010 (ui.label(_('%d copied'), 'status.copied'), copied),
5016 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5011 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5017 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5012 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5018 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5013 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5019 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5014 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5020 t = []
5015 t = []
5021 for l, s in labels:
5016 for l, s in labels:
5022 if s:
5017 if s:
5023 t.append(l % len(s))
5018 t.append(l % len(s))
5024
5019
5025 t = ', '.join(t)
5020 t = ', '.join(t)
5026 cleanworkdir = False
5021 cleanworkdir = False
5027
5022
5028 if repo.vfs.exists('graftstate'):
5023 if repo.vfs.exists('graftstate'):
5029 t += _(' (graft in progress)')
5024 t += _(' (graft in progress)')
5030 if repo.vfs.exists('updatestate'):
5025 if repo.vfs.exists('updatestate'):
5031 t += _(' (interrupted update)')
5026 t += _(' (interrupted update)')
5032 elif len(parents) > 1:
5027 elif len(parents) > 1:
5033 t += _(' (merge)')
5028 t += _(' (merge)')
5034 elif branch != parents[0].branch():
5029 elif branch != parents[0].branch():
5035 t += _(' (new branch)')
5030 t += _(' (new branch)')
5036 elif (parents[0].closesbranch() and
5031 elif (parents[0].closesbranch() and
5037 pnode in repo.branchheads(branch, closed=True)):
5032 pnode in repo.branchheads(branch, closed=True)):
5038 t += _(' (head closed)')
5033 t += _(' (head closed)')
5039 elif not (status.modified or status.added or status.removed or renamed or
5034 elif not (status.modified or status.added or status.removed or renamed or
5040 copied or subs):
5035 copied or subs):
5041 t += _(' (clean)')
5036 t += _(' (clean)')
5042 cleanworkdir = True
5037 cleanworkdir = True
5043 elif pnode not in bheads:
5038 elif pnode not in bheads:
5044 t += _(' (new branch head)')
5039 t += _(' (new branch head)')
5045
5040
5046 if parents:
5041 if parents:
5047 pendingphase = max(p.phase() for p in parents)
5042 pendingphase = max(p.phase() for p in parents)
5048 else:
5043 else:
5049 pendingphase = phases.public
5044 pendingphase = phases.public
5050
5045
5051 if pendingphase > phases.newcommitphase(ui):
5046 if pendingphase > phases.newcommitphase(ui):
5052 t += ' (%s)' % phases.phasenames[pendingphase]
5047 t += ' (%s)' % phases.phasenames[pendingphase]
5053
5048
5054 if cleanworkdir:
5049 if cleanworkdir:
5055 # i18n: column positioning for "hg summary"
5050 # i18n: column positioning for "hg summary"
5056 ui.status(_('commit: %s\n') % t.strip())
5051 ui.status(_('commit: %s\n') % t.strip())
5057 else:
5052 else:
5058 # i18n: column positioning for "hg summary"
5053 # i18n: column positioning for "hg summary"
5059 ui.write(_('commit: %s\n') % t.strip())
5054 ui.write(_('commit: %s\n') % t.strip())
5060
5055
5061 # all ancestors of branch heads - all ancestors of parent = new csets
5056 # all ancestors of branch heads - all ancestors of parent = new csets
5062 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5057 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5063 bheads))
5058 bheads))
5064
5059
5065 if new == 0:
5060 if new == 0:
5066 # i18n: column positioning for "hg summary"
5061 # i18n: column positioning for "hg summary"
5067 ui.status(_('update: (current)\n'))
5062 ui.status(_('update: (current)\n'))
5068 elif pnode not in bheads:
5063 elif pnode not in bheads:
5069 # i18n: column positioning for "hg summary"
5064 # i18n: column positioning for "hg summary"
5070 ui.write(_('update: %d new changesets (update)\n') % new)
5065 ui.write(_('update: %d new changesets (update)\n') % new)
5071 else:
5066 else:
5072 # i18n: column positioning for "hg summary"
5067 # i18n: column positioning for "hg summary"
5073 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5068 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5074 (new, len(bheads)))
5069 (new, len(bheads)))
5075
5070
5076 t = []
5071 t = []
5077 draft = len(repo.revs('draft()'))
5072 draft = len(repo.revs('draft()'))
5078 if draft:
5073 if draft:
5079 t.append(_('%d draft') % draft)
5074 t.append(_('%d draft') % draft)
5080 secret = len(repo.revs('secret()'))
5075 secret = len(repo.revs('secret()'))
5081 if secret:
5076 if secret:
5082 t.append(_('%d secret') % secret)
5077 t.append(_('%d secret') % secret)
5083
5078
5084 if draft or secret:
5079 if draft or secret:
5085 ui.status(_('phases: %s\n') % ', '.join(t))
5080 ui.status(_('phases: %s\n') % ', '.join(t))
5086
5081
5087 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5082 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5088 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5083 for trouble in ("orphan", "contentdivergent", "phasedivergent"):
5089 numtrouble = len(repo.revs(trouble + "()"))
5084 numtrouble = len(repo.revs(trouble + "()"))
5090 # We write all the possibilities to ease translation
5085 # We write all the possibilities to ease translation
5091 troublemsg = {
5086 troublemsg = {
5092 "orphan": _("orphan: %d changesets"),
5087 "orphan": _("orphan: %d changesets"),
5093 "contentdivergent": _("content-divergent: %d changesets"),
5088 "contentdivergent": _("content-divergent: %d changesets"),
5094 "phasedivergent": _("phase-divergent: %d changesets"),
5089 "phasedivergent": _("phase-divergent: %d changesets"),
5095 }
5090 }
5096 if numtrouble > 0:
5091 if numtrouble > 0:
5097 ui.status(troublemsg[trouble] % numtrouble + "\n")
5092 ui.status(troublemsg[trouble] % numtrouble + "\n")
5098
5093
5099 cmdutil.summaryhooks(ui, repo)
5094 cmdutil.summaryhooks(ui, repo)
5100
5095
5101 if opts.get('remote'):
5096 if opts.get('remote'):
5102 needsincoming, needsoutgoing = True, True
5097 needsincoming, needsoutgoing = True, True
5103 else:
5098 else:
5104 needsincoming, needsoutgoing = False, False
5099 needsincoming, needsoutgoing = False, False
5105 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5100 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5106 if i:
5101 if i:
5107 needsincoming = True
5102 needsincoming = True
5108 if o:
5103 if o:
5109 needsoutgoing = True
5104 needsoutgoing = True
5110 if not needsincoming and not needsoutgoing:
5105 if not needsincoming and not needsoutgoing:
5111 return
5106 return
5112
5107
5113 def getincoming():
5108 def getincoming():
5114 source, branches = hg.parseurl(ui.expandpath('default'))
5109 source, branches = hg.parseurl(ui.expandpath('default'))
5115 sbranch = branches[0]
5110 sbranch = branches[0]
5116 try:
5111 try:
5117 other = hg.peer(repo, {}, source)
5112 other = hg.peer(repo, {}, source)
5118 except error.RepoError:
5113 except error.RepoError:
5119 if opts.get('remote'):
5114 if opts.get('remote'):
5120 raise
5115 raise
5121 return source, sbranch, None, None, None
5116 return source, sbranch, None, None, None
5122 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5117 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5123 if revs:
5118 if revs:
5124 revs = [other.lookup(rev) for rev in revs]
5119 revs = [other.lookup(rev) for rev in revs]
5125 ui.debug('comparing with %s\n' % util.hidepassword(source))
5120 ui.debug('comparing with %s\n' % util.hidepassword(source))
5126 repo.ui.pushbuffer()
5121 repo.ui.pushbuffer()
5127 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5122 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5128 repo.ui.popbuffer()
5123 repo.ui.popbuffer()
5129 return source, sbranch, other, commoninc, commoninc[1]
5124 return source, sbranch, other, commoninc, commoninc[1]
5130
5125
5131 if needsincoming:
5126 if needsincoming:
5132 source, sbranch, sother, commoninc, incoming = getincoming()
5127 source, sbranch, sother, commoninc, incoming = getincoming()
5133 else:
5128 else:
5134 source = sbranch = sother = commoninc = incoming = None
5129 source = sbranch = sother = commoninc = incoming = None
5135
5130
5136 def getoutgoing():
5131 def getoutgoing():
5137 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5132 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5138 dbranch = branches[0]
5133 dbranch = branches[0]
5139 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5134 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5140 if source != dest:
5135 if source != dest:
5141 try:
5136 try:
5142 dother = hg.peer(repo, {}, dest)
5137 dother = hg.peer(repo, {}, dest)
5143 except error.RepoError:
5138 except error.RepoError:
5144 if opts.get('remote'):
5139 if opts.get('remote'):
5145 raise
5140 raise
5146 return dest, dbranch, None, None
5141 return dest, dbranch, None, None
5147 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5142 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5148 elif sother is None:
5143 elif sother is None:
5149 # there is no explicit destination peer, but source one is invalid
5144 # there is no explicit destination peer, but source one is invalid
5150 return dest, dbranch, None, None
5145 return dest, dbranch, None, None
5151 else:
5146 else:
5152 dother = sother
5147 dother = sother
5153 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5148 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5154 common = None
5149 common = None
5155 else:
5150 else:
5156 common = commoninc
5151 common = commoninc
5157 if revs:
5152 if revs:
5158 revs = [repo.lookup(rev) for rev in revs]
5153 revs = [repo.lookup(rev) for rev in revs]
5159 repo.ui.pushbuffer()
5154 repo.ui.pushbuffer()
5160 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5155 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5161 commoninc=common)
5156 commoninc=common)
5162 repo.ui.popbuffer()
5157 repo.ui.popbuffer()
5163 return dest, dbranch, dother, outgoing
5158 return dest, dbranch, dother, outgoing
5164
5159
5165 if needsoutgoing:
5160 if needsoutgoing:
5166 dest, dbranch, dother, outgoing = getoutgoing()
5161 dest, dbranch, dother, outgoing = getoutgoing()
5167 else:
5162 else:
5168 dest = dbranch = dother = outgoing = None
5163 dest = dbranch = dother = outgoing = None
5169
5164
5170 if opts.get('remote'):
5165 if opts.get('remote'):
5171 t = []
5166 t = []
5172 if incoming:
5167 if incoming:
5173 t.append(_('1 or more incoming'))
5168 t.append(_('1 or more incoming'))
5174 o = outgoing.missing
5169 o = outgoing.missing
5175 if o:
5170 if o:
5176 t.append(_('%d outgoing') % len(o))
5171 t.append(_('%d outgoing') % len(o))
5177 other = dother or sother
5172 other = dother or sother
5178 if 'bookmarks' in other.listkeys('namespaces'):
5173 if 'bookmarks' in other.listkeys('namespaces'):
5179 counts = bookmarks.summary(repo, other)
5174 counts = bookmarks.summary(repo, other)
5180 if counts[0] > 0:
5175 if counts[0] > 0:
5181 t.append(_('%d incoming bookmarks') % counts[0])
5176 t.append(_('%d incoming bookmarks') % counts[0])
5182 if counts[1] > 0:
5177 if counts[1] > 0:
5183 t.append(_('%d outgoing bookmarks') % counts[1])
5178 t.append(_('%d outgoing bookmarks') % counts[1])
5184
5179
5185 if t:
5180 if t:
5186 # i18n: column positioning for "hg summary"
5181 # i18n: column positioning for "hg summary"
5187 ui.write(_('remote: %s\n') % (', '.join(t)))
5182 ui.write(_('remote: %s\n') % (', '.join(t)))
5188 else:
5183 else:
5189 # i18n: column positioning for "hg summary"
5184 # i18n: column positioning for "hg summary"
5190 ui.status(_('remote: (synced)\n'))
5185 ui.status(_('remote: (synced)\n'))
5191
5186
5192 cmdutil.summaryremotehooks(ui, repo, opts,
5187 cmdutil.summaryremotehooks(ui, repo, opts,
5193 ((source, sbranch, sother, commoninc),
5188 ((source, sbranch, sother, commoninc),
5194 (dest, dbranch, dother, outgoing)))
5189 (dest, dbranch, dother, outgoing)))
5195
5190
5196 @command('tag',
5191 @command('tag',
5197 [('f', 'force', None, _('force tag')),
5192 [('f', 'force', None, _('force tag')),
5198 ('l', 'local', None, _('make the tag local')),
5193 ('l', 'local', None, _('make the tag local')),
5199 ('r', 'rev', '', _('revision to tag'), _('REV')),
5194 ('r', 'rev', '', _('revision to tag'), _('REV')),
5200 ('', 'remove', None, _('remove a tag')),
5195 ('', 'remove', None, _('remove a tag')),
5201 # -l/--local is already there, commitopts cannot be used
5196 # -l/--local is already there, commitopts cannot be used
5202 ('e', 'edit', None, _('invoke editor on commit messages')),
5197 ('e', 'edit', None, _('invoke editor on commit messages')),
5203 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5198 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5204 ] + commitopts2,
5199 ] + commitopts2,
5205 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5200 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5206 def tag(ui, repo, name1, *names, **opts):
5201 def tag(ui, repo, name1, *names, **opts):
5207 """add one or more tags for the current or given revision
5202 """add one or more tags for the current or given revision
5208
5203
5209 Name a particular revision using <name>.
5204 Name a particular revision using <name>.
5210
5205
5211 Tags are used to name particular revisions of the repository and are
5206 Tags are used to name particular revisions of the repository and are
5212 very useful to compare different revisions, to go back to significant
5207 very useful to compare different revisions, to go back to significant
5213 earlier versions or to mark branch points as releases, etc. Changing
5208 earlier versions or to mark branch points as releases, etc. Changing
5214 an existing tag is normally disallowed; use -f/--force to override.
5209 an existing tag is normally disallowed; use -f/--force to override.
5215
5210
5216 If no revision is given, the parent of the working directory is
5211 If no revision is given, the parent of the working directory is
5217 used.
5212 used.
5218
5213
5219 To facilitate version control, distribution, and merging of tags,
5214 To facilitate version control, distribution, and merging of tags,
5220 they are stored as a file named ".hgtags" which is managed similarly
5215 they are stored as a file named ".hgtags" which is managed similarly
5221 to other project files and can be hand-edited if necessary. This
5216 to other project files and can be hand-edited if necessary. This
5222 also means that tagging creates a new commit. The file
5217 also means that tagging creates a new commit. The file
5223 ".hg/localtags" is used for local tags (not shared among
5218 ".hg/localtags" is used for local tags (not shared among
5224 repositories).
5219 repositories).
5225
5220
5226 Tag commits are usually made at the head of a branch. If the parent
5221 Tag commits are usually made at the head of a branch. If the parent
5227 of the working directory is not a branch head, :hg:`tag` aborts; use
5222 of the working directory is not a branch head, :hg:`tag` aborts; use
5228 -f/--force to force the tag commit to be based on a non-head
5223 -f/--force to force the tag commit to be based on a non-head
5229 changeset.
5224 changeset.
5230
5225
5231 See :hg:`help dates` for a list of formats valid for -d/--date.
5226 See :hg:`help dates` for a list of formats valid for -d/--date.
5232
5227
5233 Since tag names have priority over branch names during revision
5228 Since tag names have priority over branch names during revision
5234 lookup, using an existing branch name as a tag name is discouraged.
5229 lookup, using an existing branch name as a tag name is discouraged.
5235
5230
5236 Returns 0 on success.
5231 Returns 0 on success.
5237 """
5232 """
5238 opts = pycompat.byteskwargs(opts)
5233 opts = pycompat.byteskwargs(opts)
5239 wlock = lock = None
5234 wlock = lock = None
5240 try:
5235 try:
5241 wlock = repo.wlock()
5236 wlock = repo.wlock()
5242 lock = repo.lock()
5237 lock = repo.lock()
5243 rev_ = "."
5238 rev_ = "."
5244 names = [t.strip() for t in (name1,) + names]
5239 names = [t.strip() for t in (name1,) + names]
5245 if len(names) != len(set(names)):
5240 if len(names) != len(set(names)):
5246 raise error.Abort(_('tag names must be unique'))
5241 raise error.Abort(_('tag names must be unique'))
5247 for n in names:
5242 for n in names:
5248 scmutil.checknewlabel(repo, n, 'tag')
5243 scmutil.checknewlabel(repo, n, 'tag')
5249 if not n:
5244 if not n:
5250 raise error.Abort(_('tag names cannot consist entirely of '
5245 raise error.Abort(_('tag names cannot consist entirely of '
5251 'whitespace'))
5246 'whitespace'))
5252 if opts.get('rev') and opts.get('remove'):
5247 if opts.get('rev') and opts.get('remove'):
5253 raise error.Abort(_("--rev and --remove are incompatible"))
5248 raise error.Abort(_("--rev and --remove are incompatible"))
5254 if opts.get('rev'):
5249 if opts.get('rev'):
5255 rev_ = opts['rev']
5250 rev_ = opts['rev']
5256 message = opts.get('message')
5251 message = opts.get('message')
5257 if opts.get('remove'):
5252 if opts.get('remove'):
5258 if opts.get('local'):
5253 if opts.get('local'):
5259 expectedtype = 'local'
5254 expectedtype = 'local'
5260 else:
5255 else:
5261 expectedtype = 'global'
5256 expectedtype = 'global'
5262
5257
5263 for n in names:
5258 for n in names:
5264 if not repo.tagtype(n):
5259 if not repo.tagtype(n):
5265 raise error.Abort(_("tag '%s' does not exist") % n)
5260 raise error.Abort(_("tag '%s' does not exist") % n)
5266 if repo.tagtype(n) != expectedtype:
5261 if repo.tagtype(n) != expectedtype:
5267 if expectedtype == 'global':
5262 if expectedtype == 'global':
5268 raise error.Abort(_("tag '%s' is not a global tag") % n)
5263 raise error.Abort(_("tag '%s' is not a global tag") % n)
5269 else:
5264 else:
5270 raise error.Abort(_("tag '%s' is not a local tag") % n)
5265 raise error.Abort(_("tag '%s' is not a local tag") % n)
5271 rev_ = 'null'
5266 rev_ = 'null'
5272 if not message:
5267 if not message:
5273 # we don't translate commit messages
5268 # we don't translate commit messages
5274 message = 'Removed tag %s' % ', '.join(names)
5269 message = 'Removed tag %s' % ', '.join(names)
5275 elif not opts.get('force'):
5270 elif not opts.get('force'):
5276 for n in names:
5271 for n in names:
5277 if n in repo.tags():
5272 if n in repo.tags():
5278 raise error.Abort(_("tag '%s' already exists "
5273 raise error.Abort(_("tag '%s' already exists "
5279 "(use -f to force)") % n)
5274 "(use -f to force)") % n)
5280 if not opts.get('local'):
5275 if not opts.get('local'):
5281 p1, p2 = repo.dirstate.parents()
5276 p1, p2 = repo.dirstate.parents()
5282 if p2 != nullid:
5277 if p2 != nullid:
5283 raise error.Abort(_('uncommitted merge'))
5278 raise error.Abort(_('uncommitted merge'))
5284 bheads = repo.branchheads()
5279 bheads = repo.branchheads()
5285 if not opts.get('force') and bheads and p1 not in bheads:
5280 if not opts.get('force') and bheads and p1 not in bheads:
5286 raise error.Abort(_('working directory is not at a branch head '
5281 raise error.Abort(_('working directory is not at a branch head '
5287 '(use -f to force)'))
5282 '(use -f to force)'))
5288 r = scmutil.revsingle(repo, rev_).node()
5283 r = scmutil.revsingle(repo, rev_).node()
5289
5284
5290 if not message:
5285 if not message:
5291 # we don't translate commit messages
5286 # we don't translate commit messages
5292 message = ('Added tag %s for changeset %s' %
5287 message = ('Added tag %s for changeset %s' %
5293 (', '.join(names), short(r)))
5288 (', '.join(names), short(r)))
5294
5289
5295 date = opts.get('date')
5290 date = opts.get('date')
5296 if date:
5291 if date:
5297 date = util.parsedate(date)
5292 date = util.parsedate(date)
5298
5293
5299 if opts.get('remove'):
5294 if opts.get('remove'):
5300 editform = 'tag.remove'
5295 editform = 'tag.remove'
5301 else:
5296 else:
5302 editform = 'tag.add'
5297 editform = 'tag.add'
5303 editor = cmdutil.getcommiteditor(editform=editform,
5298 editor = cmdutil.getcommiteditor(editform=editform,
5304 **pycompat.strkwargs(opts))
5299 **pycompat.strkwargs(opts))
5305
5300
5306 # don't allow tagging the null rev
5301 # don't allow tagging the null rev
5307 if (not opts.get('remove') and
5302 if (not opts.get('remove') and
5308 scmutil.revsingle(repo, rev_).rev() == nullrev):
5303 scmutil.revsingle(repo, rev_).rev() == nullrev):
5309 raise error.Abort(_("cannot tag null revision"))
5304 raise error.Abort(_("cannot tag null revision"))
5310
5305
5311 tagsmod.tag(repo, names, r, message, opts.get('local'),
5306 tagsmod.tag(repo, names, r, message, opts.get('local'),
5312 opts.get('user'), date, editor=editor)
5307 opts.get('user'), date, editor=editor)
5313 finally:
5308 finally:
5314 release(lock, wlock)
5309 release(lock, wlock)
5315
5310
5316 @command('tags', formatteropts, '', cmdtype=readonly)
5311 @command('tags', formatteropts, '', cmdtype=readonly)
5317 def tags(ui, repo, **opts):
5312 def tags(ui, repo, **opts):
5318 """list repository tags
5313 """list repository tags
5319
5314
5320 This lists both regular and local tags. When the -v/--verbose
5315 This lists both regular and local tags. When the -v/--verbose
5321 switch is used, a third column "local" is printed for local tags.
5316 switch is used, a third column "local" is printed for local tags.
5322 When the -q/--quiet switch is used, only the tag name is printed.
5317 When the -q/--quiet switch is used, only the tag name is printed.
5323
5318
5324 Returns 0 on success.
5319 Returns 0 on success.
5325 """
5320 """
5326
5321
5327 opts = pycompat.byteskwargs(opts)
5322 opts = pycompat.byteskwargs(opts)
5328 ui.pager('tags')
5323 ui.pager('tags')
5329 fm = ui.formatter('tags', opts)
5324 fm = ui.formatter('tags', opts)
5330 hexfunc = fm.hexfunc
5325 hexfunc = fm.hexfunc
5331 tagtype = ""
5326 tagtype = ""
5332
5327
5333 for t, n in reversed(repo.tagslist()):
5328 for t, n in reversed(repo.tagslist()):
5334 hn = hexfunc(n)
5329 hn = hexfunc(n)
5335 label = 'tags.normal'
5330 label = 'tags.normal'
5336 tagtype = ''
5331 tagtype = ''
5337 if repo.tagtype(t) == 'local':
5332 if repo.tagtype(t) == 'local':
5338 label = 'tags.local'
5333 label = 'tags.local'
5339 tagtype = 'local'
5334 tagtype = 'local'
5340
5335
5341 fm.startitem()
5336 fm.startitem()
5342 fm.write('tag', '%s', t, label=label)
5337 fm.write('tag', '%s', t, label=label)
5343 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5338 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5344 fm.condwrite(not ui.quiet, 'rev node', fmt,
5339 fm.condwrite(not ui.quiet, 'rev node', fmt,
5345 repo.changelog.rev(n), hn, label=label)
5340 repo.changelog.rev(n), hn, label=label)
5346 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5341 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5347 tagtype, label=label)
5342 tagtype, label=label)
5348 fm.plain('\n')
5343 fm.plain('\n')
5349 fm.end()
5344 fm.end()
5350
5345
5351 @command('tip',
5346 @command('tip',
5352 [('p', 'patch', None, _('show patch')),
5347 [('p', 'patch', None, _('show patch')),
5353 ('g', 'git', None, _('use git extended diff format')),
5348 ('g', 'git', None, _('use git extended diff format')),
5354 ] + templateopts,
5349 ] + templateopts,
5355 _('[-p] [-g]'))
5350 _('[-p] [-g]'))
5356 def tip(ui, repo, **opts):
5351 def tip(ui, repo, **opts):
5357 """show the tip revision (DEPRECATED)
5352 """show the tip revision (DEPRECATED)
5358
5353
5359 The tip revision (usually just called the tip) is the changeset
5354 The tip revision (usually just called the tip) is the changeset
5360 most recently added to the repository (and therefore the most
5355 most recently added to the repository (and therefore the most
5361 recently changed head).
5356 recently changed head).
5362
5357
5363 If you have just made a commit, that commit will be the tip. If
5358 If you have just made a commit, that commit will be the tip. If
5364 you have just pulled changes from another repository, the tip of
5359 you have just pulled changes from another repository, the tip of
5365 that repository becomes the current tip. The "tip" tag is special
5360 that repository becomes the current tip. The "tip" tag is special
5366 and cannot be renamed or assigned to a different changeset.
5361 and cannot be renamed or assigned to a different changeset.
5367
5362
5368 This command is deprecated, please use :hg:`heads` instead.
5363 This command is deprecated, please use :hg:`heads` instead.
5369
5364
5370 Returns 0 on success.
5365 Returns 0 on success.
5371 """
5366 """
5372 opts = pycompat.byteskwargs(opts)
5367 opts = pycompat.byteskwargs(opts)
5373 displayer = cmdutil.show_changeset(ui, repo, opts)
5368 displayer = cmdutil.show_changeset(ui, repo, opts)
5374 displayer.show(repo['tip'])
5369 displayer.show(repo['tip'])
5375 displayer.close()
5370 displayer.close()
5376
5371
5377 @command('unbundle',
5372 @command('unbundle',
5378 [('u', 'update', None,
5373 [('u', 'update', None,
5379 _('update to new branch head if changesets were unbundled'))],
5374 _('update to new branch head if changesets were unbundled'))],
5380 _('[-u] FILE...'))
5375 _('[-u] FILE...'))
5381 def unbundle(ui, repo, fname1, *fnames, **opts):
5376 def unbundle(ui, repo, fname1, *fnames, **opts):
5382 """apply one or more bundle files
5377 """apply one or more bundle files
5383
5378
5384 Apply one or more bundle files generated by :hg:`bundle`.
5379 Apply one or more bundle files generated by :hg:`bundle`.
5385
5380
5386 Returns 0 on success, 1 if an update has unresolved files.
5381 Returns 0 on success, 1 if an update has unresolved files.
5387 """
5382 """
5388 fnames = (fname1,) + fnames
5383 fnames = (fname1,) + fnames
5389
5384
5390 with repo.lock():
5385 with repo.lock():
5391 for fname in fnames:
5386 for fname in fnames:
5392 f = hg.openpath(ui, fname)
5387 f = hg.openpath(ui, fname)
5393 gen = exchange.readbundle(ui, f, fname)
5388 gen = exchange.readbundle(ui, f, fname)
5394 if isinstance(gen, streamclone.streamcloneapplier):
5389 if isinstance(gen, streamclone.streamcloneapplier):
5395 raise error.Abort(
5390 raise error.Abort(
5396 _('packed bundles cannot be applied with '
5391 _('packed bundles cannot be applied with '
5397 '"hg unbundle"'),
5392 '"hg unbundle"'),
5398 hint=_('use "hg debugapplystreamclonebundle"'))
5393 hint=_('use "hg debugapplystreamclonebundle"'))
5399 url = 'bundle:' + fname
5394 url = 'bundle:' + fname
5400 try:
5395 try:
5401 txnname = 'unbundle'
5396 txnname = 'unbundle'
5402 if not isinstance(gen, bundle2.unbundle20):
5397 if not isinstance(gen, bundle2.unbundle20):
5403 txnname = 'unbundle\n%s' % util.hidepassword(url)
5398 txnname = 'unbundle\n%s' % util.hidepassword(url)
5404 with repo.transaction(txnname) as tr:
5399 with repo.transaction(txnname) as tr:
5405 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5400 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5406 url=url)
5401 url=url)
5407 except error.BundleUnknownFeatureError as exc:
5402 except error.BundleUnknownFeatureError as exc:
5408 raise error.Abort(
5403 raise error.Abort(
5409 _('%s: unknown bundle feature, %s') % (fname, exc),
5404 _('%s: unknown bundle feature, %s') % (fname, exc),
5410 hint=_("see https://mercurial-scm.org/"
5405 hint=_("see https://mercurial-scm.org/"
5411 "wiki/BundleFeature for more "
5406 "wiki/BundleFeature for more "
5412 "information"))
5407 "information"))
5413 modheads = bundle2.combinechangegroupresults(op)
5408 modheads = bundle2.combinechangegroupresults(op)
5414
5409
5415 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5410 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5416
5411
5417 @command('^update|up|checkout|co',
5412 @command('^update|up|checkout|co',
5418 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5413 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5419 ('c', 'check', None, _('require clean working directory')),
5414 ('c', 'check', None, _('require clean working directory')),
5420 ('m', 'merge', None, _('merge uncommitted changes')),
5415 ('m', 'merge', None, _('merge uncommitted changes')),
5421 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5416 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5422 ('r', 'rev', '', _('revision'), _('REV'))
5417 ('r', 'rev', '', _('revision'), _('REV'))
5423 ] + mergetoolopts,
5418 ] + mergetoolopts,
5424 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5419 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5425 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5420 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5426 merge=None, tool=None):
5421 merge=None, tool=None):
5427 """update working directory (or switch revisions)
5422 """update working directory (or switch revisions)
5428
5423
5429 Update the repository's working directory to the specified
5424 Update the repository's working directory to the specified
5430 changeset. If no changeset is specified, update to the tip of the
5425 changeset. If no changeset is specified, update to the tip of the
5431 current named branch and move the active bookmark (see :hg:`help
5426 current named branch and move the active bookmark (see :hg:`help
5432 bookmarks`).
5427 bookmarks`).
5433
5428
5434 Update sets the working directory's parent revision to the specified
5429 Update sets the working directory's parent revision to the specified
5435 changeset (see :hg:`help parents`).
5430 changeset (see :hg:`help parents`).
5436
5431
5437 If the changeset is not a descendant or ancestor of the working
5432 If the changeset is not a descendant or ancestor of the working
5438 directory's parent and there are uncommitted changes, the update is
5433 directory's parent and there are uncommitted changes, the update is
5439 aborted. With the -c/--check option, the working directory is checked
5434 aborted. With the -c/--check option, the working directory is checked
5440 for uncommitted changes; if none are found, the working directory is
5435 for uncommitted changes; if none are found, the working directory is
5441 updated to the specified changeset.
5436 updated to the specified changeset.
5442
5437
5443 .. container:: verbose
5438 .. container:: verbose
5444
5439
5445 The -C/--clean, -c/--check, and -m/--merge options control what
5440 The -C/--clean, -c/--check, and -m/--merge options control what
5446 happens if the working directory contains uncommitted changes.
5441 happens if the working directory contains uncommitted changes.
5447 At most of one of them can be specified.
5442 At most of one of them can be specified.
5448
5443
5449 1. If no option is specified, and if
5444 1. If no option is specified, and if
5450 the requested changeset is an ancestor or descendant of
5445 the requested changeset is an ancestor or descendant of
5451 the working directory's parent, the uncommitted changes
5446 the working directory's parent, the uncommitted changes
5452 are merged into the requested changeset and the merged
5447 are merged into the requested changeset and the merged
5453 result is left uncommitted. If the requested changeset is
5448 result is left uncommitted. If the requested changeset is
5454 not an ancestor or descendant (that is, it is on another
5449 not an ancestor or descendant (that is, it is on another
5455 branch), the update is aborted and the uncommitted changes
5450 branch), the update is aborted and the uncommitted changes
5456 are preserved.
5451 are preserved.
5457
5452
5458 2. With the -m/--merge option, the update is allowed even if the
5453 2. With the -m/--merge option, the update is allowed even if the
5459 requested changeset is not an ancestor or descendant of
5454 requested changeset is not an ancestor or descendant of
5460 the working directory's parent.
5455 the working directory's parent.
5461
5456
5462 3. With the -c/--check option, the update is aborted and the
5457 3. With the -c/--check option, the update is aborted and the
5463 uncommitted changes are preserved.
5458 uncommitted changes are preserved.
5464
5459
5465 4. With the -C/--clean option, uncommitted changes are discarded and
5460 4. With the -C/--clean option, uncommitted changes are discarded and
5466 the working directory is updated to the requested changeset.
5461 the working directory is updated to the requested changeset.
5467
5462
5468 To cancel an uncommitted merge (and lose your changes), use
5463 To cancel an uncommitted merge (and lose your changes), use
5469 :hg:`update --clean .`.
5464 :hg:`update --clean .`.
5470
5465
5471 Use null as the changeset to remove the working directory (like
5466 Use null as the changeset to remove the working directory (like
5472 :hg:`clone -U`).
5467 :hg:`clone -U`).
5473
5468
5474 If you want to revert just one file to an older revision, use
5469 If you want to revert just one file to an older revision, use
5475 :hg:`revert [-r REV] NAME`.
5470 :hg:`revert [-r REV] NAME`.
5476
5471
5477 See :hg:`help dates` for a list of formats valid for -d/--date.
5472 See :hg:`help dates` for a list of formats valid for -d/--date.
5478
5473
5479 Returns 0 on success, 1 if there are unresolved files.
5474 Returns 0 on success, 1 if there are unresolved files.
5480 """
5475 """
5481 if rev and node:
5476 if rev and node:
5482 raise error.Abort(_("please specify just one revision"))
5477 raise error.Abort(_("please specify just one revision"))
5483
5478
5484 if ui.configbool('commands', 'update.requiredest'):
5479 if ui.configbool('commands', 'update.requiredest'):
5485 if not node and not rev and not date:
5480 if not node and not rev and not date:
5486 raise error.Abort(_('you must specify a destination'),
5481 raise error.Abort(_('you must specify a destination'),
5487 hint=_('for example: hg update ".::"'))
5482 hint=_('for example: hg update ".::"'))
5488
5483
5489 if rev is None or rev == '':
5484 if rev is None or rev == '':
5490 rev = node
5485 rev = node
5491
5486
5492 if date and rev is not None:
5487 if date and rev is not None:
5493 raise error.Abort(_("you can't specify a revision and a date"))
5488 raise error.Abort(_("you can't specify a revision and a date"))
5494
5489
5495 if len([x for x in (clean, check, merge) if x]) > 1:
5490 if len([x for x in (clean, check, merge) if x]) > 1:
5496 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5491 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5497 "or -m/--merge"))
5492 "or -m/--merge"))
5498
5493
5499 updatecheck = None
5494 updatecheck = None
5500 if check:
5495 if check:
5501 updatecheck = 'abort'
5496 updatecheck = 'abort'
5502 elif merge:
5497 elif merge:
5503 updatecheck = 'none'
5498 updatecheck = 'none'
5504
5499
5505 with repo.wlock():
5500 with repo.wlock():
5506 cmdutil.clearunfinished(repo)
5501 cmdutil.clearunfinished(repo)
5507
5502
5508 if date:
5503 if date:
5509 rev = cmdutil.finddate(ui, repo, date)
5504 rev = cmdutil.finddate(ui, repo, date)
5510
5505
5511 # if we defined a bookmark, we have to remember the original name
5506 # if we defined a bookmark, we have to remember the original name
5512 brev = rev
5507 brev = rev
5513 rev = scmutil.revsingle(repo, rev, rev).rev()
5508 rev = scmutil.revsingle(repo, rev, rev).rev()
5514
5509
5515 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5510 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5516
5511
5517 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5512 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5518 updatecheck=updatecheck)
5513 updatecheck=updatecheck)
5519
5514
5520 @command('verify', [])
5515 @command('verify', [])
5521 def verify(ui, repo):
5516 def verify(ui, repo):
5522 """verify the integrity of the repository
5517 """verify the integrity of the repository
5523
5518
5524 Verify the integrity of the current repository.
5519 Verify the integrity of the current repository.
5525
5520
5526 This will perform an extensive check of the repository's
5521 This will perform an extensive check of the repository's
5527 integrity, validating the hashes and checksums of each entry in
5522 integrity, validating the hashes and checksums of each entry in
5528 the changelog, manifest, and tracked files, as well as the
5523 the changelog, manifest, and tracked files, as well as the
5529 integrity of their crosslinks and indices.
5524 integrity of their crosslinks and indices.
5530
5525
5531 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5526 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5532 for more information about recovery from corruption of the
5527 for more information about recovery from corruption of the
5533 repository.
5528 repository.
5534
5529
5535 Returns 0 on success, 1 if errors are encountered.
5530 Returns 0 on success, 1 if errors are encountered.
5536 """
5531 """
5537 return hg.verify(repo)
5532 return hg.verify(repo)
5538
5533
5539 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5534 @command('version', [] + formatteropts, norepo=True, cmdtype=readonly)
5540 def version_(ui, **opts):
5535 def version_(ui, **opts):
5541 """output version and copyright information"""
5536 """output version and copyright information"""
5542 opts = pycompat.byteskwargs(opts)
5537 opts = pycompat.byteskwargs(opts)
5543 if ui.verbose:
5538 if ui.verbose:
5544 ui.pager('version')
5539 ui.pager('version')
5545 fm = ui.formatter("version", opts)
5540 fm = ui.formatter("version", opts)
5546 fm.startitem()
5541 fm.startitem()
5547 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5542 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5548 util.version())
5543 util.version())
5549 license = _(
5544 license = _(
5550 "(see https://mercurial-scm.org for more information)\n"
5545 "(see https://mercurial-scm.org for more information)\n"
5551 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5546 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5552 "This is free software; see the source for copying conditions. "
5547 "This is free software; see the source for copying conditions. "
5553 "There is NO\nwarranty; "
5548 "There is NO\nwarranty; "
5554 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5549 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5555 )
5550 )
5556 if not ui.quiet:
5551 if not ui.quiet:
5557 fm.plain(license)
5552 fm.plain(license)
5558
5553
5559 if ui.verbose:
5554 if ui.verbose:
5560 fm.plain(_("\nEnabled extensions:\n\n"))
5555 fm.plain(_("\nEnabled extensions:\n\n"))
5561 # format names and versions into columns
5556 # format names and versions into columns
5562 names = []
5557 names = []
5563 vers = []
5558 vers = []
5564 isinternals = []
5559 isinternals = []
5565 for name, module in extensions.extensions():
5560 for name, module in extensions.extensions():
5566 names.append(name)
5561 names.append(name)
5567 vers.append(extensions.moduleversion(module) or None)
5562 vers.append(extensions.moduleversion(module) or None)
5568 isinternals.append(extensions.ismoduleinternal(module))
5563 isinternals.append(extensions.ismoduleinternal(module))
5569 fn = fm.nested("extensions")
5564 fn = fm.nested("extensions")
5570 if names:
5565 if names:
5571 namefmt = " %%-%ds " % max(len(n) for n in names)
5566 namefmt = " %%-%ds " % max(len(n) for n in names)
5572 places = [_("external"), _("internal")]
5567 places = [_("external"), _("internal")]
5573 for n, v, p in zip(names, vers, isinternals):
5568 for n, v, p in zip(names, vers, isinternals):
5574 fn.startitem()
5569 fn.startitem()
5575 fn.condwrite(ui.verbose, "name", namefmt, n)
5570 fn.condwrite(ui.verbose, "name", namefmt, n)
5576 if ui.verbose:
5571 if ui.verbose:
5577 fn.plain("%s " % places[p])
5572 fn.plain("%s " % places[p])
5578 fn.data(bundled=p)
5573 fn.data(bundled=p)
5579 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5574 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5580 if ui.verbose:
5575 if ui.verbose:
5581 fn.plain("\n")
5576 fn.plain("\n")
5582 fn.end()
5577 fn.end()
5583 fm.end()
5578 fm.end()
5584
5579
5585 def loadcmdtable(ui, name, cmdtable):
5580 def loadcmdtable(ui, name, cmdtable):
5586 """Load command functions from specified cmdtable
5581 """Load command functions from specified cmdtable
5587 """
5582 """
5588 overrides = [cmd for cmd in cmdtable if cmd in table]
5583 overrides = [cmd for cmd in cmdtable if cmd in table]
5589 if overrides:
5584 if overrides:
5590 ui.warn(_("extension '%s' overrides commands: %s\n")
5585 ui.warn(_("extension '%s' overrides commands: %s\n")
5591 % (name, " ".join(overrides)))
5586 % (name, " ".join(overrides)))
5592 table.update(cmdtable)
5587 table.update(cmdtable)
@@ -1,331 +1,332 b''
1 #testcases obsstore-off obsstore-on
1 #testcases obsstore-off obsstore-on
2
2
3 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
4 > [extensions]
4 > [extensions]
5 > amend=
5 > amend=
6 > debugdrawdag=$TESTDIR/drawdag.py
6 > debugdrawdag=$TESTDIR/drawdag.py
7 > [diff]
7 > [diff]
8 > git=1
8 > git=1
9 > EOF
9 > EOF
10
10
11 #if obsstore-on
11 #if obsstore-on
12 $ cat << EOF >> $HGRCPATH
12 $ cat << EOF >> $HGRCPATH
13 > [experimental]
13 > [experimental]
14 > evolution.createmarkers=True
14 > evolution.createmarkers=True
15 > EOF
15 > EOF
16 #endif
16 #endif
17
17
18 Basic amend
18 Basic amend
19
19
20 $ hg init repo1
20 $ hg init repo1
21 $ cd repo1
21 $ cd repo1
22 $ hg debugdrawdag <<'EOS'
22 $ hg debugdrawdag <<'EOS'
23 > B
23 > B
24 > |
24 > |
25 > A
25 > A
26 > EOS
26 > EOS
27
27
28 $ hg update B -q
28 $ hg update B -q
29 $ echo 2 >> B
29 $ echo 2 >> B
30
30
31 $ hg amend
31 $ hg amend
32 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/112478962961-7e959a55-amend.hg (glob) (obsstore-off !)
32 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/112478962961-7e959a55-amend.hg (glob) (obsstore-off !)
33 #if obsstore-off
33 #if obsstore-off
34 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
34 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
35 @ 1 be169c7e8dbe B
35 @ 1 be169c7e8dbe B
36 | diff --git a/B b/B
36 | diff --git a/B b/B
37 | new file mode 100644
37 | new file mode 100644
38 | --- /dev/null
38 | --- /dev/null
39 | +++ b/B
39 | +++ b/B
40 | @@ -0,0 +1,1 @@
40 | @@ -0,0 +1,1 @@
41 | +B2
41 | +B2
42 |
42 |
43 o 0 426bada5c675 A
43 o 0 426bada5c675 A
44 diff --git a/A b/A
44 diff --git a/A b/A
45 new file mode 100644
45 new file mode 100644
46 --- /dev/null
46 --- /dev/null
47 +++ b/A
47 +++ b/A
48 @@ -0,0 +1,1 @@
48 @@ -0,0 +1,1 @@
49 +A
49 +A
50 \ No newline at end of file
50 \ No newline at end of file
51
51
52 #else
52 #else
53 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
53 $ hg log -p -G --hidden -T '{rev} {node|short} {desc}\n'
54 @ 2 be169c7e8dbe B
54 @ 2 be169c7e8dbe B
55 | diff --git a/B b/B
55 | diff --git a/B b/B
56 | new file mode 100644
56 | new file mode 100644
57 | --- /dev/null
57 | --- /dev/null
58 | +++ b/B
58 | +++ b/B
59 | @@ -0,0 +1,1 @@
59 | @@ -0,0 +1,1 @@
60 | +B2
60 | +B2
61 |
61 |
62 | x 1 112478962961 B
62 | x 1 112478962961 B
63 |/ diff --git a/B b/B
63 |/ diff --git a/B b/B
64 | new file mode 100644
64 | new file mode 100644
65 | --- /dev/null
65 | --- /dev/null
66 | +++ b/B
66 | +++ b/B
67 | @@ -0,0 +1,1 @@
67 | @@ -0,0 +1,1 @@
68 | +B
68 | +B
69 | \ No newline at end of file
69 | \ No newline at end of file
70 |
70 |
71 o 0 426bada5c675 A
71 o 0 426bada5c675 A
72 diff --git a/A b/A
72 diff --git a/A b/A
73 new file mode 100644
73 new file mode 100644
74 --- /dev/null
74 --- /dev/null
75 +++ b/A
75 +++ b/A
76 @@ -0,0 +1,1 @@
76 @@ -0,0 +1,1 @@
77 +A
77 +A
78 \ No newline at end of file
78 \ No newline at end of file
79
79
80 #endif
80 #endif
81
81
82 Nothing changed
82 Nothing changed
83
83
84 $ hg amend
84 $ hg amend
85 nothing changed
85 nothing changed
86 [1]
86 [1]
87
87
88 $ hg amend -d "0 0"
88 $ hg amend -d "0 0"
89 nothing changed
89 nothing changed
90 [1]
90 [1]
91
91
92 $ hg amend -d "Thu Jan 01 00:00:00 1970 UTC"
92 $ hg amend -d "Thu Jan 01 00:00:00 1970 UTC"
93 nothing changed
93 nothing changed
94 [1]
94 [1]
95
95
96 Matcher and metadata options
96 Matcher and metadata options
97
97
98 $ echo 3 > C
98 $ echo 3 > C
99 $ echo 4 > D
99 $ echo 4 > D
100 $ hg add C D
100 $ hg add C D
101 $ hg amend -m NEWMESSAGE -I C
101 $ hg amend -m NEWMESSAGE -I C
102 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/be169c7e8dbe-7684ddc5-amend.hg (glob) (obsstore-off !)
102 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/be169c7e8dbe-7684ddc5-amend.hg (glob) (obsstore-off !)
103 $ hg log -r . -T '{node|short} {desc} {files}\n'
103 $ hg log -r . -T '{node|short} {desc} {files}\n'
104 c7ba14d9075b NEWMESSAGE B C
104 c7ba14d9075b NEWMESSAGE B C
105 $ echo 5 > E
105 $ echo 5 > E
106 $ rm C
106 $ rm C
107 $ hg amend -d '2000 1000' -u 'Foo <foo@example.com>' -A C D
107 $ hg amend -d '2000 1000' -u 'Foo <foo@example.com>' -A C D
108 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/c7ba14d9075b-b3e76daa-amend.hg (glob) (obsstore-off !)
108 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/c7ba14d9075b-b3e76daa-amend.hg (glob) (obsstore-off !)
109 $ hg log -r . -T '{node|short} {desc} {files} {author} {date}\n'
109 $ hg log -r . -T '{node|short} {desc} {files} {author} {date}\n'
110 14f6c4bcc865 NEWMESSAGE B D Foo <foo@example.com> 2000.01000
110 14f6c4bcc865 NEWMESSAGE B D Foo <foo@example.com> 2000.01000
111
111
112 Amend with editor
112 Amend with editor
113
113
114 $ cat > $TESTTMP/prefix.sh <<'EOF'
114 $ cat > $TESTTMP/prefix.sh <<'EOF'
115 > printf 'EDITED: ' > $TESTTMP/msg
115 > printf 'EDITED: ' > $TESTTMP/msg
116 > cat "$1" >> $TESTTMP/msg
116 > cat "$1" >> $TESTTMP/msg
117 > mv $TESTTMP/msg "$1"
117 > mv $TESTTMP/msg "$1"
118 > EOF
118 > EOF
119 $ chmod +x $TESTTMP/prefix.sh
119 $ chmod +x $TESTTMP/prefix.sh
120
120
121 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend --edit
121 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend --edit
122 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/14f6c4bcc865-6591f15d-amend.hg (glob) (obsstore-off !)
122 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/14f6c4bcc865-6591f15d-amend.hg (glob) (obsstore-off !)
123 $ hg log -r . -T '{node|short} {desc}\n'
123 $ hg log -r . -T '{node|short} {desc}\n'
124 298f085230c3 EDITED: NEWMESSAGE
124 298f085230c3 EDITED: NEWMESSAGE
125 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend -e -m MSG
125 $ HGEDITOR="sh $TESTTMP/prefix.sh" hg amend -e -m MSG
126 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/298f085230c3-d81a6ad3-amend.hg (glob) (obsstore-off !)
126 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/298f085230c3-d81a6ad3-amend.hg (glob) (obsstore-off !)
127 $ hg log -r . -T '{node|short} {desc}\n'
127 $ hg log -r . -T '{node|short} {desc}\n'
128 974f07f28537 EDITED: MSG
128 974f07f28537 EDITED: MSG
129
129
130 $ echo FOO > $TESTTMP/msg
130 $ echo FOO > $TESTTMP/msg
131 $ hg amend -l $TESTTMP/msg -m BAR
131 $ hg amend -l $TESTTMP/msg -m BAR
132 abort: options --message and --logfile are mutually exclusive
132 abort: options --message and --logfile are mutually exclusive
133 [255]
133 [255]
134 $ hg amend -l $TESTTMP/msg
134 $ hg amend -l $TESTTMP/msg
135 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/974f07f28537-edb6470a-amend.hg (glob) (obsstore-off !)
135 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/974f07f28537-edb6470a-amend.hg (glob) (obsstore-off !)
136 $ hg log -r . -T '{node|short} {desc}\n'
136 $ hg log -r . -T '{node|short} {desc}\n'
137 507be9bdac71 FOO
137 507be9bdac71 FOO
138
138
139 Interactive mode
139 Interactive mode
140
140
141 $ touch F G
141 $ touch F G
142 $ hg add F G
142 $ hg add F G
143 $ cat <<EOS | hg amend -i --config ui.interactive=1
143 $ cat <<EOS | hg amend -i --config ui.interactive=1
144 > y
144 > y
145 > n
145 > n
146 > EOS
146 > EOS
147 diff --git a/F b/F
147 diff --git a/F b/F
148 new file mode 100644
148 new file mode 100644
149 examine changes to 'F'? [Ynesfdaq?] y
149 examine changes to 'F'? [Ynesfdaq?] y
150
150
151 diff --git a/G b/G
151 diff --git a/G b/G
152 new file mode 100644
152 new file mode 100644
153 examine changes to 'G'? [Ynesfdaq?] n
153 examine changes to 'G'? [Ynesfdaq?] n
154
154
155 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/507be9bdac71-c8077452-amend.hg (glob) (obsstore-off !)
155 saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/507be9bdac71-c8077452-amend.hg (glob) (obsstore-off !)
156 $ hg log -r . -T '{files}\n'
156 $ hg log -r . -T '{files}\n'
157 B D F
157 B D F
158
158
159 Amend in the middle of a stack
159 Amend in the middle of a stack
160
160
161 $ hg init $TESTTMP/repo2
161 $ hg init $TESTTMP/repo2
162 $ cd $TESTTMP/repo2
162 $ cd $TESTTMP/repo2
163 $ hg debugdrawdag <<'EOS'
163 $ hg debugdrawdag <<'EOS'
164 > C
164 > C
165 > |
165 > |
166 > B
166 > B
167 > |
167 > |
168 > A
168 > A
169 > EOS
169 > EOS
170
170
171 $ hg update -q B
171 $ hg update -q B
172 $ echo 2 >> B
172 $ echo 2 >> B
173 $ hg amend
173 $ hg amend
174 abort: cannot amend changeset with children
174 abort: cannot amend changeset with children
175 [255]
175 [255]
176
176
177 #if obsstore-on
177 #if obsstore-on
178
178
179 With allowunstable, amend could work in the middle of a stack
179 With allowunstable, amend could work in the middle of a stack
180
180
181 $ cat >> $HGRCPATH <<EOF
181 $ cat >> $HGRCPATH <<EOF
182 > [experimental]
182 > [experimental]
183 > evolution.createmarkers=True
183 > evolution.createmarkers=True
184 > evolution.allowunstable=True
184 > evolution.allowunstable=True
185 > EOF
185 > EOF
186
186
187 $ hg amend
187 $ hg amend
188 $ hg log -T '{rev} {node|short} {desc}\n' -G
188 $ hg log -T '{rev} {node|short} {desc}\n' -G
189 @ 3 be169c7e8dbe B
189 @ 3 be169c7e8dbe B
190 |
190 |
191 | o 2 26805aba1e60 C
191 | o 2 26805aba1e60 C
192 | |
192 | |
193 | x 1 112478962961 B
193 | x 1 112478962961 B
194 |/
194 |/
195 o 0 426bada5c675 A
195 o 0 426bada5c675 A
196
196
197 Checking the note stored in the obsmarker
197 Checking the note stored in the obsmarker
198
198
199 $ echo foo > bar
199 $ echo foo > bar
200 $ hg add bar
200 $ hg add bar
201 $ hg amend --note 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
201 $ hg amend --note 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
202 abort: cannot store a note of more than 255 bytes
202 abort: cannot store a note of more than 255 bytes
203 [255]
203 [255]
204 $ hg amend --note "adding bar"
204 $ hg amend --note "adding bar"
205 $ hg debugobsolete -r .
205 $ hg debugobsolete -r .
206 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
206 112478962961147124edd43549aedd1a335e44bf be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
207 be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 16084da537dd8f84cfdb3055c633772269d62e1b 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'adding bar', 'operation': 'amend', 'user': 'test'}
207 be169c7e8dbe21cd10b3d79691cbe7f241e3c21c 16084da537dd8f84cfdb3055c633772269d62e1b 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'adding bar', 'operation': 'amend', 'user': 'test'}
208 #endif
208 #endif
209
209
210 Cannot amend public changeset
210 Cannot amend public changeset
211
211
212 $ hg phase -r A --public
212 $ hg phase -r A --public
213 $ hg update -C -q A
213 $ hg update -C -q A
214 $ hg amend -m AMEND
214 $ hg amend -m AMEND
215 abort: cannot amend public changesets
215 abort: cannot amend public changesets
216 (see 'hg help phases' for details)
216 [255]
217 [255]
217
218
218 Amend a merge changeset
219 Amend a merge changeset
219
220
220 $ hg init $TESTTMP/repo3
221 $ hg init $TESTTMP/repo3
221 $ cd $TESTTMP/repo3
222 $ cd $TESTTMP/repo3
222 $ hg debugdrawdag <<'EOS'
223 $ hg debugdrawdag <<'EOS'
223 > C
224 > C
224 > /|
225 > /|
225 > A B
226 > A B
226 > EOS
227 > EOS
227 $ hg update -q C
228 $ hg update -q C
228 $ hg amend -m FOO
229 $ hg amend -m FOO
229 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/a35c07e8a2a4-15ff4612-amend.hg (glob) (obsstore-off !)
230 saved backup bundle to $TESTTMP/repo3/.hg/strip-backup/a35c07e8a2a4-15ff4612-amend.hg (glob) (obsstore-off !)
230 $ rm .hg/localtags
231 $ rm .hg/localtags
231 $ hg log -G -T '{desc}\n'
232 $ hg log -G -T '{desc}\n'
232 @ FOO
233 @ FOO
233 |\
234 |\
234 | o B
235 | o B
235 |
236 |
236 o A
237 o A
237
238
238
239
239 More complete test for status changes (issue5732)
240 More complete test for status changes (issue5732)
240 -------------------------------------------------
241 -------------------------------------------------
241
242
242 Generates history of files having 3 states, r0_r1_wc:
243 Generates history of files having 3 states, r0_r1_wc:
243
244
244 r0: ground (content/missing)
245 r0: ground (content/missing)
245 r1: old state to be amended (content/missing, where missing means removed)
246 r1: old state to be amended (content/missing, where missing means removed)
246 wc: changes to be included in r1 (content/missing-tracked/untracked)
247 wc: changes to be included in r1 (content/missing-tracked/untracked)
247
248
248 $ hg init $TESTTMP/wcstates
249 $ hg init $TESTTMP/wcstates
249 $ cd $TESTTMP/wcstates
250 $ cd $TESTTMP/wcstates
250
251
251 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
252 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 1
252 $ hg addremove -q --similarity 0
253 $ hg addremove -q --similarity 0
253 $ hg commit -m0
254 $ hg commit -m0
254
255
255 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
256 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 2
256 $ hg addremove -q --similarity 0
257 $ hg addremove -q --similarity 0
257 $ hg commit -m1
258 $ hg commit -m1
258
259
259 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
260 $ $PYTHON $TESTDIR/generate-working-copy-states.py state 2 wc
260 $ hg addremove -q --similarity 0
261 $ hg addremove -q --similarity 0
261 $ hg forget *_*_*-untracked
262 $ hg forget *_*_*-untracked
262 $ rm *_*_missing-*
263 $ rm *_*_missing-*
263
264
264 amend r1 to include wc changes
265 amend r1 to include wc changes
265
266
266 $ hg amend
267 $ hg amend
267 saved backup bundle to * (glob) (obsstore-off !)
268 saved backup bundle to * (glob) (obsstore-off !)
268
269
269 clean/modified/removed/added states of the amended revision
270 clean/modified/removed/added states of the amended revision
270
271
271 $ hg status --all --change . 'glob:content1_*_content1-tracked'
272 $ hg status --all --change . 'glob:content1_*_content1-tracked'
272 C content1_content1_content1-tracked
273 C content1_content1_content1-tracked
273 C content1_content2_content1-tracked
274 C content1_content2_content1-tracked
274 C content1_missing_content1-tracked
275 C content1_missing_content1-tracked
275 $ hg status --all --change . 'glob:content1_*_content[23]-tracked'
276 $ hg status --all --change . 'glob:content1_*_content[23]-tracked'
276 M content1_content1_content3-tracked
277 M content1_content1_content3-tracked
277 M content1_content2_content2-tracked
278 M content1_content2_content2-tracked
278 M content1_content2_content3-tracked
279 M content1_content2_content3-tracked
279 M content1_missing_content3-tracked
280 M content1_missing_content3-tracked
280 $ hg status --all --change . 'glob:content1_*_missing-tracked'
281 $ hg status --all --change . 'glob:content1_*_missing-tracked'
281 M content1_content2_missing-tracked
282 M content1_content2_missing-tracked
282 R content1_missing_missing-tracked
283 R content1_missing_missing-tracked
283 C content1_content1_missing-tracked
284 C content1_content1_missing-tracked
284 $ hg status --all --change . 'glob:content1_*_*-untracked'
285 $ hg status --all --change . 'glob:content1_*_*-untracked'
285 R content1_content1_content1-untracked
286 R content1_content1_content1-untracked
286 R content1_content1_content3-untracked
287 R content1_content1_content3-untracked
287 R content1_content1_missing-untracked
288 R content1_content1_missing-untracked
288 R content1_content2_content1-untracked
289 R content1_content2_content1-untracked
289 R content1_content2_content2-untracked
290 R content1_content2_content2-untracked
290 R content1_content2_content3-untracked
291 R content1_content2_content3-untracked
291 R content1_content2_missing-untracked
292 R content1_content2_missing-untracked
292 R content1_missing_content1-untracked
293 R content1_missing_content1-untracked
293 R content1_missing_content3-untracked
294 R content1_missing_content3-untracked
294 R content1_missing_missing-untracked
295 R content1_missing_missing-untracked
295 $ hg status --all --change . 'glob:missing_content2_*'
296 $ hg status --all --change . 'glob:missing_content2_*'
296 A missing_content2_content2-tracked
297 A missing_content2_content2-tracked
297 A missing_content2_content3-tracked
298 A missing_content2_content3-tracked
298 A missing_content2_missing-tracked
299 A missing_content2_missing-tracked
299 $ hg status --all --change . 'glob:missing_missing_*'
300 $ hg status --all --change . 'glob:missing_missing_*'
300 A missing_missing_content3-tracked
301 A missing_missing_content3-tracked
301
302
302 working directory should be all clean (with some missing/untracked files)
303 working directory should be all clean (with some missing/untracked files)
303
304
304 $ hg status --all 'glob:*_content?-tracked'
305 $ hg status --all 'glob:*_content?-tracked'
305 C content1_content1_content1-tracked
306 C content1_content1_content1-tracked
306 C content1_content1_content3-tracked
307 C content1_content1_content3-tracked
307 C content1_content2_content1-tracked
308 C content1_content2_content1-tracked
308 C content1_content2_content2-tracked
309 C content1_content2_content2-tracked
309 C content1_content2_content3-tracked
310 C content1_content2_content3-tracked
310 C content1_missing_content1-tracked
311 C content1_missing_content1-tracked
311 C content1_missing_content3-tracked
312 C content1_missing_content3-tracked
312 C missing_content2_content2-tracked
313 C missing_content2_content2-tracked
313 C missing_content2_content3-tracked
314 C missing_content2_content3-tracked
314 C missing_missing_content3-tracked
315 C missing_missing_content3-tracked
315 $ hg status --all 'glob:*_missing-tracked'
316 $ hg status --all 'glob:*_missing-tracked'
316 ! content1_content1_missing-tracked
317 ! content1_content1_missing-tracked
317 ! content1_content2_missing-tracked
318 ! content1_content2_missing-tracked
318 ! content1_missing_missing-tracked
319 ! content1_missing_missing-tracked
319 ! missing_content2_missing-tracked
320 ! missing_content2_missing-tracked
320 ! missing_missing_missing-tracked
321 ! missing_missing_missing-tracked
321 $ hg status --all 'glob:*-untracked'
322 $ hg status --all 'glob:*-untracked'
322 ? content1_content1_content1-untracked
323 ? content1_content1_content1-untracked
323 ? content1_content1_content3-untracked
324 ? content1_content1_content3-untracked
324 ? content1_content2_content1-untracked
325 ? content1_content2_content1-untracked
325 ? content1_content2_content2-untracked
326 ? content1_content2_content2-untracked
326 ? content1_content2_content3-untracked
327 ? content1_content2_content3-untracked
327 ? content1_missing_content1-untracked
328 ? content1_missing_content1-untracked
328 ? content1_missing_content3-untracked
329 ? content1_missing_content3-untracked
329 ? missing_content2_content2-untracked
330 ? missing_content2_content2-untracked
330 ? missing_content2_content3-untracked
331 ? missing_content2_content3-untracked
331 ? missing_missing_content3-untracked
332 ? missing_missing_content3-untracked
@@ -1,1269 +1,1270 b''
1 $ cat << EOF >> $HGRCPATH
1 $ cat << EOF >> $HGRCPATH
2 > [format]
2 > [format]
3 > usegeneraldelta=yes
3 > usegeneraldelta=yes
4 > EOF
4 > EOF
5
5
6 $ hg init
6 $ hg init
7
7
8 Setup:
8 Setup:
9
9
10 $ echo a >> a
10 $ echo a >> a
11 $ hg ci -Am 'base'
11 $ hg ci -Am 'base'
12 adding a
12 adding a
13
13
14 Refuse to amend public csets:
14 Refuse to amend public csets:
15
15
16 $ hg phase -r . -p
16 $ hg phase -r . -p
17 $ hg ci --amend
17 $ hg ci --amend
18 abort: cannot amend public changesets
18 abort: cannot amend public changesets
19 (see 'hg help phases' for details)
19 [255]
20 [255]
20 $ hg phase -r . -f -d
21 $ hg phase -r . -f -d
21
22
22 $ echo a >> a
23 $ echo a >> a
23 $ hg ci -Am 'base1'
24 $ hg ci -Am 'base1'
24
25
25 Nothing to amend:
26 Nothing to amend:
26
27
27 $ hg ci --amend -m 'base1'
28 $ hg ci --amend -m 'base1'
28 nothing changed
29 nothing changed
29 [1]
30 [1]
30
31
31 $ cat >> $HGRCPATH <<EOF
32 $ cat >> $HGRCPATH <<EOF
32 > [hooks]
33 > [hooks]
33 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
34 > pretxncommit.foo = sh -c "echo \\"pretxncommit \$HG_NODE\\"; hg id -r \$HG_NODE"
34 > EOF
35 > EOF
35
36
36 Amending changeset with changes in working dir:
37 Amending changeset with changes in working dir:
37 (and check that --message does not trigger an editor)
38 (and check that --message does not trigger an editor)
38
39
39 $ echo a >> a
40 $ echo a >> a
40 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
41 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -m 'amend base1'
41 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
42 pretxncommit 43f1ba15f28a50abf0aae529cf8a16bfced7b149
42 43f1ba15f28a tip
43 43f1ba15f28a tip
43 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-5ab4f721-amend.hg (glob)
44 saved backup bundle to $TESTTMP/.hg/strip-backup/489edb5b847d-5ab4f721-amend.hg (glob)
44 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
45 $ echo 'pretxncommit.foo = ' >> $HGRCPATH
45 $ hg diff -c .
46 $ hg diff -c .
46 diff -r ad120869acf0 -r 43f1ba15f28a a
47 diff -r ad120869acf0 -r 43f1ba15f28a a
47 --- a/a Thu Jan 01 00:00:00 1970 +0000
48 --- a/a Thu Jan 01 00:00:00 1970 +0000
48 +++ b/a Thu Jan 01 00:00:00 1970 +0000
49 +++ b/a Thu Jan 01 00:00:00 1970 +0000
49 @@ -1,1 +1,3 @@
50 @@ -1,1 +1,3 @@
50 a
51 a
51 +a
52 +a
52 +a
53 +a
53 $ hg log
54 $ hg log
54 changeset: 1:43f1ba15f28a
55 changeset: 1:43f1ba15f28a
55 tag: tip
56 tag: tip
56 user: test
57 user: test
57 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
58 summary: amend base1
59 summary: amend base1
59
60
60 changeset: 0:ad120869acf0
61 changeset: 0:ad120869acf0
61 user: test
62 user: test
62 date: Thu Jan 01 00:00:00 1970 +0000
63 date: Thu Jan 01 00:00:00 1970 +0000
63 summary: base
64 summary: base
64
65
65
66
66 Check proper abort for empty message
67 Check proper abort for empty message
67
68
68 $ cat > editor.sh << '__EOF__'
69 $ cat > editor.sh << '__EOF__'
69 > #!/bin/sh
70 > #!/bin/sh
70 > echo "" > "$1"
71 > echo "" > "$1"
71 > __EOF__
72 > __EOF__
72
73
73 Update the existing file to ensure that the dirstate is not in pending state
74 Update the existing file to ensure that the dirstate is not in pending state
74 (where the status of some files in the working copy is not known yet). This in
75 (where the status of some files in the working copy is not known yet). This in
75 turn ensures that when the transaction is aborted due to an empty message during
76 turn ensures that when the transaction is aborted due to an empty message during
76 the amend, there should be no rollback.
77 the amend, there should be no rollback.
77 $ echo a >> a
78 $ echo a >> a
78
79
79 $ echo b > b
80 $ echo b > b
80 $ hg add b
81 $ hg add b
81 $ hg summary
82 $ hg summary
82 parent: 1:43f1ba15f28a tip
83 parent: 1:43f1ba15f28a tip
83 amend base1
84 amend base1
84 branch: default
85 branch: default
85 commit: 1 modified, 1 added, 1 unknown
86 commit: 1 modified, 1 added, 1 unknown
86 update: (current)
87 update: (current)
87 phases: 2 draft
88 phases: 2 draft
88 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
89 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
89 abort: empty commit message
90 abort: empty commit message
90 [255]
91 [255]
91 $ hg summary
92 $ hg summary
92 parent: 1:43f1ba15f28a tip
93 parent: 1:43f1ba15f28a tip
93 amend base1
94 amend base1
94 branch: default
95 branch: default
95 commit: 1 modified, 1 added, 1 unknown
96 commit: 1 modified, 1 added, 1 unknown
96 update: (current)
97 update: (current)
97 phases: 2 draft
98 phases: 2 draft
98
99
99 Add new file along with modified existing file:
100 Add new file along with modified existing file:
100 $ hg ci --amend -m 'amend base1 new file'
101 $ hg ci --amend -m 'amend base1 new file'
101 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-007467c2-amend.hg (glob)
102 saved backup bundle to $TESTTMP/.hg/strip-backup/43f1ba15f28a-007467c2-amend.hg (glob)
102
103
103 Remove file that was added in amended commit:
104 Remove file that was added in amended commit:
104 (and test logfile option)
105 (and test logfile option)
105 (and test that logfile option do not trigger an editor)
106 (and test that logfile option do not trigger an editor)
106
107
107 $ hg rm b
108 $ hg rm b
108 $ echo 'amend base1 remove new file' > ../logfile
109 $ echo 'amend base1 remove new file' > ../logfile
109 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
110 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg ci --amend --logfile ../logfile
110 saved backup bundle to $TESTTMP/.hg/strip-backup/c16295aaf401-1ada9901-amend.hg (glob)
111 saved backup bundle to $TESTTMP/.hg/strip-backup/c16295aaf401-1ada9901-amend.hg (glob)
111
112
112 $ hg cat b
113 $ hg cat b
113 b: no such file in rev 47343646fa3d
114 b: no such file in rev 47343646fa3d
114 [1]
115 [1]
115
116
116 No changes, just a different message:
117 No changes, just a different message:
117
118
118 $ hg ci -v --amend -m 'no changes, new message'
119 $ hg ci -v --amend -m 'no changes, new message'
119 amending changeset 47343646fa3d
120 amending changeset 47343646fa3d
120 copying changeset 47343646fa3d to ad120869acf0
121 copying changeset 47343646fa3d to ad120869acf0
121 committing files:
122 committing files:
122 a
123 a
123 committing manifest
124 committing manifest
124 committing changelog
125 committing changelog
125 1 changesets found
126 1 changesets found
126 uncompressed size of bundle content:
127 uncompressed size of bundle content:
127 254 (changelog)
128 254 (changelog)
128 163 (manifests)
129 163 (manifests)
129 131 a
130 131 a
130 saved backup bundle to $TESTTMP/.hg/strip-backup/47343646fa3d-c2758885-amend.hg (glob)
131 saved backup bundle to $TESTTMP/.hg/strip-backup/47343646fa3d-c2758885-amend.hg (glob)
131 1 changesets found
132 1 changesets found
132 uncompressed size of bundle content:
133 uncompressed size of bundle content:
133 250 (changelog)
134 250 (changelog)
134 163 (manifests)
135 163 (manifests)
135 131 a
136 131 a
136 adding branch
137 adding branch
137 adding changesets
138 adding changesets
138 adding manifests
139 adding manifests
139 adding file changes
140 adding file changes
140 added 1 changesets with 1 changes to 1 files
141 added 1 changesets with 1 changes to 1 files
141 committed changeset 1:401431e913a1
142 committed changeset 1:401431e913a1
142 $ hg diff -c .
143 $ hg diff -c .
143 diff -r ad120869acf0 -r 401431e913a1 a
144 diff -r ad120869acf0 -r 401431e913a1 a
144 --- a/a Thu Jan 01 00:00:00 1970 +0000
145 --- a/a Thu Jan 01 00:00:00 1970 +0000
145 +++ b/a Thu Jan 01 00:00:00 1970 +0000
146 +++ b/a Thu Jan 01 00:00:00 1970 +0000
146 @@ -1,1 +1,4 @@
147 @@ -1,1 +1,4 @@
147 a
148 a
148 +a
149 +a
149 +a
150 +a
150 +a
151 +a
151 $ hg log
152 $ hg log
152 changeset: 1:401431e913a1
153 changeset: 1:401431e913a1
153 tag: tip
154 tag: tip
154 user: test
155 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
156 date: Thu Jan 01 00:00:00 1970 +0000
156 summary: no changes, new message
157 summary: no changes, new message
157
158
158 changeset: 0:ad120869acf0
159 changeset: 0:ad120869acf0
159 user: test
160 user: test
160 date: Thu Jan 01 00:00:00 1970 +0000
161 date: Thu Jan 01 00:00:00 1970 +0000
161 summary: base
162 summary: base
162
163
163
164
164 Disable default date on commit so when -d isn't given, the old date is preserved:
165 Disable default date on commit so when -d isn't given, the old date is preserved:
165
166
166 $ echo '[defaults]' >> $HGRCPATH
167 $ echo '[defaults]' >> $HGRCPATH
167 $ echo 'commit=' >> $HGRCPATH
168 $ echo 'commit=' >> $HGRCPATH
168
169
169 Test -u/-d:
170 Test -u/-d:
170
171
171 $ cat > .hg/checkeditform.sh <<EOF
172 $ cat > .hg/checkeditform.sh <<EOF
172 > env | grep HGEDITFORM
173 > env | grep HGEDITFORM
173 > true
174 > true
174 > EOF
175 > EOF
175 $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -u foo -d '1 0'
176 $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -u foo -d '1 0'
176 HGEDITFORM=commit.amend.normal
177 HGEDITFORM=commit.amend.normal
177 saved backup bundle to $TESTTMP/.hg/strip-backup/401431e913a1-5e8e532c-amend.hg (glob)
178 saved backup bundle to $TESTTMP/.hg/strip-backup/401431e913a1-5e8e532c-amend.hg (glob)
178 $ echo a >> a
179 $ echo a >> a
179 $ hg ci --amend -u foo -d '1 0'
180 $ hg ci --amend -u foo -d '1 0'
180 saved backup bundle to $TESTTMP/.hg/strip-backup/d96b1d28ae33-677e0afb-amend.hg (glob)
181 saved backup bundle to $TESTTMP/.hg/strip-backup/d96b1d28ae33-677e0afb-amend.hg (glob)
181 $ hg log -r .
182 $ hg log -r .
182 changeset: 1:a9a13940fc03
183 changeset: 1:a9a13940fc03
183 tag: tip
184 tag: tip
184 user: foo
185 user: foo
185 date: Thu Jan 01 00:00:01 1970 +0000
186 date: Thu Jan 01 00:00:01 1970 +0000
186 summary: no changes, new message
187 summary: no changes, new message
187
188
188
189
189 Open editor with old commit message if a message isn't given otherwise:
190 Open editor with old commit message if a message isn't given otherwise:
190
191
191 $ cat > editor.sh << '__EOF__'
192 $ cat > editor.sh << '__EOF__'
192 > #!/bin/sh
193 > #!/bin/sh
193 > cat $1
194 > cat $1
194 > echo "another precious commit message" > "$1"
195 > echo "another precious commit message" > "$1"
195 > __EOF__
196 > __EOF__
196
197
197 at first, test saving last-message.txt
198 at first, test saving last-message.txt
198
199
199 $ cat > .hg/hgrc << '__EOF__'
200 $ cat > .hg/hgrc << '__EOF__'
200 > [hooks]
201 > [hooks]
201 > pretxncommit.test-saving-last-message = false
202 > pretxncommit.test-saving-last-message = false
202 > __EOF__
203 > __EOF__
203
204
204 $ rm -f .hg/last-message.txt
205 $ rm -f .hg/last-message.txt
205 $ hg commit --amend -v -m "message given from command line"
206 $ hg commit --amend -v -m "message given from command line"
206 amending changeset a9a13940fc03
207 amending changeset a9a13940fc03
207 copying changeset a9a13940fc03 to ad120869acf0
208 copying changeset a9a13940fc03 to ad120869acf0
208 committing files:
209 committing files:
209 a
210 a
210 committing manifest
211 committing manifest
211 committing changelog
212 committing changelog
212 running hook pretxncommit.test-saving-last-message: false
213 running hook pretxncommit.test-saving-last-message: false
213 transaction abort!
214 transaction abort!
214 rollback completed
215 rollback completed
215 abort: pretxncommit.test-saving-last-message hook exited with status 1
216 abort: pretxncommit.test-saving-last-message hook exited with status 1
216 [255]
217 [255]
217 $ cat .hg/last-message.txt
218 $ cat .hg/last-message.txt
218 message given from command line (no-eol)
219 message given from command line (no-eol)
219
220
220 $ rm -f .hg/last-message.txt
221 $ rm -f .hg/last-message.txt
221 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
222 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
222 amending changeset a9a13940fc03
223 amending changeset a9a13940fc03
223 copying changeset a9a13940fc03 to ad120869acf0
224 copying changeset a9a13940fc03 to ad120869acf0
224 no changes, new message
225 no changes, new message
225
226
226
227
227 HG: Enter commit message. Lines beginning with 'HG:' are removed.
228 HG: Enter commit message. Lines beginning with 'HG:' are removed.
228 HG: Leave message empty to abort commit.
229 HG: Leave message empty to abort commit.
229 HG: --
230 HG: --
230 HG: user: foo
231 HG: user: foo
231 HG: branch 'default'
232 HG: branch 'default'
232 HG: changed a
233 HG: changed a
233 committing files:
234 committing files:
234 a
235 a
235 committing manifest
236 committing manifest
236 committing changelog
237 committing changelog
237 running hook pretxncommit.test-saving-last-message: false
238 running hook pretxncommit.test-saving-last-message: false
238 transaction abort!
239 transaction abort!
239 rollback completed
240 rollback completed
240 abort: pretxncommit.test-saving-last-message hook exited with status 1
241 abort: pretxncommit.test-saving-last-message hook exited with status 1
241 [255]
242 [255]
242
243
243 $ cat .hg/last-message.txt
244 $ cat .hg/last-message.txt
244 another precious commit message
245 another precious commit message
245
246
246 $ cat > .hg/hgrc << '__EOF__'
247 $ cat > .hg/hgrc << '__EOF__'
247 > [hooks]
248 > [hooks]
248 > pretxncommit.test-saving-last-message =
249 > pretxncommit.test-saving-last-message =
249 > __EOF__
250 > __EOF__
250
251
251 then, test editing custom commit message
252 then, test editing custom commit message
252
253
253 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
254 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
254 amending changeset a9a13940fc03
255 amending changeset a9a13940fc03
255 copying changeset a9a13940fc03 to ad120869acf0
256 copying changeset a9a13940fc03 to ad120869acf0
256 no changes, new message
257 no changes, new message
257
258
258
259
259 HG: Enter commit message. Lines beginning with 'HG:' are removed.
260 HG: Enter commit message. Lines beginning with 'HG:' are removed.
260 HG: Leave message empty to abort commit.
261 HG: Leave message empty to abort commit.
261 HG: --
262 HG: --
262 HG: user: foo
263 HG: user: foo
263 HG: branch 'default'
264 HG: branch 'default'
264 HG: changed a
265 HG: changed a
265 committing files:
266 committing files:
266 a
267 a
267 committing manifest
268 committing manifest
268 committing changelog
269 committing changelog
269 1 changesets found
270 1 changesets found
270 uncompressed size of bundle content:
271 uncompressed size of bundle content:
271 249 (changelog)
272 249 (changelog)
272 163 (manifests)
273 163 (manifests)
273 133 a
274 133 a
274 saved backup bundle to $TESTTMP/.hg/strip-backup/a9a13940fc03-7c2e8674-amend.hg (glob)
275 saved backup bundle to $TESTTMP/.hg/strip-backup/a9a13940fc03-7c2e8674-amend.hg (glob)
275 1 changesets found
276 1 changesets found
276 uncompressed size of bundle content:
277 uncompressed size of bundle content:
277 257 (changelog)
278 257 (changelog)
278 163 (manifests)
279 163 (manifests)
279 133 a
280 133 a
280 adding branch
281 adding branch
281 adding changesets
282 adding changesets
282 adding manifests
283 adding manifests
283 adding file changes
284 adding file changes
284 added 1 changesets with 1 changes to 1 files
285 added 1 changesets with 1 changes to 1 files
285 committed changeset 1:64a124ba1b44
286 committed changeset 1:64a124ba1b44
286
287
287 Same, but with changes in working dir (different code path):
288 Same, but with changes in working dir (different code path):
288
289
289 $ echo a >> a
290 $ echo a >> a
290 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
291 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend -v
291 amending changeset 64a124ba1b44
292 amending changeset 64a124ba1b44
292 another precious commit message
293 another precious commit message
293
294
294
295
295 HG: Enter commit message. Lines beginning with 'HG:' are removed.
296 HG: Enter commit message. Lines beginning with 'HG:' are removed.
296 HG: Leave message empty to abort commit.
297 HG: Leave message empty to abort commit.
297 HG: --
298 HG: --
298 HG: user: foo
299 HG: user: foo
299 HG: branch 'default'
300 HG: branch 'default'
300 HG: changed a
301 HG: changed a
301 committing files:
302 committing files:
302 a
303 a
303 committing manifest
304 committing manifest
304 committing changelog
305 committing changelog
305 1 changesets found
306 1 changesets found
306 uncompressed size of bundle content:
307 uncompressed size of bundle content:
307 257 (changelog)
308 257 (changelog)
308 163 (manifests)
309 163 (manifests)
309 133 a
310 133 a
310 saved backup bundle to $TESTTMP/.hg/strip-backup/64a124ba1b44-10374b8f-amend.hg (glob)
311 saved backup bundle to $TESTTMP/.hg/strip-backup/64a124ba1b44-10374b8f-amend.hg (glob)
311 1 changesets found
312 1 changesets found
312 uncompressed size of bundle content:
313 uncompressed size of bundle content:
313 257 (changelog)
314 257 (changelog)
314 163 (manifests)
315 163 (manifests)
315 135 a
316 135 a
316 adding branch
317 adding branch
317 adding changesets
318 adding changesets
318 adding manifests
319 adding manifests
319 adding file changes
320 adding file changes
320 added 1 changesets with 1 changes to 1 files
321 added 1 changesets with 1 changes to 1 files
321 committed changeset 1:7892795b8e38
322 committed changeset 1:7892795b8e38
322
323
323 $ rm editor.sh
324 $ rm editor.sh
324 $ hg log -r .
325 $ hg log -r .
325 changeset: 1:7892795b8e38
326 changeset: 1:7892795b8e38
326 tag: tip
327 tag: tip
327 user: foo
328 user: foo
328 date: Thu Jan 01 00:00:01 1970 +0000
329 date: Thu Jan 01 00:00:01 1970 +0000
329 summary: another precious commit message
330 summary: another precious commit message
330
331
331
332
332 Moving bookmarks, preserve active bookmark:
333 Moving bookmarks, preserve active bookmark:
333
334
334 $ hg book book1
335 $ hg book book1
335 $ hg book book2
336 $ hg book book2
336 $ hg ci --amend -m 'move bookmarks'
337 $ hg ci --amend -m 'move bookmarks'
337 saved backup bundle to $TESTTMP/.hg/strip-backup/7892795b8e38-3fb46217-amend.hg (glob)
338 saved backup bundle to $TESTTMP/.hg/strip-backup/7892795b8e38-3fb46217-amend.hg (glob)
338 $ hg book
339 $ hg book
339 book1 1:8311f17e2616
340 book1 1:8311f17e2616
340 * book2 1:8311f17e2616
341 * book2 1:8311f17e2616
341 $ echo a >> a
342 $ echo a >> a
342 $ hg ci --amend -m 'move bookmarks'
343 $ hg ci --amend -m 'move bookmarks'
343 saved backup bundle to $TESTTMP/.hg/strip-backup/8311f17e2616-f0504fe3-amend.hg (glob)
344 saved backup bundle to $TESTTMP/.hg/strip-backup/8311f17e2616-f0504fe3-amend.hg (glob)
344 $ hg book
345 $ hg book
345 book1 1:a3b65065808c
346 book1 1:a3b65065808c
346 * book2 1:a3b65065808c
347 * book2 1:a3b65065808c
347
348
348 abort does not loose bookmarks
349 abort does not loose bookmarks
349
350
350 $ cat > editor.sh << '__EOF__'
351 $ cat > editor.sh << '__EOF__'
351 > #!/bin/sh
352 > #!/bin/sh
352 > echo "" > "$1"
353 > echo "" > "$1"
353 > __EOF__
354 > __EOF__
354 $ echo a >> a
355 $ echo a >> a
355 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
356 $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
356 abort: empty commit message
357 abort: empty commit message
357 [255]
358 [255]
358 $ hg book
359 $ hg book
359 book1 1:a3b65065808c
360 book1 1:a3b65065808c
360 * book2 1:a3b65065808c
361 * book2 1:a3b65065808c
361 $ hg revert -Caq
362 $ hg revert -Caq
362 $ rm editor.sh
363 $ rm editor.sh
363
364
364 $ echo '[defaults]' >> $HGRCPATH
365 $ echo '[defaults]' >> $HGRCPATH
365 $ echo "commit=-d '0 0'" >> $HGRCPATH
366 $ echo "commit=-d '0 0'" >> $HGRCPATH
366
367
367 Moving branches:
368 Moving branches:
368
369
369 $ hg branch foo
370 $ hg branch foo
370 marked working directory as branch foo
371 marked working directory as branch foo
371 (branches are permanent and global, did you want a bookmark?)
372 (branches are permanent and global, did you want a bookmark?)
372 $ echo a >> a
373 $ echo a >> a
373 $ hg ci -m 'branch foo'
374 $ hg ci -m 'branch foo'
374 $ hg branch default -f
375 $ hg branch default -f
375 marked working directory as branch default
376 marked working directory as branch default
376 $ hg ci --amend -m 'back to default'
377 $ hg ci --amend -m 'back to default'
377 saved backup bundle to $TESTTMP/.hg/strip-backup/f8339a38efe1-c18453c9-amend.hg (glob)
378 saved backup bundle to $TESTTMP/.hg/strip-backup/f8339a38efe1-c18453c9-amend.hg (glob)
378 $ hg branches
379 $ hg branches
379 default 2:9c07515f2650
380 default 2:9c07515f2650
380
381
381 Close branch:
382 Close branch:
382
383
383 $ hg up -q 0
384 $ hg up -q 0
384 $ echo b >> b
385 $ echo b >> b
385 $ hg branch foo
386 $ hg branch foo
386 marked working directory as branch foo
387 marked working directory as branch foo
387 (branches are permanent and global, did you want a bookmark?)
388 (branches are permanent and global, did you want a bookmark?)
388 $ hg ci -Am 'fork'
389 $ hg ci -Am 'fork'
389 adding b
390 adding b
390 $ echo b >> b
391 $ echo b >> b
391 $ hg ci -mb
392 $ hg ci -mb
392 $ hg ci --amend --close-branch -m 'closing branch foo'
393 $ hg ci --amend --close-branch -m 'closing branch foo'
393 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-54245dc7-amend.hg (glob)
394 saved backup bundle to $TESTTMP/.hg/strip-backup/c962248fa264-54245dc7-amend.hg (glob)
394
395
395 Same thing, different code path:
396 Same thing, different code path:
396
397
397 $ echo b >> b
398 $ echo b >> b
398 $ hg ci -m 'reopen branch'
399 $ hg ci -m 'reopen branch'
399 reopening closed branch head 4
400 reopening closed branch head 4
400 $ echo b >> b
401 $ echo b >> b
401 $ hg ci --amend --close-branch
402 $ hg ci --amend --close-branch
402 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-b900d9fa-amend.hg (glob)
403 saved backup bundle to $TESTTMP/.hg/strip-backup/027371728205-b900d9fa-amend.hg (glob)
403 $ hg branches
404 $ hg branches
404 default 2:9c07515f2650
405 default 2:9c07515f2650
405
406
406 Refuse to amend during a merge:
407 Refuse to amend during a merge:
407
408
408 $ hg up -q default
409 $ hg up -q default
409 $ hg merge foo
410 $ hg merge foo
410 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
411 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
411 (branch merge, don't forget to commit)
412 (branch merge, don't forget to commit)
412 $ hg ci --amend
413 $ hg ci --amend
413 abort: cannot amend while merging
414 abort: cannot amend while merging
414 [255]
415 [255]
415 $ hg ci -m 'merge'
416 $ hg ci -m 'merge'
416
417
417 Follow copies/renames:
418 Follow copies/renames:
418
419
419 $ hg mv b c
420 $ hg mv b c
420 $ hg ci -m 'b -> c'
421 $ hg ci -m 'b -> c'
421 $ hg mv c d
422 $ hg mv c d
422 $ hg ci --amend -m 'b -> d'
423 $ hg ci --amend -m 'b -> d'
423 saved backup bundle to $TESTTMP/.hg/strip-backup/42f3f27a067d-f23cc9f7-amend.hg (glob)
424 saved backup bundle to $TESTTMP/.hg/strip-backup/42f3f27a067d-f23cc9f7-amend.hg (glob)
424 $ hg st --rev '.^' --copies d
425 $ hg st --rev '.^' --copies d
425 A d
426 A d
426 b
427 b
427 $ hg cp d e
428 $ hg cp d e
428 $ hg ci -m 'e = d'
429 $ hg ci -m 'e = d'
429 $ hg cp e f
430 $ hg cp e f
430 $ hg ci --amend -m 'f = d'
431 $ hg ci --amend -m 'f = d'
431 saved backup bundle to $TESTTMP/.hg/strip-backup/9198f73182d5-251d584a-amend.hg (glob)
432 saved backup bundle to $TESTTMP/.hg/strip-backup/9198f73182d5-251d584a-amend.hg (glob)
432 $ hg st --rev '.^' --copies f
433 $ hg st --rev '.^' --copies f
433 A f
434 A f
434 d
435 d
435
436
436 $ mv f f.orig
437 $ mv f f.orig
437 $ hg rm -A f
438 $ hg rm -A f
438 $ hg ci -m removef
439 $ hg ci -m removef
439 $ hg cp a f
440 $ hg cp a f
440 $ mv f.orig f
441 $ mv f.orig f
441 $ hg ci --amend -m replacef
442 $ hg ci --amend -m replacef
442 saved backup bundle to $TESTTMP/.hg/strip-backup/f0993ab6b482-eda301bf-amend.hg (glob)
443 saved backup bundle to $TESTTMP/.hg/strip-backup/f0993ab6b482-eda301bf-amend.hg (glob)
443 $ hg st --change . --copies
444 $ hg st --change . --copies
444 $ hg log -r . --template "{file_copies}\n"
445 $ hg log -r . --template "{file_copies}\n"
445
446
446
447
447 Move added file (issue3410):
448 Move added file (issue3410):
448
449
449 $ echo g >> g
450 $ echo g >> g
450 $ hg ci -Am g
451 $ hg ci -Am g
451 adding g
452 adding g
452 $ hg mv g h
453 $ hg mv g h
453 $ hg ci --amend
454 $ hg ci --amend
454 saved backup bundle to $TESTTMP/.hg/strip-backup/58585e3f095c-0f5ebcda-amend.hg (glob)
455 saved backup bundle to $TESTTMP/.hg/strip-backup/58585e3f095c-0f5ebcda-amend.hg (glob)
455 $ hg st --change . --copies h
456 $ hg st --change . --copies h
456 A h
457 A h
457 $ hg log -r . --template "{file_copies}\n"
458 $ hg log -r . --template "{file_copies}\n"
458
459
459
460
460 Can't rollback an amend:
461 Can't rollback an amend:
461
462
462 $ hg rollback
463 $ hg rollback
463 no rollback information available
464 no rollback information available
464 [1]
465 [1]
465
466
466 Preserve extra dict (issue3430):
467 Preserve extra dict (issue3430):
467
468
468 $ hg branch a
469 $ hg branch a
469 marked working directory as branch a
470 marked working directory as branch a
470 (branches are permanent and global, did you want a bookmark?)
471 (branches are permanent and global, did you want a bookmark?)
471 $ echo a >> a
472 $ echo a >> a
472 $ hg ci -ma
473 $ hg ci -ma
473 $ hg ci --amend -m "a'"
474 $ hg ci --amend -m "a'"
474 saved backup bundle to $TESTTMP/.hg/strip-backup/39a162f1d65e-9dfe13d8-amend.hg (glob)
475 saved backup bundle to $TESTTMP/.hg/strip-backup/39a162f1d65e-9dfe13d8-amend.hg (glob)
475 $ hg log -r . --template "{branch}\n"
476 $ hg log -r . --template "{branch}\n"
476 a
477 a
477 $ hg ci --amend -m "a''"
478 $ hg ci --amend -m "a''"
478 saved backup bundle to $TESTTMP/.hg/strip-backup/d5ca7b1ac72b-0b4c1a34-amend.hg (glob)
479 saved backup bundle to $TESTTMP/.hg/strip-backup/d5ca7b1ac72b-0b4c1a34-amend.hg (glob)
479 $ hg log -r . --template "{branch}\n"
480 $ hg log -r . --template "{branch}\n"
480 a
481 a
481
482
482 Also preserve other entries in the dict that are in the old commit,
483 Also preserve other entries in the dict that are in the old commit,
483 first graft something so there's an additional entry:
484 first graft something so there's an additional entry:
484
485
485 $ hg up 0 -q
486 $ hg up 0 -q
486 $ echo z > z
487 $ echo z > z
487 $ hg ci -Am 'fork'
488 $ hg ci -Am 'fork'
488 adding z
489 adding z
489 created new head
490 created new head
490 $ hg up 11
491 $ hg up 11
491 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
492 5 files updated, 0 files merged, 1 files removed, 0 files unresolved
492 $ hg graft 12
493 $ hg graft 12
493 grafting 12:2647734878ef "fork" (tip)
494 grafting 12:2647734878ef "fork" (tip)
494 $ hg ci --amend -m 'graft amend'
495 $ hg ci --amend -m 'graft amend'
495 saved backup bundle to $TESTTMP/.hg/strip-backup/fe8c6f7957ca-25638666-amend.hg (glob)
496 saved backup bundle to $TESTTMP/.hg/strip-backup/fe8c6f7957ca-25638666-amend.hg (glob)
496 $ hg log -r . --debug | grep extra
497 $ hg log -r . --debug | grep extra
497 extra: amend_source=fe8c6f7957ca1665ed77496ed7a07657d469ac60
498 extra: amend_source=fe8c6f7957ca1665ed77496ed7a07657d469ac60
498 extra: branch=a
499 extra: branch=a
499 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
500 extra: source=2647734878ef0236dda712fae9c1651cf694ea8a
500
501
501 Preserve phase
502 Preserve phase
502
503
503 $ hg phase '.^::.'
504 $ hg phase '.^::.'
504 11: draft
505 11: draft
505 13: draft
506 13: draft
506 $ hg phase --secret --force .
507 $ hg phase --secret --force .
507 $ hg phase '.^::.'
508 $ hg phase '.^::.'
508 11: draft
509 11: draft
509 13: secret
510 13: secret
510 $ hg commit --amend -m 'amend for phase' -q
511 $ hg commit --amend -m 'amend for phase' -q
511 $ hg phase '.^::.'
512 $ hg phase '.^::.'
512 11: draft
513 11: draft
513 13: secret
514 13: secret
514
515
515 Test amend with obsolete
516 Test amend with obsolete
516 ---------------------------
517 ---------------------------
517
518
518 Enable obsolete
519 Enable obsolete
519
520
520 $ cat >> $HGRCPATH << EOF
521 $ cat >> $HGRCPATH << EOF
521 > [experimental]
522 > [experimental]
522 > evolution.createmarkers=True
523 > evolution.createmarkers=True
523 > evolution.allowunstable=True
524 > evolution.allowunstable=True
524 > EOF
525 > EOF
525
526
526 Amend with no files changes
527 Amend with no files changes
527
528
528 $ hg id -n
529 $ hg id -n
529 13
530 13
530 $ hg ci --amend -m 'babar'
531 $ hg ci --amend -m 'babar'
531 $ hg id -n
532 $ hg id -n
532 14
533 14
533 $ hg log -Gl 3 --style=compact
534 $ hg log -Gl 3 --style=compact
534 @ 14[tip]:11 682950e85999 1970-01-01 00:00 +0000 test
535 @ 14[tip]:11 682950e85999 1970-01-01 00:00 +0000 test
535 | babar
536 | babar
536 |
537 |
537 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
538 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
538 | | fork
539 | | fork
539 | ~
540 | ~
540 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
541 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
541 | a''
542 | a''
542 ~
543 ~
543 $ hg log -Gl 4 --hidden --style=compact
544 $ hg log -Gl 4 --hidden --style=compact
544 @ 14[tip]:11 682950e85999 1970-01-01 00:00 +0000 test
545 @ 14[tip]:11 682950e85999 1970-01-01 00:00 +0000 test
545 | babar
546 | babar
546 |
547 |
547 | x 13:11 5167600b0f7a 1970-01-01 00:00 +0000 test
548 | x 13:11 5167600b0f7a 1970-01-01 00:00 +0000 test
548 |/ amend for phase
549 |/ amend for phase
549 |
550 |
550 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
551 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
551 | | fork
552 | | fork
552 | ~
553 | ~
553 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
554 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
554 | a''
555 | a''
555 ~
556 ~
556
557
557 Amend with files changes
558 Amend with files changes
558
559
559 (note: the extra commit over 15 is a temporary junk I would be happy to get
560 (note: the extra commit over 15 is a temporary junk I would be happy to get
560 ride of)
561 ride of)
561
562
562 $ echo 'babar' >> a
563 $ echo 'babar' >> a
563 $ hg commit --amend
564 $ hg commit --amend
564 $ hg log -Gl 6 --hidden --style=compact
565 $ hg log -Gl 6 --hidden --style=compact
565 @ 15[tip]:11 a5b42b49b0d5 1970-01-01 00:00 +0000 test
566 @ 15[tip]:11 a5b42b49b0d5 1970-01-01 00:00 +0000 test
566 | babar
567 | babar
567 |
568 |
568 | x 14:11 682950e85999 1970-01-01 00:00 +0000 test
569 | x 14:11 682950e85999 1970-01-01 00:00 +0000 test
569 |/ babar
570 |/ babar
570 |
571 |
571 | x 13:11 5167600b0f7a 1970-01-01 00:00 +0000 test
572 | x 13:11 5167600b0f7a 1970-01-01 00:00 +0000 test
572 |/ amend for phase
573 |/ amend for phase
573 |
574 |
574 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
575 | o 12:0 2647734878ef 1970-01-01 00:00 +0000 test
575 | | fork
576 | | fork
576 | ~
577 | ~
577 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
578 o 11 0ddb275cfad1 1970-01-01 00:00 +0000 test
578 | a''
579 | a''
579 |
580 |
580 o 10 5fa75032e226 1970-01-01 00:00 +0000 test
581 o 10 5fa75032e226 1970-01-01 00:00 +0000 test
581 | g
582 | g
582 ~
583 ~
583
584
584
585
585 Test that amend does not make it easy to create obsolescence cycle
586 Test that amend does not make it easy to create obsolescence cycle
586 ---------------------------------------------------------------------
587 ---------------------------------------------------------------------
587
588
588 $ hg id -r 14 --hidden
589 $ hg id -r 14 --hidden
589 682950e85999 (a)
590 682950e85999 (a)
590 $ hg revert -ar 14 --hidden
591 $ hg revert -ar 14 --hidden
591 reverting a
592 reverting a
592 $ hg commit --amend
593 $ hg commit --amend
593 $ hg id
594 $ hg id
594 37973c7e0b61 (a) tip
595 37973c7e0b61 (a) tip
595
596
596 Test that rewriting leaving instability behind is allowed
597 Test that rewriting leaving instability behind is allowed
597 ---------------------------------------------------------------------
598 ---------------------------------------------------------------------
598
599
599 $ hg up '.^'
600 $ hg up '.^'
600 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
601 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
601 $ echo 'b' >> a
602 $ echo 'b' >> a
602 $ hg log --style compact -r 'children(.)'
603 $ hg log --style compact -r 'children(.)'
603 16[tip]:11 37973c7e0b61 1970-01-01 00:00 +0000 test
604 16[tip]:11 37973c7e0b61 1970-01-01 00:00 +0000 test
604 babar
605 babar
605
606
606 $ hg commit --amend
607 $ hg commit --amend
607 $ hg log -r 'orphan()'
608 $ hg log -r 'orphan()'
608 changeset: 16:37973c7e0b61
609 changeset: 16:37973c7e0b61
609 branch: a
610 branch: a
610 parent: 11:0ddb275cfad1
611 parent: 11:0ddb275cfad1
611 user: test
612 user: test
612 date: Thu Jan 01 00:00:00 1970 +0000
613 date: Thu Jan 01 00:00:00 1970 +0000
613 instability: orphan
614 instability: orphan
614 summary: babar
615 summary: babar
615
616
616
617
617 Amend a merge changeset (with renames and conflicts from the second parent):
618 Amend a merge changeset (with renames and conflicts from the second parent):
618
619
619 $ hg up -q default
620 $ hg up -q default
620 $ hg branch -q bar
621 $ hg branch -q bar
621 $ hg cp a aa
622 $ hg cp a aa
622 $ hg mv z zz
623 $ hg mv z zz
623 $ echo cc > cc
624 $ echo cc > cc
624 $ hg add cc
625 $ hg add cc
625 $ hg ci -m aazzcc
626 $ hg ci -m aazzcc
626 $ hg up -q default
627 $ hg up -q default
627 $ echo a >> a
628 $ echo a >> a
628 $ echo dd > cc
629 $ echo dd > cc
629 $ hg add cc
630 $ hg add cc
630 $ hg ci -m aa
631 $ hg ci -m aa
631 $ hg merge -q bar
632 $ hg merge -q bar
632 warning: conflicts while merging cc! (edit, then use 'hg resolve --mark')
633 warning: conflicts while merging cc! (edit, then use 'hg resolve --mark')
633 [1]
634 [1]
634 $ hg resolve -m cc
635 $ hg resolve -m cc
635 (no more unresolved files)
636 (no more unresolved files)
636 $ hg ci -m 'merge bar'
637 $ hg ci -m 'merge bar'
637 $ hg log --config diff.git=1 -pr .
638 $ hg log --config diff.git=1 -pr .
638 changeset: 20:163cfd7219f7
639 changeset: 20:163cfd7219f7
639 tag: tip
640 tag: tip
640 parent: 19:30d96aeaf27b
641 parent: 19:30d96aeaf27b
641 parent: 18:1aa437659d19
642 parent: 18:1aa437659d19
642 user: test
643 user: test
643 date: Thu Jan 01 00:00:00 1970 +0000
644 date: Thu Jan 01 00:00:00 1970 +0000
644 summary: merge bar
645 summary: merge bar
645
646
646 diff --git a/a b/aa
647 diff --git a/a b/aa
647 copy from a
648 copy from a
648 copy to aa
649 copy to aa
649 diff --git a/cc b/cc
650 diff --git a/cc b/cc
650 --- a/cc
651 --- a/cc
651 +++ b/cc
652 +++ b/cc
652 @@ -1,1 +1,5 @@
653 @@ -1,1 +1,5 @@
653 +<<<<<<< working copy: 30d96aeaf27b - test: aa
654 +<<<<<<< working copy: 30d96aeaf27b - test: aa
654 dd
655 dd
655 +=======
656 +=======
656 +cc
657 +cc
657 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
658 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
658 diff --git a/z b/zz
659 diff --git a/z b/zz
659 rename from z
660 rename from z
660 rename to zz
661 rename to zz
661
662
662 $ hg debugrename aa
663 $ hg debugrename aa
663 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
664 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
664 $ hg debugrename zz
665 $ hg debugrename zz
665 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
666 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
666 $ hg debugrename cc
667 $ hg debugrename cc
667 cc not renamed
668 cc not renamed
668 $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -m 'merge bar (amend message)' --edit
669 $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -m 'merge bar (amend message)' --edit
669 HGEDITFORM=commit.amend.merge
670 HGEDITFORM=commit.amend.merge
670 $ hg log --config diff.git=1 -pr .
671 $ hg log --config diff.git=1 -pr .
671 changeset: 21:bca52d4ed186
672 changeset: 21:bca52d4ed186
672 tag: tip
673 tag: tip
673 parent: 19:30d96aeaf27b
674 parent: 19:30d96aeaf27b
674 parent: 18:1aa437659d19
675 parent: 18:1aa437659d19
675 user: test
676 user: test
676 date: Thu Jan 01 00:00:00 1970 +0000
677 date: Thu Jan 01 00:00:00 1970 +0000
677 summary: merge bar (amend message)
678 summary: merge bar (amend message)
678
679
679 diff --git a/a b/aa
680 diff --git a/a b/aa
680 copy from a
681 copy from a
681 copy to aa
682 copy to aa
682 diff --git a/cc b/cc
683 diff --git a/cc b/cc
683 --- a/cc
684 --- a/cc
684 +++ b/cc
685 +++ b/cc
685 @@ -1,1 +1,5 @@
686 @@ -1,1 +1,5 @@
686 +<<<<<<< working copy: 30d96aeaf27b - test: aa
687 +<<<<<<< working copy: 30d96aeaf27b - test: aa
687 dd
688 dd
688 +=======
689 +=======
689 +cc
690 +cc
690 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
691 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
691 diff --git a/z b/zz
692 diff --git a/z b/zz
692 rename from z
693 rename from z
693 rename to zz
694 rename to zz
694
695
695 $ hg debugrename aa
696 $ hg debugrename aa
696 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
697 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
697 $ hg debugrename zz
698 $ hg debugrename zz
698 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
699 zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a
699 $ hg debugrename cc
700 $ hg debugrename cc
700 cc not renamed
701 cc not renamed
701 $ hg mv zz z
702 $ hg mv zz z
702 $ hg ci --amend -m 'merge bar (undo rename)'
703 $ hg ci --amend -m 'merge bar (undo rename)'
703 $ hg log --config diff.git=1 -pr .
704 $ hg log --config diff.git=1 -pr .
704 changeset: 22:12594a98ca3f
705 changeset: 22:12594a98ca3f
705 tag: tip
706 tag: tip
706 parent: 19:30d96aeaf27b
707 parent: 19:30d96aeaf27b
707 parent: 18:1aa437659d19
708 parent: 18:1aa437659d19
708 user: test
709 user: test
709 date: Thu Jan 01 00:00:00 1970 +0000
710 date: Thu Jan 01 00:00:00 1970 +0000
710 summary: merge bar (undo rename)
711 summary: merge bar (undo rename)
711
712
712 diff --git a/a b/aa
713 diff --git a/a b/aa
713 copy from a
714 copy from a
714 copy to aa
715 copy to aa
715 diff --git a/cc b/cc
716 diff --git a/cc b/cc
716 --- a/cc
717 --- a/cc
717 +++ b/cc
718 +++ b/cc
718 @@ -1,1 +1,5 @@
719 @@ -1,1 +1,5 @@
719 +<<<<<<< working copy: 30d96aeaf27b - test: aa
720 +<<<<<<< working copy: 30d96aeaf27b - test: aa
720 dd
721 dd
721 +=======
722 +=======
722 +cc
723 +cc
723 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
724 +>>>>>>> merge rev: 1aa437659d19 bar - test: aazzcc
724
725
725 $ hg debugrename z
726 $ hg debugrename z
726 z not renamed
727 z not renamed
727
728
728 Amend a merge changeset (with renames during the merge):
729 Amend a merge changeset (with renames during the merge):
729
730
730 $ hg up -q bar
731 $ hg up -q bar
731 $ echo x > x
732 $ echo x > x
732 $ hg add x
733 $ hg add x
733 $ hg ci -m x
734 $ hg ci -m x
734 $ hg up -q default
735 $ hg up -q default
735 $ hg merge -q bar
736 $ hg merge -q bar
736 $ hg mv aa aaa
737 $ hg mv aa aaa
737 $ echo aa >> aaa
738 $ echo aa >> aaa
738 $ hg ci -m 'merge bar again'
739 $ hg ci -m 'merge bar again'
739 $ hg log --config diff.git=1 -pr .
740 $ hg log --config diff.git=1 -pr .
740 changeset: 24:dffde028b388
741 changeset: 24:dffde028b388
741 tag: tip
742 tag: tip
742 parent: 22:12594a98ca3f
743 parent: 22:12594a98ca3f
743 parent: 23:4c94d5bc65f5
744 parent: 23:4c94d5bc65f5
744 user: test
745 user: test
745 date: Thu Jan 01 00:00:00 1970 +0000
746 date: Thu Jan 01 00:00:00 1970 +0000
746 summary: merge bar again
747 summary: merge bar again
747
748
748 diff --git a/aa b/aa
749 diff --git a/aa b/aa
749 deleted file mode 100644
750 deleted file mode 100644
750 --- a/aa
751 --- a/aa
751 +++ /dev/null
752 +++ /dev/null
752 @@ -1,2 +0,0 @@
753 @@ -1,2 +0,0 @@
753 -a
754 -a
754 -a
755 -a
755 diff --git a/aaa b/aaa
756 diff --git a/aaa b/aaa
756 new file mode 100644
757 new file mode 100644
757 --- /dev/null
758 --- /dev/null
758 +++ b/aaa
759 +++ b/aaa
759 @@ -0,0 +1,3 @@
760 @@ -0,0 +1,3 @@
760 +a
761 +a
761 +a
762 +a
762 +aa
763 +aa
763 diff --git a/x b/x
764 diff --git a/x b/x
764 new file mode 100644
765 new file mode 100644
765 --- /dev/null
766 --- /dev/null
766 +++ b/x
767 +++ b/x
767 @@ -0,0 +1,1 @@
768 @@ -0,0 +1,1 @@
768 +x
769 +x
769
770
770 $ hg debugrename aaa
771 $ hg debugrename aaa
771 aaa renamed from aa:37d9b5d994eab34eda9c16b195ace52c7b129980
772 aaa renamed from aa:37d9b5d994eab34eda9c16b195ace52c7b129980
772 $ hg mv aaa aa
773 $ hg mv aaa aa
773 $ hg ci --amend -m 'merge bar again (undo rename)'
774 $ hg ci --amend -m 'merge bar again (undo rename)'
774 $ hg log --config diff.git=1 -pr .
775 $ hg log --config diff.git=1 -pr .
775 changeset: 25:18e3ba160489
776 changeset: 25:18e3ba160489
776 tag: tip
777 tag: tip
777 parent: 22:12594a98ca3f
778 parent: 22:12594a98ca3f
778 parent: 23:4c94d5bc65f5
779 parent: 23:4c94d5bc65f5
779 user: test
780 user: test
780 date: Thu Jan 01 00:00:00 1970 +0000
781 date: Thu Jan 01 00:00:00 1970 +0000
781 summary: merge bar again (undo rename)
782 summary: merge bar again (undo rename)
782
783
783 diff --git a/aa b/aa
784 diff --git a/aa b/aa
784 --- a/aa
785 --- a/aa
785 +++ b/aa
786 +++ b/aa
786 @@ -1,2 +1,3 @@
787 @@ -1,2 +1,3 @@
787 a
788 a
788 a
789 a
789 +aa
790 +aa
790 diff --git a/x b/x
791 diff --git a/x b/x
791 new file mode 100644
792 new file mode 100644
792 --- /dev/null
793 --- /dev/null
793 +++ b/x
794 +++ b/x
794 @@ -0,0 +1,1 @@
795 @@ -0,0 +1,1 @@
795 +x
796 +x
796
797
797 $ hg debugrename aa
798 $ hg debugrename aa
798 aa not renamed
799 aa not renamed
799 $ hg debugrename -r '.^' aa
800 $ hg debugrename -r '.^' aa
800 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
801 aa renamed from a:a80d06849b333b8a3d5c445f8ba3142010dcdc9e
801
802
802 Amend a merge changeset (with manifest-level conflicts):
803 Amend a merge changeset (with manifest-level conflicts):
803
804
804 $ hg up -q bar
805 $ hg up -q bar
805 $ hg rm aa
806 $ hg rm aa
806 $ hg ci -m 'rm aa'
807 $ hg ci -m 'rm aa'
807 $ hg up -q default
808 $ hg up -q default
808 $ echo aa >> aa
809 $ echo aa >> aa
809 $ hg ci -m aa
810 $ hg ci -m aa
810 $ hg merge -q bar --config ui.interactive=True << EOF
811 $ hg merge -q bar --config ui.interactive=True << EOF
811 > c
812 > c
812 > EOF
813 > EOF
813 local [working copy] changed aa which other [merge rev] deleted
814 local [working copy] changed aa which other [merge rev] deleted
814 use (c)hanged version, (d)elete, or leave (u)nresolved? c
815 use (c)hanged version, (d)elete, or leave (u)nresolved? c
815 $ hg ci -m 'merge bar (with conflicts)'
816 $ hg ci -m 'merge bar (with conflicts)'
816 $ hg log --config diff.git=1 -pr .
817 $ hg log --config diff.git=1 -pr .
817 changeset: 28:b4c3035e2544
818 changeset: 28:b4c3035e2544
818 tag: tip
819 tag: tip
819 parent: 27:4b216ca5ba97
820 parent: 27:4b216ca5ba97
820 parent: 26:67db8847a540
821 parent: 26:67db8847a540
821 user: test
822 user: test
822 date: Thu Jan 01 00:00:00 1970 +0000
823 date: Thu Jan 01 00:00:00 1970 +0000
823 summary: merge bar (with conflicts)
824 summary: merge bar (with conflicts)
824
825
825
826
826 $ hg rm aa
827 $ hg rm aa
827 $ hg ci --amend -m 'merge bar (with conflicts, amended)'
828 $ hg ci --amend -m 'merge bar (with conflicts, amended)'
828 $ hg log --config diff.git=1 -pr .
829 $ hg log --config diff.git=1 -pr .
829 changeset: 29:1205ed810051
830 changeset: 29:1205ed810051
830 tag: tip
831 tag: tip
831 parent: 27:4b216ca5ba97
832 parent: 27:4b216ca5ba97
832 parent: 26:67db8847a540
833 parent: 26:67db8847a540
833 user: test
834 user: test
834 date: Thu Jan 01 00:00:00 1970 +0000
835 date: Thu Jan 01 00:00:00 1970 +0000
835 summary: merge bar (with conflicts, amended)
836 summary: merge bar (with conflicts, amended)
836
837
837 diff --git a/aa b/aa
838 diff --git a/aa b/aa
838 deleted file mode 100644
839 deleted file mode 100644
839 --- a/aa
840 --- a/aa
840 +++ /dev/null
841 +++ /dev/null
841 @@ -1,4 +0,0 @@
842 @@ -1,4 +0,0 @@
842 -a
843 -a
843 -a
844 -a
844 -aa
845 -aa
845 -aa
846 -aa
846
847
847 Issue 3445: amending with --close-branch a commit that created a new head should fail
848 Issue 3445: amending with --close-branch a commit that created a new head should fail
848 This shouldn't be possible:
849 This shouldn't be possible:
849
850
850 $ hg up -q default
851 $ hg up -q default
851 $ hg branch closewithamend
852 $ hg branch closewithamend
852 marked working directory as branch closewithamend
853 marked working directory as branch closewithamend
853 $ echo foo > foo
854 $ echo foo > foo
854 $ hg add foo
855 $ hg add foo
855 $ hg ci -m..
856 $ hg ci -m..
856 $ hg ci --amend --close-branch -m 'closing'
857 $ hg ci --amend --close-branch -m 'closing'
857 abort: can only close branch heads
858 abort: can only close branch heads
858 [255]
859 [255]
859
860
860 This silliness fails:
861 This silliness fails:
861
862
862 $ hg branch silliness
863 $ hg branch silliness
863 marked working directory as branch silliness
864 marked working directory as branch silliness
864 $ echo b >> b
865 $ echo b >> b
865 $ hg ci --close-branch -m'open and close'
866 $ hg ci --close-branch -m'open and close'
866 abort: can only close branch heads
867 abort: can only close branch heads
867 [255]
868 [255]
868
869
869 Test that amend with --secret creates new secret changeset forcibly
870 Test that amend with --secret creates new secret changeset forcibly
870 ---------------------------------------------------------------------
871 ---------------------------------------------------------------------
871
872
872 $ hg phase '.^::.'
873 $ hg phase '.^::.'
873 29: draft
874 29: draft
874 30: draft
875 30: draft
875 $ hg commit --amend --secret -m 'amend as secret' -q
876 $ hg commit --amend --secret -m 'amend as secret' -q
876 $ hg phase '.^::.'
877 $ hg phase '.^::.'
877 29: draft
878 29: draft
878 31: secret
879 31: secret
879
880
880 Test that amend with --edit invokes editor forcibly
881 Test that amend with --edit invokes editor forcibly
881 ---------------------------------------------------
882 ---------------------------------------------------
882
883
883 $ hg parents --template "{desc}\n"
884 $ hg parents --template "{desc}\n"
884 amend as secret
885 amend as secret
885 $ HGEDITOR=cat hg commit --amend -m "editor should be suppressed"
886 $ HGEDITOR=cat hg commit --amend -m "editor should be suppressed"
886 $ hg parents --template "{desc}\n"
887 $ hg parents --template "{desc}\n"
887 editor should be suppressed
888 editor should be suppressed
888
889
889 $ hg status --rev '.^1::.'
890 $ hg status --rev '.^1::.'
890 A foo
891 A foo
891 $ HGEDITOR=cat hg commit --amend -m "editor should be invoked" --edit
892 $ HGEDITOR=cat hg commit --amend -m "editor should be invoked" --edit
892 editor should be invoked
893 editor should be invoked
893
894
894
895
895 HG: Enter commit message. Lines beginning with 'HG:' are removed.
896 HG: Enter commit message. Lines beginning with 'HG:' are removed.
896 HG: Leave message empty to abort commit.
897 HG: Leave message empty to abort commit.
897 HG: --
898 HG: --
898 HG: user: test
899 HG: user: test
899 HG: branch 'silliness'
900 HG: branch 'silliness'
900 HG: added foo
901 HG: added foo
901 $ hg parents --template "{desc}\n"
902 $ hg parents --template "{desc}\n"
902 editor should be invoked
903 editor should be invoked
903
904
904 Test that "diff()" in committemplate works correctly for amending
905 Test that "diff()" in committemplate works correctly for amending
905 -----------------------------------------------------------------
906 -----------------------------------------------------------------
906
907
907 $ cat >> .hg/hgrc <<EOF
908 $ cat >> .hg/hgrc <<EOF
908 > [committemplate]
909 > [committemplate]
909 > changeset.commit.amend = {desc}\n
910 > changeset.commit.amend = {desc}\n
910 > HG: M: {file_mods}
911 > HG: M: {file_mods}
911 > HG: A: {file_adds}
912 > HG: A: {file_adds}
912 > HG: R: {file_dels}
913 > HG: R: {file_dels}
913 > {splitlines(diff()) % 'HG: {line}\n'}
914 > {splitlines(diff()) % 'HG: {line}\n'}
914 > EOF
915 > EOF
915
916
916 $ hg parents --template "M: {file_mods}\nA: {file_adds}\nR: {file_dels}\n"
917 $ hg parents --template "M: {file_mods}\nA: {file_adds}\nR: {file_dels}\n"
917 M:
918 M:
918 A: foo
919 A: foo
919 R:
920 R:
920 $ hg status -amr
921 $ hg status -amr
921 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of foo"
922 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of foo"
922 expecting diff of foo
923 expecting diff of foo
923
924
924 HG: M:
925 HG: M:
925 HG: A: foo
926 HG: A: foo
926 HG: R:
927 HG: R:
927 HG: diff -r 1205ed810051 foo
928 HG: diff -r 1205ed810051 foo
928 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
929 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
929 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
930 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
930 HG: @@ -0,0 +1,1 @@
931 HG: @@ -0,0 +1,1 @@
931 HG: +foo
932 HG: +foo
932
933
933 $ echo y > y
934 $ echo y > y
934 $ hg add y
935 $ hg add y
935 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of foo and y"
936 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of foo and y"
936 expecting diff of foo and y
937 expecting diff of foo and y
937
938
938 HG: M:
939 HG: M:
939 HG: A: foo y
940 HG: A: foo y
940 HG: R:
941 HG: R:
941 HG: diff -r 1205ed810051 foo
942 HG: diff -r 1205ed810051 foo
942 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
943 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
943 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
944 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
944 HG: @@ -0,0 +1,1 @@
945 HG: @@ -0,0 +1,1 @@
945 HG: +foo
946 HG: +foo
946 HG: diff -r 1205ed810051 y
947 HG: diff -r 1205ed810051 y
947 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
948 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
948 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
949 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
949 HG: @@ -0,0 +1,1 @@
950 HG: @@ -0,0 +1,1 @@
950 HG: +y
951 HG: +y
951
952
952 $ hg rm a
953 $ hg rm a
953 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of a, foo and y"
954 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of a, foo and y"
954 expecting diff of a, foo and y
955 expecting diff of a, foo and y
955
956
956 HG: M:
957 HG: M:
957 HG: A: foo y
958 HG: A: foo y
958 HG: R: a
959 HG: R: a
959 HG: diff -r 1205ed810051 a
960 HG: diff -r 1205ed810051 a
960 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
961 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
961 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
962 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
962 HG: @@ -1,2 +0,0 @@
963 HG: @@ -1,2 +0,0 @@
963 HG: -a
964 HG: -a
964 HG: -a
965 HG: -a
965 HG: diff -r 1205ed810051 foo
966 HG: diff -r 1205ed810051 foo
966 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
967 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
967 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
968 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
968 HG: @@ -0,0 +1,1 @@
969 HG: @@ -0,0 +1,1 @@
969 HG: +foo
970 HG: +foo
970 HG: diff -r 1205ed810051 y
971 HG: diff -r 1205ed810051 y
971 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
972 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
972 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
973 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
973 HG: @@ -0,0 +1,1 @@
974 HG: @@ -0,0 +1,1 @@
974 HG: +y
975 HG: +y
975
976
976 $ hg rm x
977 $ hg rm x
977 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of a, foo, x and y"
978 $ HGEDITOR=cat hg commit --amend -e -m "expecting diff of a, foo, x and y"
978 expecting diff of a, foo, x and y
979 expecting diff of a, foo, x and y
979
980
980 HG: M:
981 HG: M:
981 HG: A: foo y
982 HG: A: foo y
982 HG: R: a x
983 HG: R: a x
983 HG: diff -r 1205ed810051 a
984 HG: diff -r 1205ed810051 a
984 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
985 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
985 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
986 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
986 HG: @@ -1,2 +0,0 @@
987 HG: @@ -1,2 +0,0 @@
987 HG: -a
988 HG: -a
988 HG: -a
989 HG: -a
989 HG: diff -r 1205ed810051 foo
990 HG: diff -r 1205ed810051 foo
990 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
991 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
991 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
992 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
992 HG: @@ -0,0 +1,1 @@
993 HG: @@ -0,0 +1,1 @@
993 HG: +foo
994 HG: +foo
994 HG: diff -r 1205ed810051 x
995 HG: diff -r 1205ed810051 x
995 HG: --- a/x Thu Jan 01 00:00:00 1970 +0000
996 HG: --- a/x Thu Jan 01 00:00:00 1970 +0000
996 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
997 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
997 HG: @@ -1,1 +0,0 @@
998 HG: @@ -1,1 +0,0 @@
998 HG: -x
999 HG: -x
999 HG: diff -r 1205ed810051 y
1000 HG: diff -r 1205ed810051 y
1000 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1001 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1001 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
1002 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
1002 HG: @@ -0,0 +1,1 @@
1003 HG: @@ -0,0 +1,1 @@
1003 HG: +y
1004 HG: +y
1004
1005
1005 $ echo cccc >> cc
1006 $ echo cccc >> cc
1006 $ hg status -amr
1007 $ hg status -amr
1007 M cc
1008 M cc
1008 $ HGEDITOR=cat hg commit --amend -e -m "cc should be excluded" -X cc
1009 $ HGEDITOR=cat hg commit --amend -e -m "cc should be excluded" -X cc
1009 cc should be excluded
1010 cc should be excluded
1010
1011
1011 HG: M:
1012 HG: M:
1012 HG: A: foo y
1013 HG: A: foo y
1013 HG: R: a x
1014 HG: R: a x
1014 HG: diff -r 1205ed810051 a
1015 HG: diff -r 1205ed810051 a
1015 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
1016 HG: --- a/a Thu Jan 01 00:00:00 1970 +0000
1016 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1017 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1017 HG: @@ -1,2 +0,0 @@
1018 HG: @@ -1,2 +0,0 @@
1018 HG: -a
1019 HG: -a
1019 HG: -a
1020 HG: -a
1020 HG: diff -r 1205ed810051 foo
1021 HG: diff -r 1205ed810051 foo
1021 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1022 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1022 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
1023 HG: +++ b/foo Thu Jan 01 00:00:00 1970 +0000
1023 HG: @@ -0,0 +1,1 @@
1024 HG: @@ -0,0 +1,1 @@
1024 HG: +foo
1025 HG: +foo
1025 HG: diff -r 1205ed810051 x
1026 HG: diff -r 1205ed810051 x
1026 HG: --- a/x Thu Jan 01 00:00:00 1970 +0000
1027 HG: --- a/x Thu Jan 01 00:00:00 1970 +0000
1027 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1028 HG: +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1028 HG: @@ -1,1 +0,0 @@
1029 HG: @@ -1,1 +0,0 @@
1029 HG: -x
1030 HG: -x
1030 HG: diff -r 1205ed810051 y
1031 HG: diff -r 1205ed810051 y
1031 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1032 HG: --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1032 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
1033 HG: +++ b/y Thu Jan 01 00:00:00 1970 +0000
1033 HG: @@ -0,0 +1,1 @@
1034 HG: @@ -0,0 +1,1 @@
1034 HG: +y
1035 HG: +y
1035
1036
1036 Check for issue4405
1037 Check for issue4405
1037 -------------------
1038 -------------------
1038
1039
1039 Setup the repo with a file that gets moved in a second commit.
1040 Setup the repo with a file that gets moved in a second commit.
1040 $ hg init repo
1041 $ hg init repo
1041 $ cd repo
1042 $ cd repo
1042 $ touch a0
1043 $ touch a0
1043 $ hg add a0
1044 $ hg add a0
1044 $ hg commit -m a0
1045 $ hg commit -m a0
1045 $ hg mv a0 a1
1046 $ hg mv a0 a1
1046 $ hg commit -m a1
1047 $ hg commit -m a1
1047 $ hg up -q 0
1048 $ hg up -q 0
1048 $ hg log -G --template '{rev} {desc}'
1049 $ hg log -G --template '{rev} {desc}'
1049 o 1 a1
1050 o 1 a1
1050 |
1051 |
1051 @ 0 a0
1052 @ 0 a0
1052
1053
1053
1054
1054 Now we branch the repro, but re-use the file contents, so we have a divergence
1055 Now we branch the repro, but re-use the file contents, so we have a divergence
1055 in the file revlog topology and the changelog topology.
1056 in the file revlog topology and the changelog topology.
1056 $ hg revert --rev 1 --all
1057 $ hg revert --rev 1 --all
1057 removing a0
1058 removing a0
1058 adding a1
1059 adding a1
1059 $ hg ci -qm 'a1-amend'
1060 $ hg ci -qm 'a1-amend'
1060 $ hg log -G --template '{rev} {desc}'
1061 $ hg log -G --template '{rev} {desc}'
1061 @ 2 a1-amend
1062 @ 2 a1-amend
1062 |
1063 |
1063 | o 1 a1
1064 | o 1 a1
1064 |/
1065 |/
1065 o 0 a0
1066 o 0 a0
1066
1067
1067
1068
1068 The way mercurial does amends is by folding the working copy and old commit
1069 The way mercurial does amends is by folding the working copy and old commit
1069 together into another commit (rev 3). During this process, _findlimit is called
1070 together into another commit (rev 3). During this process, _findlimit is called
1070 to check how far back to look for the transitive closure of file copy
1071 to check how far back to look for the transitive closure of file copy
1071 information, but due to the divergence of the filelog and changelog graph
1072 information, but due to the divergence of the filelog and changelog graph
1072 topologies, before _findlimit was fixed, it returned a rev which was not far
1073 topologies, before _findlimit was fixed, it returned a rev which was not far
1073 enough back in this case.
1074 enough back in this case.
1074 $ hg mv a1 a2
1075 $ hg mv a1 a2
1075 $ hg status --copies --rev 0
1076 $ hg status --copies --rev 0
1076 A a2
1077 A a2
1077 a0
1078 a0
1078 R a0
1079 R a0
1079 $ hg ci --amend -q
1080 $ hg ci --amend -q
1080 $ hg log -G --template '{rev} {desc}'
1081 $ hg log -G --template '{rev} {desc}'
1081 @ 3 a1-amend
1082 @ 3 a1-amend
1082 |
1083 |
1083 | o 1 a1
1084 | o 1 a1
1084 |/
1085 |/
1085 o 0 a0
1086 o 0 a0
1086
1087
1087
1088
1088 Before the fix, the copy information was lost.
1089 Before the fix, the copy information was lost.
1089 $ hg status --copies --rev 0
1090 $ hg status --copies --rev 0
1090 A a2
1091 A a2
1091 a0
1092 a0
1092 R a0
1093 R a0
1093 $ cd ..
1094 $ cd ..
1094
1095
1095 Check that amend properly preserve rename from directory rename (issue-4516)
1096 Check that amend properly preserve rename from directory rename (issue-4516)
1096
1097
1097 If a parent of the merge renames a full directory, any files added to the old
1098 If a parent of the merge renames a full directory, any files added to the old
1098 directory in the other parent will be renamed to the new directory. For some
1099 directory in the other parent will be renamed to the new directory. For some
1099 reason, the rename metadata was when amending such merge. This test ensure we
1100 reason, the rename metadata was when amending such merge. This test ensure we
1100 do not regress. We have a dedicated repo because it needs a setup with renamed
1101 do not regress. We have a dedicated repo because it needs a setup with renamed
1101 directory)
1102 directory)
1102
1103
1103 $ hg init issue4516
1104 $ hg init issue4516
1104 $ cd issue4516
1105 $ cd issue4516
1105 $ mkdir olddirname
1106 $ mkdir olddirname
1106 $ echo line1 > olddirname/commonfile.py
1107 $ echo line1 > olddirname/commonfile.py
1107 $ hg add olddirname/commonfile.py
1108 $ hg add olddirname/commonfile.py
1108 $ hg ci -m first
1109 $ hg ci -m first
1109
1110
1110 $ hg branch newdirname
1111 $ hg branch newdirname
1111 marked working directory as branch newdirname
1112 marked working directory as branch newdirname
1112 (branches are permanent and global, did you want a bookmark?)
1113 (branches are permanent and global, did you want a bookmark?)
1113 $ hg mv olddirname newdirname
1114 $ hg mv olddirname newdirname
1114 moving olddirname/commonfile.py to newdirname/commonfile.py (glob)
1115 moving olddirname/commonfile.py to newdirname/commonfile.py (glob)
1115 $ hg ci -m rename
1116 $ hg ci -m rename
1116
1117
1117 $ hg update default
1118 $ hg update default
1118 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1119 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1119 $ echo line1 > olddirname/newfile.py
1120 $ echo line1 > olddirname/newfile.py
1120 $ hg add olddirname/newfile.py
1121 $ hg add olddirname/newfile.py
1121 $ hg ci -m log
1122 $ hg ci -m log
1122
1123
1123 $ hg up newdirname
1124 $ hg up newdirname
1124 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1125 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1125 $ # create newdirname/newfile.py
1126 $ # create newdirname/newfile.py
1126 $ hg merge default
1127 $ hg merge default
1127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1128 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1128 (branch merge, don't forget to commit)
1129 (branch merge, don't forget to commit)
1129 $ hg ci -m add
1130 $ hg ci -m add
1130 $
1131 $
1131 $ hg debugrename newdirname/newfile.py
1132 $ hg debugrename newdirname/newfile.py
1132 newdirname/newfile.py renamed from olddirname/newfile.py:690b295714aed510803d3020da9c70fca8336def (glob)
1133 newdirname/newfile.py renamed from olddirname/newfile.py:690b295714aed510803d3020da9c70fca8336def (glob)
1133 $ hg status -C --change .
1134 $ hg status -C --change .
1134 A newdirname/newfile.py
1135 A newdirname/newfile.py
1135 $ hg status -C --rev 1
1136 $ hg status -C --rev 1
1136 A newdirname/newfile.py
1137 A newdirname/newfile.py
1137 $ hg status -C --rev 2
1138 $ hg status -C --rev 2
1138 A newdirname/commonfile.py
1139 A newdirname/commonfile.py
1139 olddirname/commonfile.py
1140 olddirname/commonfile.py
1140 A newdirname/newfile.py
1141 A newdirname/newfile.py
1141 olddirname/newfile.py
1142 olddirname/newfile.py
1142 R olddirname/commonfile.py
1143 R olddirname/commonfile.py
1143 R olddirname/newfile.py
1144 R olddirname/newfile.py
1144 $ hg debugindex newdirname/newfile.py
1145 $ hg debugindex newdirname/newfile.py
1145 rev offset length delta linkrev nodeid p1 p2
1146 rev offset length delta linkrev nodeid p1 p2
1146 0 0 89 -1 3 34a4d536c0c0 000000000000 000000000000
1147 0 0 89 -1 3 34a4d536c0c0 000000000000 000000000000
1147
1148
1148 $ echo a >> newdirname/commonfile.py
1149 $ echo a >> newdirname/commonfile.py
1149 $ hg ci --amend -m bug
1150 $ hg ci --amend -m bug
1150 $ hg debugrename newdirname/newfile.py
1151 $ hg debugrename newdirname/newfile.py
1151 newdirname/newfile.py renamed from olddirname/newfile.py:690b295714aed510803d3020da9c70fca8336def (glob)
1152 newdirname/newfile.py renamed from olddirname/newfile.py:690b295714aed510803d3020da9c70fca8336def (glob)
1152 $ hg debugindex newdirname/newfile.py
1153 $ hg debugindex newdirname/newfile.py
1153 rev offset length delta linkrev nodeid p1 p2
1154 rev offset length delta linkrev nodeid p1 p2
1154 0 0 89 -1 3 34a4d536c0c0 000000000000 000000000000
1155 0 0 89 -1 3 34a4d536c0c0 000000000000 000000000000
1155
1156
1156 #if execbit
1157 #if execbit
1157
1158
1158 Test if amend preserves executable bit changes
1159 Test if amend preserves executable bit changes
1159 $ chmod +x newdirname/commonfile.py
1160 $ chmod +x newdirname/commonfile.py
1160 $ hg ci -m chmod
1161 $ hg ci -m chmod
1161 $ hg ci --amend -m "chmod amended"
1162 $ hg ci --amend -m "chmod amended"
1162 $ hg ci --amend -m "chmod amended second time"
1163 $ hg ci --amend -m "chmod amended second time"
1163 $ hg log -p --git -r .
1164 $ hg log -p --git -r .
1164 changeset: 7:b1326f52dddf
1165 changeset: 7:b1326f52dddf
1165 branch: newdirname
1166 branch: newdirname
1166 tag: tip
1167 tag: tip
1167 parent: 4:7fd235f7cb2f
1168 parent: 4:7fd235f7cb2f
1168 user: test
1169 user: test
1169 date: Thu Jan 01 00:00:00 1970 +0000
1170 date: Thu Jan 01 00:00:00 1970 +0000
1170 summary: chmod amended second time
1171 summary: chmod amended second time
1171
1172
1172 diff --git a/newdirname/commonfile.py b/newdirname/commonfile.py
1173 diff --git a/newdirname/commonfile.py b/newdirname/commonfile.py
1173 old mode 100644
1174 old mode 100644
1174 new mode 100755
1175 new mode 100755
1175
1176
1176 #endif
1177 #endif
1177
1178
1178 Test amend with file inclusion options
1179 Test amend with file inclusion options
1179 --------------------------------------
1180 --------------------------------------
1180
1181
1181 These tests ensure that we are always amending some files that were part of the
1182 These tests ensure that we are always amending some files that were part of the
1182 pre-amend commit. We want to test that the remaining files in the pre-amend
1183 pre-amend commit. We want to test that the remaining files in the pre-amend
1183 commit were not changed in the amended commit. We do so by performing a diff of
1184 commit were not changed in the amended commit. We do so by performing a diff of
1184 the amended commit against its parent commit.
1185 the amended commit against its parent commit.
1185 $ cd ..
1186 $ cd ..
1186 $ hg init testfileinclusions
1187 $ hg init testfileinclusions
1187 $ cd testfileinclusions
1188 $ cd testfileinclusions
1188 $ echo a > a
1189 $ echo a > a
1189 $ echo b > b
1190 $ echo b > b
1190 $ hg commit -Aqm "Adding a and b"
1191 $ hg commit -Aqm "Adding a and b"
1191
1192
1192 Only add changes to a particular file
1193 Only add changes to a particular file
1193 $ echo a >> a
1194 $ echo a >> a
1194 $ echo b >> b
1195 $ echo b >> b
1195 $ hg commit --amend -I a
1196 $ hg commit --amend -I a
1196 $ hg diff --git -r null -r .
1197 $ hg diff --git -r null -r .
1197 diff --git a/a b/a
1198 diff --git a/a b/a
1198 new file mode 100644
1199 new file mode 100644
1199 --- /dev/null
1200 --- /dev/null
1200 +++ b/a
1201 +++ b/a
1201 @@ -0,0 +1,2 @@
1202 @@ -0,0 +1,2 @@
1202 +a
1203 +a
1203 +a
1204 +a
1204 diff --git a/b b/b
1205 diff --git a/b b/b
1205 new file mode 100644
1206 new file mode 100644
1206 --- /dev/null
1207 --- /dev/null
1207 +++ b/b
1208 +++ b/b
1208 @@ -0,0 +1,1 @@
1209 @@ -0,0 +1,1 @@
1209 +b
1210 +b
1210
1211
1211 $ echo a >> a
1212 $ echo a >> a
1212 $ hg commit --amend b
1213 $ hg commit --amend b
1213 $ hg diff --git -r null -r .
1214 $ hg diff --git -r null -r .
1214 diff --git a/a b/a
1215 diff --git a/a b/a
1215 new file mode 100644
1216 new file mode 100644
1216 --- /dev/null
1217 --- /dev/null
1217 +++ b/a
1218 +++ b/a
1218 @@ -0,0 +1,2 @@
1219 @@ -0,0 +1,2 @@
1219 +a
1220 +a
1220 +a
1221 +a
1221 diff --git a/b b/b
1222 diff --git a/b b/b
1222 new file mode 100644
1223 new file mode 100644
1223 --- /dev/null
1224 --- /dev/null
1224 +++ b/b
1225 +++ b/b
1225 @@ -0,0 +1,2 @@
1226 @@ -0,0 +1,2 @@
1226 +b
1227 +b
1227 +b
1228 +b
1228
1229
1229 Exclude changes to a particular file
1230 Exclude changes to a particular file
1230 $ echo b >> b
1231 $ echo b >> b
1231 $ hg commit --amend -X a
1232 $ hg commit --amend -X a
1232 $ hg diff --git -r null -r .
1233 $ hg diff --git -r null -r .
1233 diff --git a/a b/a
1234 diff --git a/a b/a
1234 new file mode 100644
1235 new file mode 100644
1235 --- /dev/null
1236 --- /dev/null
1236 +++ b/a
1237 +++ b/a
1237 @@ -0,0 +1,2 @@
1238 @@ -0,0 +1,2 @@
1238 +a
1239 +a
1239 +a
1240 +a
1240 diff --git a/b b/b
1241 diff --git a/b b/b
1241 new file mode 100644
1242 new file mode 100644
1242 --- /dev/null
1243 --- /dev/null
1243 +++ b/b
1244 +++ b/b
1244 @@ -0,0 +1,3 @@
1245 @@ -0,0 +1,3 @@
1245 +b
1246 +b
1246 +b
1247 +b
1247 +b
1248 +b
1248
1249
1249 Check the addremove flag
1250 Check the addremove flag
1250 $ echo c > c
1251 $ echo c > c
1251 $ rm a
1252 $ rm a
1252 $ hg commit --amend -A
1253 $ hg commit --amend -A
1253 removing a
1254 removing a
1254 adding c
1255 adding c
1255 $ hg diff --git -r null -r .
1256 $ hg diff --git -r null -r .
1256 diff --git a/b b/b
1257 diff --git a/b b/b
1257 new file mode 100644
1258 new file mode 100644
1258 --- /dev/null
1259 --- /dev/null
1259 +++ b/b
1260 +++ b/b
1260 @@ -0,0 +1,3 @@
1261 @@ -0,0 +1,3 @@
1261 +b
1262 +b
1262 +b
1263 +b
1263 +b
1264 +b
1264 diff --git a/c b/c
1265 diff --git a/c b/c
1265 new file mode 100644
1266 new file mode 100644
1266 --- /dev/null
1267 --- /dev/null
1267 +++ b/c
1268 +++ b/c
1268 @@ -0,0 +1,1 @@
1269 @@ -0,0 +1,1 @@
1269 +c
1270 +c
@@ -1,385 +1,386 b''
1 Test uncommit - set up the config
1 Test uncommit - set up the config
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [experimental]
4 > [experimental]
5 > evolution.createmarkers=True
5 > evolution.createmarkers=True
6 > evolution.allowunstable=True
6 > evolution.allowunstable=True
7 > [extensions]
7 > [extensions]
8 > uncommit =
8 > uncommit =
9 > drawdag=$TESTDIR/drawdag.py
9 > drawdag=$TESTDIR/drawdag.py
10 > EOF
10 > EOF
11
11
12 Build up a repo
12 Build up a repo
13
13
14 $ hg init repo
14 $ hg init repo
15 $ cd repo
15 $ cd repo
16 $ hg bookmark foo
16 $ hg bookmark foo
17
17
18 Help for uncommit
18 Help for uncommit
19
19
20 $ hg help uncommit
20 $ hg help uncommit
21 hg uncommit [OPTION]... [FILE]...
21 hg uncommit [OPTION]... [FILE]...
22
22
23 uncommit part or all of a local changeset
23 uncommit part or all of a local changeset
24
24
25 This command undoes the effect of a local commit, returning the affected
25 This command undoes the effect of a local commit, returning the affected
26 files to their uncommitted state. This means that files modified or
26 files to their uncommitted state. This means that files modified or
27 deleted in the changeset will be left unchanged, and so will remain
27 deleted in the changeset will be left unchanged, and so will remain
28 modified in the working directory.
28 modified in the working directory.
29
29
30 (use 'hg help -e uncommit' to show help for the uncommit extension)
30 (use 'hg help -e uncommit' to show help for the uncommit extension)
31
31
32 options ([+] can be repeated):
32 options ([+] can be repeated):
33
33
34 --keep allow an empty commit after uncommiting
34 --keep allow an empty commit after uncommiting
35 -I --include PATTERN [+] include names matching the given patterns
35 -I --include PATTERN [+] include names matching the given patterns
36 -X --exclude PATTERN [+] exclude names matching the given patterns
36 -X --exclude PATTERN [+] exclude names matching the given patterns
37
37
38 (some details hidden, use --verbose to show complete help)
38 (some details hidden, use --verbose to show complete help)
39
39
40 Uncommit with no commits should fail
40 Uncommit with no commits should fail
41
41
42 $ hg uncommit
42 $ hg uncommit
43 abort: cannot uncommit null changeset
43 abort: cannot uncommit null changeset
44 (no changeset checked out)
44 [255]
45 [255]
45
46
46 Create some commits
47 Create some commits
47
48
48 $ touch files
49 $ touch files
49 $ hg add files
50 $ hg add files
50 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
51 $ for i in a ab abc abcd abcde; do echo $i > files; echo $i > file-$i; hg add file-$i; hg commit -m "added file-$i"; done
51 $ ls
52 $ ls
52 file-a
53 file-a
53 file-ab
54 file-ab
54 file-abc
55 file-abc
55 file-abcd
56 file-abcd
56 file-abcde
57 file-abcde
57 files
58 files
58
59
59 $ hg log -G -T '{rev}:{node} {desc}' --hidden
60 $ hg log -G -T '{rev}:{node} {desc}' --hidden
60 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
61 @ 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
61 |
62 |
62 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
63 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
63 |
64 |
64 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
65 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
65 |
66 |
66 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
67 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
67 |
68 |
68 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
69 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
69
70
70 Simple uncommit off the top, also moves bookmark
71 Simple uncommit off the top, also moves bookmark
71
72
72 $ hg bookmark
73 $ hg bookmark
73 * foo 4:6c4fd43ed714
74 * foo 4:6c4fd43ed714
74 $ hg uncommit
75 $ hg uncommit
75 $ hg status
76 $ hg status
76 M files
77 M files
77 A file-abcde
78 A file-abcde
78 $ hg bookmark
79 $ hg bookmark
79 * foo 3:6db330d65db4
80 * foo 3:6db330d65db4
80
81
81 $ hg log -G -T '{rev}:{node} {desc}' --hidden
82 $ hg log -G -T '{rev}:{node} {desc}' --hidden
82 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
83 x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
83 |
84 |
84 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
85 @ 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
85 |
86 |
86 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
87 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
87 |
88 |
88 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
89 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
89 |
90 |
90 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
91 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
91
92
92
93
93 Recommit
94 Recommit
94
95
95 $ hg commit -m 'new change abcde'
96 $ hg commit -m 'new change abcde'
96 $ hg status
97 $ hg status
97 $ hg heads -T '{rev}:{node} {desc}'
98 $ hg heads -T '{rev}:{node} {desc}'
98 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
99 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde (no-eol)
99
100
100 Uncommit of non-existent and unchanged files has no effect
101 Uncommit of non-existent and unchanged files has no effect
101 $ hg uncommit nothinghere
102 $ hg uncommit nothinghere
102 nothing to uncommit
103 nothing to uncommit
103 [1]
104 [1]
104 $ hg status
105 $ hg status
105 $ hg uncommit file-abc
106 $ hg uncommit file-abc
106 nothing to uncommit
107 nothing to uncommit
107 [1]
108 [1]
108 $ hg status
109 $ hg status
109
110
110 Try partial uncommit, also moves bookmark
111 Try partial uncommit, also moves bookmark
111
112
112 $ hg bookmark
113 $ hg bookmark
113 * foo 5:0c07a3ccda77
114 * foo 5:0c07a3ccda77
114 $ hg uncommit files
115 $ hg uncommit files
115 $ hg status
116 $ hg status
116 M files
117 M files
117 $ hg bookmark
118 $ hg bookmark
118 * foo 6:3727deee06f7
119 * foo 6:3727deee06f7
119 $ hg heads -T '{rev}:{node} {desc}'
120 $ hg heads -T '{rev}:{node} {desc}'
120 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
121 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde (no-eol)
121 $ hg log -r . -p -T '{rev}:{node} {desc}'
122 $ hg log -r . -p -T '{rev}:{node} {desc}'
122 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
123 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcdediff -r 6db330d65db4 -r 3727deee06f7 file-abcde
123 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
125 +++ b/file-abcde Thu Jan 01 00:00:00 1970 +0000
125 @@ -0,0 +1,1 @@
126 @@ -0,0 +1,1 @@
126 +abcde
127 +abcde
127
128
128 $ hg log -G -T '{rev}:{node} {desc}' --hidden
129 $ hg log -G -T '{rev}:{node} {desc}' --hidden
129 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
130 @ 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
130 |
131 |
131 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
132 | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
132 |/
133 |/
133 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
134 | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
134 |/
135 |/
135 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
136 o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
136 |
137 |
137 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
138 o 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
138 |
139 |
139 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
140 o 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
140 |
141 |
141 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
142 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
142
143
143 $ hg commit -m 'update files for abcde'
144 $ hg commit -m 'update files for abcde'
144
145
145 Uncommit with dirty state
146 Uncommit with dirty state
146
147
147 $ echo "foo" >> files
148 $ echo "foo" >> files
148 $ cat files
149 $ cat files
149 abcde
150 abcde
150 foo
151 foo
151 $ hg status
152 $ hg status
152 M files
153 M files
153 $ hg uncommit
154 $ hg uncommit
154 abort: uncommitted changes
155 abort: uncommitted changes
155 [255]
156 [255]
156 $ hg uncommit files
157 $ hg uncommit files
157 $ cat files
158 $ cat files
158 abcde
159 abcde
159 foo
160 foo
160 $ hg commit -m "files abcde + foo"
161 $ hg commit -m "files abcde + foo"
161
162
162 Testing the 'experimental.uncommitondirtywdir' config
163 Testing the 'experimental.uncommitondirtywdir' config
163
164
164 $ echo "bar" >> files
165 $ echo "bar" >> files
165 $ hg uncommit
166 $ hg uncommit
166 abort: uncommitted changes
167 abort: uncommitted changes
167 [255]
168 [255]
168 $ hg uncommit --config experimental.uncommitondirtywdir=True
169 $ hg uncommit --config experimental.uncommitondirtywdir=True
169 $ hg commit -m "files abcde + foo"
170 $ hg commit -m "files abcde + foo"
170
171
171 Uncommit in the middle of a stack, does not move bookmark
172 Uncommit in the middle of a stack, does not move bookmark
172
173
173 $ hg checkout '.^^^'
174 $ hg checkout '.^^^'
174 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
175 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
175 (leaving bookmark foo)
176 (leaving bookmark foo)
176 $ hg log -r . -p -T '{rev}:{node} {desc}'
177 $ hg log -r . -p -T '{rev}:{node} {desc}'
177 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
178 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abcdiff -r 69a232e754b0 -r abf2df566fc1 file-abc
178 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
179 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
179 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
180 +++ b/file-abc Thu Jan 01 00:00:00 1970 +0000
180 @@ -0,0 +1,1 @@
181 @@ -0,0 +1,1 @@
181 +abc
182 +abc
182 diff -r 69a232e754b0 -r abf2df566fc1 files
183 diff -r 69a232e754b0 -r abf2df566fc1 files
183 --- a/files Thu Jan 01 00:00:00 1970 +0000
184 --- a/files Thu Jan 01 00:00:00 1970 +0000
184 +++ b/files Thu Jan 01 00:00:00 1970 +0000
185 +++ b/files Thu Jan 01 00:00:00 1970 +0000
185 @@ -1,1 +1,1 @@
186 @@ -1,1 +1,1 @@
186 -ab
187 -ab
187 +abc
188 +abc
188
189
189 $ hg bookmark
190 $ hg bookmark
190 foo 9:48e5bd7cd583
191 foo 9:48e5bd7cd583
191 $ hg uncommit
192 $ hg uncommit
192 $ hg status
193 $ hg status
193 M files
194 M files
194 A file-abc
195 A file-abc
195 $ hg heads -T '{rev}:{node} {desc}'
196 $ hg heads -T '{rev}:{node} {desc}'
196 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
197 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo (no-eol)
197 $ hg bookmark
198 $ hg bookmark
198 foo 9:48e5bd7cd583
199 foo 9:48e5bd7cd583
199 $ hg commit -m 'new abc'
200 $ hg commit -m 'new abc'
200 created new head
201 created new head
201
202
202 Partial uncommit in the middle, does not move bookmark
203 Partial uncommit in the middle, does not move bookmark
203
204
204 $ hg checkout '.^'
205 $ hg checkout '.^'
205 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
206 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
206 $ hg log -r . -p -T '{rev}:{node} {desc}'
207 $ hg log -r . -p -T '{rev}:{node} {desc}'
207 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
208 1:69a232e754b08d568c4899475faf2eb44b857802 added file-abdiff -r 3004d2d9b508 -r 69a232e754b0 file-ab
208 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
210 +++ b/file-ab Thu Jan 01 00:00:00 1970 +0000
210 @@ -0,0 +1,1 @@
211 @@ -0,0 +1,1 @@
211 +ab
212 +ab
212 diff -r 3004d2d9b508 -r 69a232e754b0 files
213 diff -r 3004d2d9b508 -r 69a232e754b0 files
213 --- a/files Thu Jan 01 00:00:00 1970 +0000
214 --- a/files Thu Jan 01 00:00:00 1970 +0000
214 +++ b/files Thu Jan 01 00:00:00 1970 +0000
215 +++ b/files Thu Jan 01 00:00:00 1970 +0000
215 @@ -1,1 +1,1 @@
216 @@ -1,1 +1,1 @@
216 -a
217 -a
217 +ab
218 +ab
218
219
219 $ hg bookmark
220 $ hg bookmark
220 foo 9:48e5bd7cd583
221 foo 9:48e5bd7cd583
221 $ hg uncommit file-ab
222 $ hg uncommit file-ab
222 $ hg status
223 $ hg status
223 A file-ab
224 A file-ab
224
225
225 $ hg heads -T '{rev}:{node} {desc}\n'
226 $ hg heads -T '{rev}:{node} {desc}\n'
226 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
227 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
227 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
228 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
228 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
229 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
229
230
230 $ hg bookmark
231 $ hg bookmark
231 foo 9:48e5bd7cd583
232 foo 9:48e5bd7cd583
232 $ hg commit -m 'update ab'
233 $ hg commit -m 'update ab'
233 $ hg status
234 $ hg status
234 $ hg heads -T '{rev}:{node} {desc}\n'
235 $ hg heads -T '{rev}:{node} {desc}\n'
235 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
236 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
236 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
237 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
237 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
238 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
238
239
239 $ hg log -G -T '{rev}:{node} {desc}' --hidden
240 $ hg log -G -T '{rev}:{node} {desc}' --hidden
240 @ 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
241 @ 12:f21039c59242b085491bb58f591afc4ed1c04c09 update ab
241 |
242 |
242 o 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
243 o 11:8eb87968f2edb7f27f27fe676316e179de65fff6 added file-ab
243 |
244 |
244 | o 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
245 | o 10:5dc89ca4486f8a88716c5797fa9f498d13d7c2e1 new abc
245 | |
246 | |
246 | | o 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
247 | | o 9:48e5bd7cd583eb24164ef8b89185819c84c96ed7 files abcde + foo
247 | | |
248 | | |
248 | | | x 8:83815831694b1271e9f207cb1b79b2b19275edcb files abcde + foo
249 | | | x 8:83815831694b1271e9f207cb1b79b2b19275edcb files abcde + foo
249 | | |/
250 | | |/
250 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
251 | | | x 7:0977fa602c2fd7d8427ed4e7ee15ea13b84c9173 update files for abcde
251 | | |/
252 | | |/
252 | | o 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
253 | | o 6:3727deee06f72f5ffa8db792ee299cf39e3e190b new change abcde
253 | | |
254 | | |
254 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
255 | | | x 5:0c07a3ccda771b25f1cb1edbd02e683723344ef1 new change abcde
255 | | |/
256 | | |/
256 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
257 | | | x 4:6c4fd43ed714e7fcd8adbaa7b16c953c2e985b60 added file-abcde
257 | | |/
258 | | |/
258 | | o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
259 | | o 3:6db330d65db434145c0b59d291853e9a84719b24 added file-abcd
259 | | |
260 | | |
260 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
261 | | x 2:abf2df566fc193b3ac34d946e63c1583e4d4732b added file-abc
261 | |/
262 | |/
262 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
263 | x 1:69a232e754b08d568c4899475faf2eb44b857802 added file-ab
263 |/
264 |/
264 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
265 o 0:3004d2d9b50883c1538fc754a3aeb55f1b4084f6 added file-a
265
266
266 Uncommit with draft parent
267 Uncommit with draft parent
267
268
268 $ hg uncommit
269 $ hg uncommit
269 $ hg phase -r .
270 $ hg phase -r .
270 11: draft
271 11: draft
271 $ hg commit -m 'update ab again'
272 $ hg commit -m 'update ab again'
272
273
273 Uncommit with public parent
274 Uncommit with public parent
274
275
275 $ hg phase -p "::.^"
276 $ hg phase -p "::.^"
276 $ hg uncommit
277 $ hg uncommit
277 $ hg phase -r .
278 $ hg phase -r .
278 11: public
279 11: public
279
280
280 Partial uncommit with public parent
281 Partial uncommit with public parent
281
282
282 $ echo xyz > xyz
283 $ echo xyz > xyz
283 $ hg add xyz
284 $ hg add xyz
284 $ hg commit -m "update ab and add xyz"
285 $ hg commit -m "update ab and add xyz"
285 $ hg uncommit xyz
286 $ hg uncommit xyz
286 $ hg status
287 $ hg status
287 A xyz
288 A xyz
288 $ hg phase -r .
289 $ hg phase -r .
289 15: draft
290 15: draft
290 $ hg phase -r ".^"
291 $ hg phase -r ".^"
291 11: public
292 11: public
292
293
293 Uncommit leaving an empty changeset
294 Uncommit leaving an empty changeset
294
295
295 $ cd $TESTTMP
296 $ cd $TESTTMP
296 $ hg init repo1
297 $ hg init repo1
297 $ cd repo1
298 $ cd repo1
298 $ hg debugdrawdag <<'EOS'
299 $ hg debugdrawdag <<'EOS'
299 > Q
300 > Q
300 > |
301 > |
301 > P
302 > P
302 > EOS
303 > EOS
303 $ hg up Q -q
304 $ hg up Q -q
304 $ hg uncommit --keep
305 $ hg uncommit --keep
305 $ hg log -G -T '{desc} FILES: {files}'
306 $ hg log -G -T '{desc} FILES: {files}'
306 @ Q FILES:
307 @ Q FILES:
307 |
308 |
308 | x Q FILES: Q
309 | x Q FILES: Q
309 |/
310 |/
310 o P FILES: P
311 o P FILES: P
311
312
312 $ hg status
313 $ hg status
313 A Q
314 A Q
314
315
315 $ cd ..
316 $ cd ..
316 $ rm -rf repo1
317 $ rm -rf repo1
317
318
318 Testing uncommit while merge
319 Testing uncommit while merge
319
320
320 $ hg init repo2
321 $ hg init repo2
321 $ cd repo2
322 $ cd repo2
322
323
323 Create some history
324 Create some history
324
325
325 $ touch a
326 $ touch a
326 $ hg add a
327 $ hg add a
327 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
328 $ for i in 1 2 3; do echo $i > a; hg commit -m "a $i"; done
328 $ hg checkout 0
329 $ hg checkout 0
329 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 $ touch b
331 $ touch b
331 $ hg add b
332 $ hg add b
332 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
333 $ for i in 1 2 3; do echo $i > b; hg commit -m "b $i"; done
333 created new head
334 created new head
334 $ hg log -G -T '{rev}:{node} {desc}' --hidden
335 $ hg log -G -T '{rev}:{node} {desc}' --hidden
335 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
336 @ 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
336 |
337 |
337 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
338 o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
338 |
339 |
339 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
340 o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
340 |
341 |
341 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
342 | o 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
342 | |
343 | |
343 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
344 | o 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
344 |/
345 |/
345 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
346 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
346
347
347
348
348 Add and expect uncommit to fail on both merge working dir and merge changeset
349 Add and expect uncommit to fail on both merge working dir and merge changeset
349
350
350 $ hg merge 2
351 $ hg merge 2
351 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
352 (branch merge, don't forget to commit)
353 (branch merge, don't forget to commit)
353
354
354 $ hg uncommit
355 $ hg uncommit
355 abort: outstanding uncommitted merge
356 abort: outstanding uncommitted merge
356 [255]
357 [255]
357
358
358 $ hg uncommit --config experimental.uncommitondirtywdir=True
359 $ hg uncommit --config experimental.uncommitondirtywdir=True
359 abort: cannot uncommit while merging
360 abort: cannot uncommit while merging
360 [255]
361 [255]
361
362
362 $ hg status
363 $ hg status
363 M a
364 M a
364 $ hg commit -m 'merge a and b'
365 $ hg commit -m 'merge a and b'
365
366
366 $ hg uncommit
367 $ hg uncommit
367 abort: cannot uncommit merge changeset
368 abort: cannot uncommit merge changeset
368 [255]
369 [255]
369
370
370 $ hg status
371 $ hg status
371 $ hg log -G -T '{rev}:{node} {desc}' --hidden
372 $ hg log -G -T '{rev}:{node} {desc}' --hidden
372 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
373 @ 6:c03b9c37bc67bf504d4912061cfb527b47a63c6e merge a and b
373 |\
374 |\
374 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
375 | o 5:2cd56cdde163ded2fbb16ba2f918c96046ab0bf2 b 3
375 | |
376 | |
376 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
377 | o 4:c3a0d5bb3b15834ffd2ef9ef603e93ec65cf2037 b 2
377 | |
378 | |
378 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
379 | o 3:49bb009ca26078726b8870f1edb29fae8f7618f5 b 1
379 | |
380 | |
380 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
381 o | 2:990982b7384266e691f1bc08ca36177adcd1c8a9 a 3
381 | |
382 | |
382 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
383 o | 1:24d38e3cf160c7b6f5ffe82179332229886a6d34 a 2
383 |/
384 |/
384 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
385 o 0:ea4e33293d4d274a2ba73150733c2612231f398c a 1
385
386
General Comments 0
You need to be logged in to leave comments. Login now