##// END OF EJS Templates
pull: allow to specify multiple sources...
marmoute -
r47498:68538348 default
parent child Browse files
Show More
@@ -0,0 +1,315 b''
1 ====================================================
2 Test push/pull from multiple source at the same time
3 ====================================================
4
5
6 Setup
7 =====
8
9 main repository
10 ---------------
11
12 $ . $RUNTESTDIR/testlib/common.sh
13 $ hg init main-repo
14 $ cd main-repo
15 $ mkcommit A
16 $ mkcommit B
17 $ mkcommit C
18 $ mkcommit D
19 $ mkcommit E
20 $ hg up 'desc(B)'
21 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
22 $ mkcommit F
23 created new head
24 $ mkcommit G
25 $ hg up 'desc(C)'
26 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
27 $ mkcommit H
28 created new head
29 $ hg up null --quiet
30 $ hg log -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
31 o H 7
32 |
33 | o E 4
34 | |
35 | o D 3
36 |/
37 o C 2
38 |
39 | o G 6
40 | |
41 | o F 5
42 |/
43 o B 1
44 |
45 o A 0
46
47 $ cd ..
48
49 Various other repositories
50 --------------------------
51
52 $ hg clone main-repo branch-E --rev 4 -U
53 adding changesets
54 adding manifests
55 adding file changes
56 added 5 changesets with 5 changes to 5 files
57 new changesets 4a2df7238c3b:a603bfb5a83e
58 $ hg clone main-repo branch-G --rev 6 -U
59 adding changesets
60 adding manifests
61 adding file changes
62 added 4 changesets with 4 changes to 4 files
63 new changesets 4a2df7238c3b:c521a06b234b
64 $ hg clone main-repo branch-H --rev 7 -U
65 adding changesets
66 adding manifests
67 adding file changes
68 added 4 changesets with 4 changes to 4 files
69 new changesets 4a2df7238c3b:40faebb2ec45
70
71 Test simple bare operation
72 ==========================
73
74 $ hg clone main-repo test-repo-bare --rev 0 -U
75 adding changesets
76 adding manifests
77 adding file changes
78 added 1 changesets with 1 changes to 1 files
79 new changesets 4a2df7238c3b
80
81 $ hg pull -R test-repo-bare ./branch-E ./branch-G ./branch-H
82 pulling from ./branch-E
83 searching for changes
84 adding changesets
85 adding manifests
86 adding file changes
87 added 4 changesets with 4 changes to 4 files
88 new changesets 27547f69f254:a603bfb5a83e
89 (run 'hg update' to get a working copy)
90 pulling from ./branch-G
91 searching for changes
92 adding changesets
93 adding manifests
94 adding file changes
95 added 2 changesets with 2 changes to 2 files (+1 heads)
96 new changesets 2f3a4c5c1417:c521a06b234b
97 (run 'hg heads' to see heads, 'hg merge' to merge)
98 pulling from ./branch-H
99 searching for changes
100 adding changesets
101 adding manifests
102 adding file changes
103 added 1 changesets with 1 changes to 1 files (+1 heads)
104 new changesets 40faebb2ec45
105 (run 'hg heads .' to see heads, 'hg merge' to merge)
106 $ hg log -R test-repo-bare -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
107 o H 7
108 |
109 | o E 4
110 | |
111 | o D 3
112 |/
113 o C 2
114 |
115 | o G 6
116 | |
117 | o F 5
118 |/
119 o B 1
120 |
121 o A 0
122
123
124 Test operation with a target
125 ============================
126
127 $ hg clone main-repo test-repo-rev --rev 0 -U
128 adding changesets
129 adding manifests
130 adding file changes
131 added 1 changesets with 1 changes to 1 files
132 new changesets 4a2df7238c3b
133
134 pulling an explicite revision
135
136 $ node_b=`hg log -R main-repo --rev 'desc(B)' -T '{node}'`
137 $ hg pull -R test-repo-rev ./branch-E ./branch-G ./branch-H --rev $node_b
138 pulling from ./branch-E
139 searching for changes
140 adding changesets
141 adding manifests
142 adding file changes
143 added 1 changesets with 1 changes to 1 files
144 new changesets 27547f69f254
145 (run 'hg update' to get a working copy)
146 pulling from ./branch-G
147 no changes found
148 pulling from ./branch-H
149 no changes found
150 $ hg log -R test-repo-rev -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
151 o B 1
152 |
153 o A 0
154
155
156 pulling a branch head, the branch head resolve to different revision on the
157 different repositories.
158
159 $ hg pull -R test-repo-rev ./branch-E ./branch-G ./branch-H --rev default
160 pulling from ./branch-E
161 searching for changes
162 adding changesets
163 adding manifests
164 adding file changes
165 added 3 changesets with 3 changes to 3 files
166 new changesets f838bfaca5c7:a603bfb5a83e
167 (run 'hg update' to get a working copy)
168 pulling from ./branch-G
169 searching for changes
170 adding changesets
171 adding manifests
172 adding file changes
173 added 2 changesets with 2 changes to 2 files (+1 heads)
174 new changesets 2f3a4c5c1417:c521a06b234b
175 (run 'hg heads' to see heads, 'hg merge' to merge)
176 pulling from ./branch-H
177 searching for changes
178 adding changesets
179 adding manifests
180 adding file changes
181 added 1 changesets with 1 changes to 1 files (+1 heads)
182 new changesets 40faebb2ec45
183 (run 'hg heads .' to see heads, 'hg merge' to merge)
184 $ hg log -R test-repo-rev -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
185 o H 7
186 |
187 | o E 4
188 | |
189 | o D 3
190 |/
191 o C 2
192 |
193 | o G 6
194 | |
195 | o F 5
196 |/
197 o B 1
198 |
199 o A 0
200
201
202
203 Test with --update
204 ==================
205
206 update without conflicts
207 ------------------------
208
209 $ hg clone main-repo test-repo-update --rev 0
210 adding changesets
211 adding manifests
212 adding file changes
213 added 1 changesets with 1 changes to 1 files
214 new changesets 4a2df7238c3b
215 updating to branch default
216 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
217
218 We update for each pull, so the first on get into a branch independant from the
219 other and stay there. This is the expected behavior.
220
221 $ hg log -R test-repo-update -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
222 @ A 0
223
224 $ hg pull -R test-repo-update ./branch-E ./branch-G ./branch-H --update
225 pulling from ./branch-E
226 searching for changes
227 adding changesets
228 adding manifests
229 adding file changes
230 added 4 changesets with 4 changes to 4 files
231 new changesets 27547f69f254:a603bfb5a83e
232 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 pulling from ./branch-G
234 searching for changes
235 adding changesets
236 adding manifests
237 adding file changes
238 added 2 changesets with 2 changes to 2 files (+1 heads)
239 new changesets 2f3a4c5c1417:c521a06b234b
240 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 updated to "a603bfb5a83e: E"
242 1 other heads for branch "default"
243 pulling from ./branch-H
244 searching for changes
245 adding changesets
246 adding manifests
247 adding file changes
248 added 1 changesets with 1 changes to 1 files (+1 heads)
249 new changesets 40faebb2ec45
250 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 updated to "a603bfb5a83e: E"
252 2 other heads for branch "default"
253 $ hg log -R test-repo-update -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
254 o H 7
255 |
256 | @ E 4
257 | |
258 | o D 3
259 |/
260 o C 2
261 |
262 | o G 6
263 | |
264 | o F 5
265 |/
266 o B 1
267 |
268 o A 0
269
270
271 update with conflicts
272 ---------------------
273
274 $ hg clone main-repo test-repo-conflict --rev 0
275 adding changesets
276 adding manifests
277 adding file changes
278 added 1 changesets with 1 changes to 1 files
279 new changesets 4a2df7238c3b
280 updating to branch default
281 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
282
283 The update has conflict and interrupt the pull.
284
285 $ echo this-will-conflict > test-repo-conflict/D
286 $ hg add -R test-repo-conflict test-repo-conflict/D
287 $ hg log -R test-repo-conflict -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
288 @ A 0
289
290 $ hg pull -R test-repo-conflict ./branch-E ./branch-G ./branch-H --update
291 pulling from ./branch-E
292 searching for changes
293 adding changesets
294 adding manifests
295 adding file changes
296 added 4 changesets with 4 changes to 4 files
297 new changesets 27547f69f254:a603bfb5a83e
298 merging D
299 warning: conflicts while merging D! (edit, then use 'hg resolve --mark')
300 3 files updated, 0 files merged, 0 files removed, 1 files unresolved
301 use 'hg resolve' to retry unresolved file merges
302 [1]
303 $ hg -R test-repo-conflict resolve -l
304 U D
305 $ hg log -R test-repo-conflict -T '{desc} {rev}\n' --rev 'sort(all(), "topo")' -G
306 @ E 4
307 |
308 o D 3
309 |
310 o C 2
311 |
312 o B 1
313 |
314 % A 0
315
@@ -0,0 +1,7 b''
1 mkcommit() {
2 name="$1"
3 shift
4 echo "$name" > "$name"
5 hg add "$name"
6 hg ci -m "$name" "$@"
7 }
@@ -1,7885 +1,7894 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 errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 bundlecaches,
29 bundlecaches,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 grep as grepmod,
44 grep as grepmod,
45 hbisect,
45 hbisect,
46 help,
46 help,
47 hg,
47 hg,
48 logcmdutil,
48 logcmdutil,
49 merge as mergemod,
49 merge as mergemod,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 narrowspec,
51 narrowspec,
52 obsolete,
52 obsolete,
53 obsutil,
53 obsutil,
54 patch,
54 patch,
55 phases,
55 phases,
56 pycompat,
56 pycompat,
57 rcutil,
57 rcutil,
58 registrar,
58 registrar,
59 requirements,
59 requirements,
60 revsetlang,
60 revsetlang,
61 rewriteutil,
61 rewriteutil,
62 scmutil,
62 scmutil,
63 server,
63 server,
64 shelve as shelvemod,
64 shelve as shelvemod,
65 state as statemod,
65 state as statemod,
66 streamclone,
66 streamclone,
67 tags as tagsmod,
67 tags as tagsmod,
68 ui as uimod,
68 ui as uimod,
69 util,
69 util,
70 verify as verifymod,
70 verify as verifymod,
71 vfs as vfsmod,
71 vfs as vfsmod,
72 wireprotoserver,
72 wireprotoserver,
73 )
73 )
74 from .utils import (
74 from .utils import (
75 dateutil,
75 dateutil,
76 stringutil,
76 stringutil,
77 )
77 )
78
78
79 table = {}
79 table = {}
80 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
81
81
82 command = registrar.command(table)
82 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
83 INTENT_READONLY = registrar.INTENT_READONLY
84
84
85 # common command options
85 # common command options
86
86
87 globalopts = [
87 globalopts = [
88 (
88 (
89 b'R',
89 b'R',
90 b'repository',
90 b'repository',
91 b'',
91 b'',
92 _(b'repository root directory or name of overlay bundle file'),
92 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
93 _(b'REPO'),
94 ),
94 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
96 (
97 b'y',
97 b'y',
98 b'noninteractive',
98 b'noninteractive',
99 None,
99 None,
100 _(
100 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
101 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
102 ),
103 ),
103 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
106 (
107 b'',
107 b'',
108 b'color',
108 b'color',
109 b'',
109 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
111 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
113 _(b'TYPE'),
114 ),
114 ),
115 (
115 (
116 b'',
116 b'',
117 b'config',
117 b'config',
118 [],
118 [],
119 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
120 _(b'CONFIG'),
121 ),
121 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
123 (b'', b'debugger', None, _(b'start debugger')),
124 (
124 (
125 b'',
125 b'',
126 b'encoding',
126 b'encoding',
127 encoding.encoding,
127 encoding.encoding,
128 _(b'set the charset encoding'),
128 _(b'set the charset encoding'),
129 _(b'ENCODE'),
129 _(b'ENCODE'),
130 ),
130 ),
131 (
131 (
132 b'',
132 b'',
133 b'encodingmode',
133 b'encodingmode',
134 encoding.encodingmode,
134 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
135 _(b'set the charset encoding mode'),
136 _(b'MODE'),
136 _(b'MODE'),
137 ),
137 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
141 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
144 (
145 b'',
145 b'',
146 b'pager',
146 b'pager',
147 b'auto',
147 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
149 _(b'TYPE'),
150 ),
150 ),
151 ]
151 ]
152
152
153 dryrunopts = cmdutil.dryrunopts
153 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
154 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
155 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
156 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
157 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
158 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
159 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
160 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
161 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
162 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
163 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
164 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
165 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
166 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
167 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
168 debugrevlogopts = cmdutil.debugrevlogopts
169
169
170 # Commands start here, listed alphabetically
170 # Commands start here, listed alphabetically
171
171
172
172
173 @command(
173 @command(
174 b'abort',
174 b'abort',
175 dryrunopts,
175 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
177 helpbasic=True,
178 )
178 )
179 def abort(ui, repo, **opts):
179 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
180 """abort an unfinished operation (EXPERIMENTAL)
181
181
182 Aborts a multistep operation like graft, histedit, rebase, merge,
182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
183 and unshelve if they are in an unfinished state.
184
184
185 use --dry-run/-n to dry run the command.
185 use --dry-run/-n to dry run the command.
186 """
186 """
187 dryrun = opts.get('dry_run')
187 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
188 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
189 if not abortstate:
190 raise error.StateError(_(b'no operation in progress'))
190 raise error.StateError(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
191 if not abortstate.abortfunc:
192 raise error.InputError(
192 raise error.InputError(
193 (
193 (
194 _(b"%s in progress but does not support 'hg abort'")
194 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
195 % (abortstate._opname)
196 ),
196 ),
197 hint=abortstate.hint(),
197 hint=abortstate.hint(),
198 )
198 )
199 if dryrun:
199 if dryrun:
200 ui.status(
200 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
202 )
203 return
203 return
204 return abortstate.abortfunc(ui, repo)
204 return abortstate.abortfunc(ui, repo)
205
205
206
206
207 @command(
207 @command(
208 b'add',
208 b'add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
210 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
212 helpbasic=True,
213 inferrepo=True,
213 inferrepo=True,
214 )
214 )
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 relative = scmutil.anypats(pats, opts)
337 relative = scmutil.anypats(pats, opts)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340
340
341
341
342 @command(
342 @command(
343 b'annotate|blame',
343 b'annotate|blame',
344 [
344 [
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (
346 (
347 b'',
347 b'',
348 b'follow',
348 b'follow',
349 None,
349 None,
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 ),
351 ),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'f', b'file', None, _(b'list the filename')),
355 (b'f', b'file', None, _(b'list the filename')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
359 (
359 (
360 b'l',
360 b'l',
361 b'line-number',
361 b'line-number',
362 None,
362 None,
363 _(b'show line number at the first appearance'),
363 _(b'show line number at the first appearance'),
364 ),
364 ),
365 (
365 (
366 b'',
366 b'',
367 b'skip',
367 b'skip',
368 [],
368 [],
369 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'REV'),
370 _(b'REV'),
371 ),
371 ),
372 ]
372 ]
373 + diffwsopts
373 + diffwsopts
374 + walkopts
374 + walkopts
375 + formatteropts,
375 + formatteropts,
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpbasic=True,
378 helpbasic=True,
379 inferrepo=True,
379 inferrepo=True,
380 )
380 )
381 def annotate(ui, repo, *pats, **opts):
381 def annotate(ui, repo, *pats, **opts):
382 """show changeset information by line for each file
382 """show changeset information by line for each file
383
383
384 List changes in files, showing the revision id responsible for
384 List changes in files, showing the revision id responsible for
385 each line.
385 each line.
386
386
387 This command is useful for discovering when a change was made and
387 This command is useful for discovering when a change was made and
388 by whom.
388 by whom.
389
389
390 If you include --file, --user, or --date, the revision number is
390 If you include --file, --user, or --date, the revision number is
391 suppressed unless you also include --number.
391 suppressed unless you also include --number.
392
392
393 Without the -a/--text option, annotate will avoid processing files
393 Without the -a/--text option, annotate will avoid processing files
394 it detects as binary. With -a, annotate will annotate the file
394 it detects as binary. With -a, annotate will annotate the file
395 anyway, although the results will probably be neither useful
395 anyway, although the results will probably be neither useful
396 nor desirable.
396 nor desirable.
397
397
398 .. container:: verbose
398 .. container:: verbose
399
399
400 Template:
400 Template:
401
401
402 The following keywords are supported in addition to the common template
402 The following keywords are supported in addition to the common template
403 keywords and functions. See also :hg:`help templates`.
403 keywords and functions. See also :hg:`help templates`.
404
404
405 :lines: List of lines with annotation data.
405 :lines: List of lines with annotation data.
406 :path: String. Repository-absolute path of the specified file.
406 :path: String. Repository-absolute path of the specified file.
407
407
408 And each entry of ``{lines}`` provides the following sub-keywords in
408 And each entry of ``{lines}`` provides the following sub-keywords in
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410
410
411 :line: String. Line content.
411 :line: String. Line content.
412 :lineno: Integer. Line number at that revision.
412 :lineno: Integer. Line number at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
414
414
415 See :hg:`help templates.operators` for the list expansion syntax.
415 See :hg:`help templates.operators` for the list expansion syntax.
416
416
417 Returns 0 on success.
417 Returns 0 on success.
418 """
418 """
419 opts = pycompat.byteskwargs(opts)
419 opts = pycompat.byteskwargs(opts)
420 if not pats:
420 if not pats:
421 raise error.InputError(
421 raise error.InputError(
422 _(b'at least one filename or pattern is required')
422 _(b'at least one filename or pattern is required')
423 )
423 )
424
424
425 if opts.get(b'follow'):
425 if opts.get(b'follow'):
426 # --follow is deprecated and now just an alias for -f/--file
426 # --follow is deprecated and now just an alias for -f/--file
427 # to mimic the behavior of Mercurial before version 1.5
427 # to mimic the behavior of Mercurial before version 1.5
428 opts[b'file'] = True
428 opts[b'file'] = True
429
429
430 if (
430 if (
431 not opts.get(b'user')
431 not opts.get(b'user')
432 and not opts.get(b'changeset')
432 and not opts.get(b'changeset')
433 and not opts.get(b'date')
433 and not opts.get(b'date')
434 and not opts.get(b'file')
434 and not opts.get(b'file')
435 ):
435 ):
436 opts[b'number'] = True
436 opts[b'number'] = True
437
437
438 linenumber = opts.get(b'line_number') is not None
438 linenumber = opts.get(b'line_number') is not None
439 if (
439 if (
440 linenumber
440 linenumber
441 and (not opts.get(b'changeset'))
441 and (not opts.get(b'changeset'))
442 and (not opts.get(b'number'))
442 and (not opts.get(b'number'))
443 ):
443 ):
444 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
444 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
445
445
446 rev = opts.get(b'rev')
446 rev = opts.get(b'rev')
447 if rev:
447 if rev:
448 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
448 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
449 ctx = scmutil.revsingle(repo, rev)
449 ctx = scmutil.revsingle(repo, rev)
450
450
451 ui.pager(b'annotate')
451 ui.pager(b'annotate')
452 rootfm = ui.formatter(b'annotate', opts)
452 rootfm = ui.formatter(b'annotate', opts)
453 if ui.debugflag:
453 if ui.debugflag:
454 shorthex = pycompat.identity
454 shorthex = pycompat.identity
455 else:
455 else:
456
456
457 def shorthex(h):
457 def shorthex(h):
458 return h[:12]
458 return h[:12]
459
459
460 if ui.quiet:
460 if ui.quiet:
461 datefunc = dateutil.shortdate
461 datefunc = dateutil.shortdate
462 else:
462 else:
463 datefunc = dateutil.datestr
463 datefunc = dateutil.datestr
464 if ctx.rev() is None:
464 if ctx.rev() is None:
465 if opts.get(b'changeset'):
465 if opts.get(b'changeset'):
466 # omit "+" suffix which is appended to node hex
466 # omit "+" suffix which is appended to node hex
467 def formatrev(rev):
467 def formatrev(rev):
468 if rev == wdirrev:
468 if rev == wdirrev:
469 return b'%d' % ctx.p1().rev()
469 return b'%d' % ctx.p1().rev()
470 else:
470 else:
471 return b'%d' % rev
471 return b'%d' % rev
472
472
473 else:
473 else:
474
474
475 def formatrev(rev):
475 def formatrev(rev):
476 if rev == wdirrev:
476 if rev == wdirrev:
477 return b'%d+' % ctx.p1().rev()
477 return b'%d+' % ctx.p1().rev()
478 else:
478 else:
479 return b'%d ' % rev
479 return b'%d ' % rev
480
480
481 def formathex(h):
481 def formathex(h):
482 if h == wdirhex:
482 if h == wdirhex:
483 return b'%s+' % shorthex(hex(ctx.p1().node()))
483 return b'%s+' % shorthex(hex(ctx.p1().node()))
484 else:
484 else:
485 return b'%s ' % shorthex(h)
485 return b'%s ' % shorthex(h)
486
486
487 else:
487 else:
488 formatrev = b'%d'.__mod__
488 formatrev = b'%d'.__mod__
489 formathex = shorthex
489 formathex = shorthex
490
490
491 opmap = [
491 opmap = [
492 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
492 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
493 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
493 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
494 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
494 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
495 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
495 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
496 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
496 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
497 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
497 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
498 ]
498 ]
499 opnamemap = {
499 opnamemap = {
500 b'rev': b'number',
500 b'rev': b'number',
501 b'node': b'changeset',
501 b'node': b'changeset',
502 b'path': b'file',
502 b'path': b'file',
503 b'lineno': b'line_number',
503 b'lineno': b'line_number',
504 }
504 }
505
505
506 if rootfm.isplain():
506 if rootfm.isplain():
507
507
508 def makefunc(get, fmt):
508 def makefunc(get, fmt):
509 return lambda x: fmt(get(x))
509 return lambda x: fmt(get(x))
510
510
511 else:
511 else:
512
512
513 def makefunc(get, fmt):
513 def makefunc(get, fmt):
514 return get
514 return get
515
515
516 datahint = rootfm.datahint()
516 datahint = rootfm.datahint()
517 funcmap = [
517 funcmap = [
518 (makefunc(get, fmt), sep)
518 (makefunc(get, fmt), sep)
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 ]
521 ]
522 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
522 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
523 fields = b' '.join(
523 fields = b' '.join(
524 fn
524 fn
525 for fn, sep, get, fmt in opmap
525 for fn, sep, get, fmt in opmap
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
527 )
527 )
528
528
529 def bad(x, y):
529 def bad(x, y):
530 raise error.Abort(b"%s: %s" % (x, y))
530 raise error.Abort(b"%s: %s" % (x, y))
531
531
532 m = scmutil.match(ctx, pats, opts, badfn=bad)
532 m = scmutil.match(ctx, pats, opts, badfn=bad)
533
533
534 follow = not opts.get(b'no_follow')
534 follow = not opts.get(b'no_follow')
535 diffopts = patch.difffeatureopts(
535 diffopts = patch.difffeatureopts(
536 ui, opts, section=b'annotate', whitespace=True
536 ui, opts, section=b'annotate', whitespace=True
537 )
537 )
538 skiprevs = opts.get(b'skip')
538 skiprevs = opts.get(b'skip')
539 if skiprevs:
539 if skiprevs:
540 skiprevs = scmutil.revrange(repo, skiprevs)
540 skiprevs = scmutil.revrange(repo, skiprevs)
541
541
542 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
542 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
543 for abs in ctx.walk(m):
543 for abs in ctx.walk(m):
544 fctx = ctx[abs]
544 fctx = ctx[abs]
545 rootfm.startitem()
545 rootfm.startitem()
546 rootfm.data(path=abs)
546 rootfm.data(path=abs)
547 if not opts.get(b'text') and fctx.isbinary():
547 if not opts.get(b'text') and fctx.isbinary():
548 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
548 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
549 continue
549 continue
550
550
551 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
551 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
552 lines = fctx.annotate(
552 lines = fctx.annotate(
553 follow=follow, skiprevs=skiprevs, diffopts=diffopts
553 follow=follow, skiprevs=skiprevs, diffopts=diffopts
554 )
554 )
555 if not lines:
555 if not lines:
556 fm.end()
556 fm.end()
557 continue
557 continue
558 formats = []
558 formats = []
559 pieces = []
559 pieces = []
560
560
561 for f, sep in funcmap:
561 for f, sep in funcmap:
562 l = [f(n) for n in lines]
562 l = [f(n) for n in lines]
563 if fm.isplain():
563 if fm.isplain():
564 sizes = [encoding.colwidth(x) for x in l]
564 sizes = [encoding.colwidth(x) for x in l]
565 ml = max(sizes)
565 ml = max(sizes)
566 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
566 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
567 else:
567 else:
568 formats.append([b'%s'] * len(l))
568 formats.append([b'%s'] * len(l))
569 pieces.append(l)
569 pieces.append(l)
570
570
571 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
571 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
572 fm.startitem()
572 fm.startitem()
573 fm.context(fctx=n.fctx)
573 fm.context(fctx=n.fctx)
574 fm.write(fields, b"".join(f), *p)
574 fm.write(fields, b"".join(f), *p)
575 if n.skip:
575 if n.skip:
576 fmt = b"* %s"
576 fmt = b"* %s"
577 else:
577 else:
578 fmt = b": %s"
578 fmt = b": %s"
579 fm.write(b'line', fmt, n.text)
579 fm.write(b'line', fmt, n.text)
580
580
581 if not lines[-1].text.endswith(b'\n'):
581 if not lines[-1].text.endswith(b'\n'):
582 fm.plain(b'\n')
582 fm.plain(b'\n')
583 fm.end()
583 fm.end()
584
584
585 rootfm.end()
585 rootfm.end()
586
586
587
587
588 @command(
588 @command(
589 b'archive',
589 b'archive',
590 [
590 [
591 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
591 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
592 (
592 (
593 b'p',
593 b'p',
594 b'prefix',
594 b'prefix',
595 b'',
595 b'',
596 _(b'directory prefix for files in archive'),
596 _(b'directory prefix for files in archive'),
597 _(b'PREFIX'),
597 _(b'PREFIX'),
598 ),
598 ),
599 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
599 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
600 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
600 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
601 ]
601 ]
602 + subrepoopts
602 + subrepoopts
603 + walkopts,
603 + walkopts,
604 _(b'[OPTION]... DEST'),
604 _(b'[OPTION]... DEST'),
605 helpcategory=command.CATEGORY_IMPORT_EXPORT,
605 helpcategory=command.CATEGORY_IMPORT_EXPORT,
606 )
606 )
607 def archive(ui, repo, dest, **opts):
607 def archive(ui, repo, dest, **opts):
608 """create an unversioned archive of a repository revision
608 """create an unversioned archive of a repository revision
609
609
610 By default, the revision used is the parent of the working
610 By default, the revision used is the parent of the working
611 directory; use -r/--rev to specify a different revision.
611 directory; use -r/--rev to specify a different revision.
612
612
613 The archive type is automatically detected based on file
613 The archive type is automatically detected based on file
614 extension (to override, use -t/--type).
614 extension (to override, use -t/--type).
615
615
616 .. container:: verbose
616 .. container:: verbose
617
617
618 Examples:
618 Examples:
619
619
620 - create a zip file containing the 1.0 release::
620 - create a zip file containing the 1.0 release::
621
621
622 hg archive -r 1.0 project-1.0.zip
622 hg archive -r 1.0 project-1.0.zip
623
623
624 - create a tarball excluding .hg files::
624 - create a tarball excluding .hg files::
625
625
626 hg archive project.tar.gz -X ".hg*"
626 hg archive project.tar.gz -X ".hg*"
627
627
628 Valid types are:
628 Valid types are:
629
629
630 :``files``: a directory full of files (default)
630 :``files``: a directory full of files (default)
631 :``tar``: tar archive, uncompressed
631 :``tar``: tar archive, uncompressed
632 :``tbz2``: tar archive, compressed using bzip2
632 :``tbz2``: tar archive, compressed using bzip2
633 :``tgz``: tar archive, compressed using gzip
633 :``tgz``: tar archive, compressed using gzip
634 :``txz``: tar archive, compressed using lzma (only in Python 3)
634 :``txz``: tar archive, compressed using lzma (only in Python 3)
635 :``uzip``: zip archive, uncompressed
635 :``uzip``: zip archive, uncompressed
636 :``zip``: zip archive, compressed using deflate
636 :``zip``: zip archive, compressed using deflate
637
637
638 The exact name of the destination archive or directory is given
638 The exact name of the destination archive or directory is given
639 using a format string; see :hg:`help export` for details.
639 using a format string; see :hg:`help export` for details.
640
640
641 Each member added to an archive file has a directory prefix
641 Each member added to an archive file has a directory prefix
642 prepended. Use -p/--prefix to specify a format string for the
642 prepended. Use -p/--prefix to specify a format string for the
643 prefix. The default is the basename of the archive, with suffixes
643 prefix. The default is the basename of the archive, with suffixes
644 removed.
644 removed.
645
645
646 Returns 0 on success.
646 Returns 0 on success.
647 """
647 """
648
648
649 opts = pycompat.byteskwargs(opts)
649 opts = pycompat.byteskwargs(opts)
650 rev = opts.get(b'rev')
650 rev = opts.get(b'rev')
651 if rev:
651 if rev:
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
653 ctx = scmutil.revsingle(repo, rev)
653 ctx = scmutil.revsingle(repo, rev)
654 if not ctx:
654 if not ctx:
655 raise error.InputError(
655 raise error.InputError(
656 _(b'no working directory: please specify a revision')
656 _(b'no working directory: please specify a revision')
657 )
657 )
658 node = ctx.node()
658 node = ctx.node()
659 dest = cmdutil.makefilename(ctx, dest)
659 dest = cmdutil.makefilename(ctx, dest)
660 if os.path.realpath(dest) == repo.root:
660 if os.path.realpath(dest) == repo.root:
661 raise error.InputError(_(b'repository root cannot be destination'))
661 raise error.InputError(_(b'repository root cannot be destination'))
662
662
663 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
663 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
664 prefix = opts.get(b'prefix')
664 prefix = opts.get(b'prefix')
665
665
666 if dest == b'-':
666 if dest == b'-':
667 if kind == b'files':
667 if kind == b'files':
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
669 dest = cmdutil.makefileobj(ctx, dest)
669 dest = cmdutil.makefileobj(ctx, dest)
670 if not prefix:
670 if not prefix:
671 prefix = os.path.basename(repo.root) + b'-%h'
671 prefix = os.path.basename(repo.root) + b'-%h'
672
672
673 prefix = cmdutil.makefilename(ctx, prefix)
673 prefix = cmdutil.makefilename(ctx, prefix)
674 match = scmutil.match(ctx, [], opts)
674 match = scmutil.match(ctx, [], opts)
675 archival.archive(
675 archival.archive(
676 repo,
676 repo,
677 dest,
677 dest,
678 node,
678 node,
679 kind,
679 kind,
680 not opts.get(b'no_decode'),
680 not opts.get(b'no_decode'),
681 match,
681 match,
682 prefix,
682 prefix,
683 subrepos=opts.get(b'subrepos'),
683 subrepos=opts.get(b'subrepos'),
684 )
684 )
685
685
686
686
687 @command(
687 @command(
688 b'backout',
688 b'backout',
689 [
689 [
690 (
690 (
691 b'',
691 b'',
692 b'merge',
692 b'merge',
693 None,
693 None,
694 _(b'merge with old dirstate parent after backout'),
694 _(b'merge with old dirstate parent after backout'),
695 ),
695 ),
696 (
696 (
697 b'',
697 b'',
698 b'commit',
698 b'commit',
699 None,
699 None,
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
701 ),
701 ),
702 (b'', b'no-commit', None, _(b'do not commit')),
702 (b'', b'no-commit', None, _(b'do not commit')),
703 (
703 (
704 b'',
704 b'',
705 b'parent',
705 b'parent',
706 b'',
706 b'',
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
708 _(b'REV'),
708 _(b'REV'),
709 ),
709 ),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
712 ]
712 ]
713 + mergetoolopts
713 + mergetoolopts
714 + walkopts
714 + walkopts
715 + commitopts
715 + commitopts
716 + commitopts2,
716 + commitopts2,
717 _(b'[OPTION]... [-r] REV'),
717 _(b'[OPTION]... [-r] REV'),
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
719 )
719 )
720 def backout(ui, repo, node=None, rev=None, **opts):
720 def backout(ui, repo, node=None, rev=None, **opts):
721 """reverse effect of earlier changeset
721 """reverse effect of earlier changeset
722
722
723 Prepare a new changeset with the effect of REV undone in the
723 Prepare a new changeset with the effect of REV undone in the
724 current working directory. If no conflicts were encountered,
724 current working directory. If no conflicts were encountered,
725 it will be committed immediately.
725 it will be committed immediately.
726
726
727 If REV is the parent of the working directory, then this new changeset
727 If REV is the parent of the working directory, then this new changeset
728 is committed automatically (unless --no-commit is specified).
728 is committed automatically (unless --no-commit is specified).
729
729
730 .. note::
730 .. note::
731
731
732 :hg:`backout` cannot be used to fix either an unwanted or
732 :hg:`backout` cannot be used to fix either an unwanted or
733 incorrect merge.
733 incorrect merge.
734
734
735 .. container:: verbose
735 .. container:: verbose
736
736
737 Examples:
737 Examples:
738
738
739 - Reverse the effect of the parent of the working directory.
739 - Reverse the effect of the parent of the working directory.
740 This backout will be committed immediately::
740 This backout will be committed immediately::
741
741
742 hg backout -r .
742 hg backout -r .
743
743
744 - Reverse the effect of previous bad revision 23::
744 - Reverse the effect of previous bad revision 23::
745
745
746 hg backout -r 23
746 hg backout -r 23
747
747
748 - Reverse the effect of previous bad revision 23 and
748 - Reverse the effect of previous bad revision 23 and
749 leave changes uncommitted::
749 leave changes uncommitted::
750
750
751 hg backout -r 23 --no-commit
751 hg backout -r 23 --no-commit
752 hg commit -m "Backout revision 23"
752 hg commit -m "Backout revision 23"
753
753
754 By default, the pending changeset will have one parent,
754 By default, the pending changeset will have one parent,
755 maintaining a linear history. With --merge, the pending
755 maintaining a linear history. With --merge, the pending
756 changeset will instead have two parents: the old parent of the
756 changeset will instead have two parents: the old parent of the
757 working directory and a new child of REV that simply undoes REV.
757 working directory and a new child of REV that simply undoes REV.
758
758
759 Before version 1.7, the behavior without --merge was equivalent
759 Before version 1.7, the behavior without --merge was equivalent
760 to specifying --merge followed by :hg:`update --clean .` to
760 to specifying --merge followed by :hg:`update --clean .` to
761 cancel the merge and leave the child of REV as a head to be
761 cancel the merge and leave the child of REV as a head to be
762 merged separately.
762 merged separately.
763
763
764 See :hg:`help dates` for a list of formats valid for -d/--date.
764 See :hg:`help dates` for a list of formats valid for -d/--date.
765
765
766 See :hg:`help revert` for a way to restore files to the state
766 See :hg:`help revert` for a way to restore files to the state
767 of another revision.
767 of another revision.
768
768
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
770 files.
770 files.
771 """
771 """
772 with repo.wlock(), repo.lock():
772 with repo.wlock(), repo.lock():
773 return _dobackout(ui, repo, node, rev, **opts)
773 return _dobackout(ui, repo, node, rev, **opts)
774
774
775
775
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
778 opts = pycompat.byteskwargs(opts)
778 opts = pycompat.byteskwargs(opts)
779
779
780 if rev and node:
780 if rev and node:
781 raise error.InputError(_(b"please specify just one revision"))
781 raise error.InputError(_(b"please specify just one revision"))
782
782
783 if not rev:
783 if not rev:
784 rev = node
784 rev = node
785
785
786 if not rev:
786 if not rev:
787 raise error.InputError(_(b"please specify a revision to backout"))
787 raise error.InputError(_(b"please specify a revision to backout"))
788
788
789 date = opts.get(b'date')
789 date = opts.get(b'date')
790 if date:
790 if date:
791 opts[b'date'] = dateutil.parsedate(date)
791 opts[b'date'] = dateutil.parsedate(date)
792
792
793 cmdutil.checkunfinished(repo)
793 cmdutil.checkunfinished(repo)
794 cmdutil.bailifchanged(repo)
794 cmdutil.bailifchanged(repo)
795 ctx = scmutil.revsingle(repo, rev)
795 ctx = scmutil.revsingle(repo, rev)
796 node = ctx.node()
796 node = ctx.node()
797
797
798 op1, op2 = repo.dirstate.parents()
798 op1, op2 = repo.dirstate.parents()
799 if not repo.changelog.isancestor(node, op1):
799 if not repo.changelog.isancestor(node, op1):
800 raise error.InputError(
800 raise error.InputError(
801 _(b'cannot backout change that is not an ancestor')
801 _(b'cannot backout change that is not an ancestor')
802 )
802 )
803
803
804 p1, p2 = repo.changelog.parents(node)
804 p1, p2 = repo.changelog.parents(node)
805 if p1 == nullid:
805 if p1 == nullid:
806 raise error.InputError(_(b'cannot backout a change with no parents'))
806 raise error.InputError(_(b'cannot backout a change with no parents'))
807 if p2 != nullid:
807 if p2 != nullid:
808 if not opts.get(b'parent'):
808 if not opts.get(b'parent'):
809 raise error.InputError(_(b'cannot backout a merge changeset'))
809 raise error.InputError(_(b'cannot backout a merge changeset'))
810 p = repo.lookup(opts[b'parent'])
810 p = repo.lookup(opts[b'parent'])
811 if p not in (p1, p2):
811 if p not in (p1, p2):
812 raise error.InputError(
812 raise error.InputError(
813 _(b'%s is not a parent of %s') % (short(p), short(node))
813 _(b'%s is not a parent of %s') % (short(p), short(node))
814 )
814 )
815 parent = p
815 parent = p
816 else:
816 else:
817 if opts.get(b'parent'):
817 if opts.get(b'parent'):
818 raise error.InputError(
818 raise error.InputError(
819 _(b'cannot use --parent on non-merge changeset')
819 _(b'cannot use --parent on non-merge changeset')
820 )
820 )
821 parent = p1
821 parent = p1
822
822
823 # the backout should appear on the same branch
823 # the backout should appear on the same branch
824 branch = repo.dirstate.branch()
824 branch = repo.dirstate.branch()
825 bheads = repo.branchheads(branch)
825 bheads = repo.branchheads(branch)
826 rctx = scmutil.revsingle(repo, hex(parent))
826 rctx = scmutil.revsingle(repo, hex(parent))
827 if not opts.get(b'merge') and op1 != node:
827 if not opts.get(b'merge') and op1 != node:
828 with dirstateguard.dirstateguard(repo, b'backout'):
828 with dirstateguard.dirstateguard(repo, b'backout'):
829 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
829 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
830 with ui.configoverride(overrides, b'backout'):
830 with ui.configoverride(overrides, b'backout'):
831 stats = mergemod.back_out(ctx, parent=repo[parent])
831 stats = mergemod.back_out(ctx, parent=repo[parent])
832 repo.setparents(op1, op2)
832 repo.setparents(op1, op2)
833 hg._showstats(repo, stats)
833 hg._showstats(repo, stats)
834 if stats.unresolvedcount:
834 if stats.unresolvedcount:
835 repo.ui.status(
835 repo.ui.status(
836 _(b"use 'hg resolve' to retry unresolved file merges\n")
836 _(b"use 'hg resolve' to retry unresolved file merges\n")
837 )
837 )
838 return 1
838 return 1
839 else:
839 else:
840 hg.clean(repo, node, show_stats=False)
840 hg.clean(repo, node, show_stats=False)
841 repo.dirstate.setbranch(branch)
841 repo.dirstate.setbranch(branch)
842 cmdutil.revert(ui, repo, rctx)
842 cmdutil.revert(ui, repo, rctx)
843
843
844 if opts.get(b'no_commit'):
844 if opts.get(b'no_commit'):
845 msg = _(b"changeset %s backed out, don't forget to commit.\n")
845 msg = _(b"changeset %s backed out, don't forget to commit.\n")
846 ui.status(msg % short(node))
846 ui.status(msg % short(node))
847 return 0
847 return 0
848
848
849 def commitfunc(ui, repo, message, match, opts):
849 def commitfunc(ui, repo, message, match, opts):
850 editform = b'backout'
850 editform = b'backout'
851 e = cmdutil.getcommiteditor(
851 e = cmdutil.getcommiteditor(
852 editform=editform, **pycompat.strkwargs(opts)
852 editform=editform, **pycompat.strkwargs(opts)
853 )
853 )
854 if not message:
854 if not message:
855 # we don't translate commit messages
855 # we don't translate commit messages
856 message = b"Backed out changeset %s" % short(node)
856 message = b"Backed out changeset %s" % short(node)
857 e = cmdutil.getcommiteditor(edit=True, editform=editform)
857 e = cmdutil.getcommiteditor(edit=True, editform=editform)
858 return repo.commit(
858 return repo.commit(
859 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
859 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
860 )
860 )
861
861
862 # save to detect changes
862 # save to detect changes
863 tip = repo.changelog.tip()
863 tip = repo.changelog.tip()
864
864
865 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
865 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
866 if not newnode:
866 if not newnode:
867 ui.status(_(b"nothing changed\n"))
867 ui.status(_(b"nothing changed\n"))
868 return 1
868 return 1
869 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
869 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
870
870
871 def nice(node):
871 def nice(node):
872 return b'%d:%s' % (repo.changelog.rev(node), short(node))
872 return b'%d:%s' % (repo.changelog.rev(node), short(node))
873
873
874 ui.status(
874 ui.status(
875 _(b'changeset %s backs out changeset %s\n')
875 _(b'changeset %s backs out changeset %s\n')
876 % (nice(newnode), nice(node))
876 % (nice(newnode), nice(node))
877 )
877 )
878 if opts.get(b'merge') and op1 != node:
878 if opts.get(b'merge') and op1 != node:
879 hg.clean(repo, op1, show_stats=False)
879 hg.clean(repo, op1, show_stats=False)
880 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
880 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
882 with ui.configoverride(overrides, b'backout'):
882 with ui.configoverride(overrides, b'backout'):
883 return hg.merge(repo[b'tip'])
883 return hg.merge(repo[b'tip'])
884 return 0
884 return 0
885
885
886
886
887 @command(
887 @command(
888 b'bisect',
888 b'bisect',
889 [
889 [
890 (b'r', b'reset', False, _(b'reset bisect state')),
890 (b'r', b'reset', False, _(b'reset bisect state')),
891 (b'g', b'good', False, _(b'mark changeset good')),
891 (b'g', b'good', False, _(b'mark changeset good')),
892 (b'b', b'bad', False, _(b'mark changeset bad')),
892 (b'b', b'bad', False, _(b'mark changeset bad')),
893 (b's', b'skip', False, _(b'skip testing changeset')),
893 (b's', b'skip', False, _(b'skip testing changeset')),
894 (b'e', b'extend', False, _(b'extend the bisect range')),
894 (b'e', b'extend', False, _(b'extend the bisect range')),
895 (
895 (
896 b'c',
896 b'c',
897 b'command',
897 b'command',
898 b'',
898 b'',
899 _(b'use command to check changeset state'),
899 _(b'use command to check changeset state'),
900 _(b'CMD'),
900 _(b'CMD'),
901 ),
901 ),
902 (b'U', b'noupdate', False, _(b'do not update to target')),
902 (b'U', b'noupdate', False, _(b'do not update to target')),
903 ],
903 ],
904 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
904 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
906 )
906 )
907 def bisect(
907 def bisect(
908 ui,
908 ui,
909 repo,
909 repo,
910 positional_1=None,
910 positional_1=None,
911 positional_2=None,
911 positional_2=None,
912 command=None,
912 command=None,
913 reset=None,
913 reset=None,
914 good=None,
914 good=None,
915 bad=None,
915 bad=None,
916 skip=None,
916 skip=None,
917 extend=None,
917 extend=None,
918 noupdate=None,
918 noupdate=None,
919 ):
919 ):
920 """subdivision search of changesets
920 """subdivision search of changesets
921
921
922 This command helps to find changesets which introduce problems. To
922 This command helps to find changesets which introduce problems. To
923 use, mark the earliest changeset you know exhibits the problem as
923 use, mark the earliest changeset you know exhibits the problem as
924 bad, then mark the latest changeset which is free from the problem
924 bad, then mark the latest changeset which is free from the problem
925 as good. Bisect will update your working directory to a revision
925 as good. Bisect will update your working directory to a revision
926 for testing (unless the -U/--noupdate option is specified). Once
926 for testing (unless the -U/--noupdate option is specified). Once
927 you have performed tests, mark the working directory as good or
927 you have performed tests, mark the working directory as good or
928 bad, and bisect will either update to another candidate changeset
928 bad, and bisect will either update to another candidate changeset
929 or announce that it has found the bad revision.
929 or announce that it has found the bad revision.
930
930
931 As a shortcut, you can also use the revision argument to mark a
931 As a shortcut, you can also use the revision argument to mark a
932 revision as good or bad without checking it out first.
932 revision as good or bad without checking it out first.
933
933
934 If you supply a command, it will be used for automatic bisection.
934 If you supply a command, it will be used for automatic bisection.
935 The environment variable HG_NODE will contain the ID of the
935 The environment variable HG_NODE will contain the ID of the
936 changeset being tested. The exit status of the command will be
936 changeset being tested. The exit status of the command will be
937 used to mark revisions as good or bad: status 0 means good, 125
937 used to mark revisions as good or bad: status 0 means good, 125
938 means to skip the revision, 127 (command not found) will abort the
938 means to skip the revision, 127 (command not found) will abort the
939 bisection, and any other non-zero exit status means the revision
939 bisection, and any other non-zero exit status means the revision
940 is bad.
940 is bad.
941
941
942 .. container:: verbose
942 .. container:: verbose
943
943
944 Some examples:
944 Some examples:
945
945
946 - start a bisection with known bad revision 34, and good revision 12::
946 - start a bisection with known bad revision 34, and good revision 12::
947
947
948 hg bisect --bad 34
948 hg bisect --bad 34
949 hg bisect --good 12
949 hg bisect --good 12
950
950
951 - advance the current bisection by marking current revision as good or
951 - advance the current bisection by marking current revision as good or
952 bad::
952 bad::
953
953
954 hg bisect --good
954 hg bisect --good
955 hg bisect --bad
955 hg bisect --bad
956
956
957 - mark the current revision, or a known revision, to be skipped (e.g. if
957 - mark the current revision, or a known revision, to be skipped (e.g. if
958 that revision is not usable because of another issue)::
958 that revision is not usable because of another issue)::
959
959
960 hg bisect --skip
960 hg bisect --skip
961 hg bisect --skip 23
961 hg bisect --skip 23
962
962
963 - skip all revisions that do not touch directories ``foo`` or ``bar``::
963 - skip all revisions that do not touch directories ``foo`` or ``bar``::
964
964
965 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
965 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
966
966
967 - forget the current bisection::
967 - forget the current bisection::
968
968
969 hg bisect --reset
969 hg bisect --reset
970
970
971 - use 'make && make tests' to automatically find the first broken
971 - use 'make && make tests' to automatically find the first broken
972 revision::
972 revision::
973
973
974 hg bisect --reset
974 hg bisect --reset
975 hg bisect --bad 34
975 hg bisect --bad 34
976 hg bisect --good 12
976 hg bisect --good 12
977 hg bisect --command "make && make tests"
977 hg bisect --command "make && make tests"
978
978
979 - see all changesets whose states are already known in the current
979 - see all changesets whose states are already known in the current
980 bisection::
980 bisection::
981
981
982 hg log -r "bisect(pruned)"
982 hg log -r "bisect(pruned)"
983
983
984 - see the changeset currently being bisected (especially useful
984 - see the changeset currently being bisected (especially useful
985 if running with -U/--noupdate)::
985 if running with -U/--noupdate)::
986
986
987 hg log -r "bisect(current)"
987 hg log -r "bisect(current)"
988
988
989 - see all changesets that took part in the current bisection::
989 - see all changesets that took part in the current bisection::
990
990
991 hg log -r "bisect(range)"
991 hg log -r "bisect(range)"
992
992
993 - you can even get a nice graph::
993 - you can even get a nice graph::
994
994
995 hg log --graph -r "bisect(range)"
995 hg log --graph -r "bisect(range)"
996
996
997 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
997 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
998
998
999 Returns 0 on success.
999 Returns 0 on success.
1000 """
1000 """
1001 rev = []
1001 rev = []
1002 # backward compatibility
1002 # backward compatibility
1003 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1003 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1004 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1004 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1005 cmd = positional_1
1005 cmd = positional_1
1006 rev.append(positional_2)
1006 rev.append(positional_2)
1007 if cmd == b"good":
1007 if cmd == b"good":
1008 good = True
1008 good = True
1009 elif cmd == b"bad":
1009 elif cmd == b"bad":
1010 bad = True
1010 bad = True
1011 else:
1011 else:
1012 reset = True
1012 reset = True
1013 elif positional_2:
1013 elif positional_2:
1014 raise error.InputError(_(b'incompatible arguments'))
1014 raise error.InputError(_(b'incompatible arguments'))
1015 elif positional_1 is not None:
1015 elif positional_1 is not None:
1016 rev.append(positional_1)
1016 rev.append(positional_1)
1017
1017
1018 incompatibles = {
1018 incompatibles = {
1019 b'--bad': bad,
1019 b'--bad': bad,
1020 b'--command': bool(command),
1020 b'--command': bool(command),
1021 b'--extend': extend,
1021 b'--extend': extend,
1022 b'--good': good,
1022 b'--good': good,
1023 b'--reset': reset,
1023 b'--reset': reset,
1024 b'--skip': skip,
1024 b'--skip': skip,
1025 }
1025 }
1026
1026
1027 enabled = [x for x in incompatibles if incompatibles[x]]
1027 enabled = [x for x in incompatibles if incompatibles[x]]
1028
1028
1029 if len(enabled) > 1:
1029 if len(enabled) > 1:
1030 raise error.InputError(
1030 raise error.InputError(
1031 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1031 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1032 )
1032 )
1033
1033
1034 if reset:
1034 if reset:
1035 hbisect.resetstate(repo)
1035 hbisect.resetstate(repo)
1036 return
1036 return
1037
1037
1038 state = hbisect.load_state(repo)
1038 state = hbisect.load_state(repo)
1039
1039
1040 if rev:
1040 if rev:
1041 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1041 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1042 else:
1042 else:
1043 nodes = [repo.lookup(b'.')]
1043 nodes = [repo.lookup(b'.')]
1044
1044
1045 # update state
1045 # update state
1046 if good or bad or skip:
1046 if good or bad or skip:
1047 if good:
1047 if good:
1048 state[b'good'] += nodes
1048 state[b'good'] += nodes
1049 elif bad:
1049 elif bad:
1050 state[b'bad'] += nodes
1050 state[b'bad'] += nodes
1051 elif skip:
1051 elif skip:
1052 state[b'skip'] += nodes
1052 state[b'skip'] += nodes
1053 hbisect.save_state(repo, state)
1053 hbisect.save_state(repo, state)
1054 if not (state[b'good'] and state[b'bad']):
1054 if not (state[b'good'] and state[b'bad']):
1055 return
1055 return
1056
1056
1057 def mayupdate(repo, node, show_stats=True):
1057 def mayupdate(repo, node, show_stats=True):
1058 """common used update sequence"""
1058 """common used update sequence"""
1059 if noupdate:
1059 if noupdate:
1060 return
1060 return
1061 cmdutil.checkunfinished(repo)
1061 cmdutil.checkunfinished(repo)
1062 cmdutil.bailifchanged(repo)
1062 cmdutil.bailifchanged(repo)
1063 return hg.clean(repo, node, show_stats=show_stats)
1063 return hg.clean(repo, node, show_stats=show_stats)
1064
1064
1065 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1065 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1066
1066
1067 if command:
1067 if command:
1068 changesets = 1
1068 changesets = 1
1069 if noupdate:
1069 if noupdate:
1070 try:
1070 try:
1071 node = state[b'current'][0]
1071 node = state[b'current'][0]
1072 except LookupError:
1072 except LookupError:
1073 raise error.StateError(
1073 raise error.StateError(
1074 _(
1074 _(
1075 b'current bisect revision is unknown - '
1075 b'current bisect revision is unknown - '
1076 b'start a new bisect to fix'
1076 b'start a new bisect to fix'
1077 )
1077 )
1078 )
1078 )
1079 else:
1079 else:
1080 node, p2 = repo.dirstate.parents()
1080 node, p2 = repo.dirstate.parents()
1081 if p2 != nullid:
1081 if p2 != nullid:
1082 raise error.StateError(_(b'current bisect revision is a merge'))
1082 raise error.StateError(_(b'current bisect revision is a merge'))
1083 if rev:
1083 if rev:
1084 if not nodes:
1084 if not nodes:
1085 raise error.Abort(_(b'empty revision set'))
1085 raise error.Abort(_(b'empty revision set'))
1086 node = repo[nodes.last()].node()
1086 node = repo[nodes.last()].node()
1087 with hbisect.restore_state(repo, state, node):
1087 with hbisect.restore_state(repo, state, node):
1088 while changesets:
1088 while changesets:
1089 # update state
1089 # update state
1090 state[b'current'] = [node]
1090 state[b'current'] = [node]
1091 hbisect.save_state(repo, state)
1091 hbisect.save_state(repo, state)
1092 status = ui.system(
1092 status = ui.system(
1093 command,
1093 command,
1094 environ={b'HG_NODE': hex(node)},
1094 environ={b'HG_NODE': hex(node)},
1095 blockedtag=b'bisect_check',
1095 blockedtag=b'bisect_check',
1096 )
1096 )
1097 if status == 125:
1097 if status == 125:
1098 transition = b"skip"
1098 transition = b"skip"
1099 elif status == 0:
1099 elif status == 0:
1100 transition = b"good"
1100 transition = b"good"
1101 # status < 0 means process was killed
1101 # status < 0 means process was killed
1102 elif status == 127:
1102 elif status == 127:
1103 raise error.Abort(_(b"failed to execute %s") % command)
1103 raise error.Abort(_(b"failed to execute %s") % command)
1104 elif status < 0:
1104 elif status < 0:
1105 raise error.Abort(_(b"%s killed") % command)
1105 raise error.Abort(_(b"%s killed") % command)
1106 else:
1106 else:
1107 transition = b"bad"
1107 transition = b"bad"
1108 state[transition].append(node)
1108 state[transition].append(node)
1109 ctx = repo[node]
1109 ctx = repo[node]
1110 ui.status(
1110 ui.status(
1111 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1111 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1112 )
1112 )
1113 hbisect.checkstate(state)
1113 hbisect.checkstate(state)
1114 # bisect
1114 # bisect
1115 nodes, changesets, bgood = hbisect.bisect(repo, state)
1115 nodes, changesets, bgood = hbisect.bisect(repo, state)
1116 # update to next check
1116 # update to next check
1117 node = nodes[0]
1117 node = nodes[0]
1118 mayupdate(repo, node, show_stats=False)
1118 mayupdate(repo, node, show_stats=False)
1119 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1119 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1120 return
1120 return
1121
1121
1122 hbisect.checkstate(state)
1122 hbisect.checkstate(state)
1123
1123
1124 # actually bisect
1124 # actually bisect
1125 nodes, changesets, good = hbisect.bisect(repo, state)
1125 nodes, changesets, good = hbisect.bisect(repo, state)
1126 if extend:
1126 if extend:
1127 if not changesets:
1127 if not changesets:
1128 extendnode = hbisect.extendrange(repo, state, nodes, good)
1128 extendnode = hbisect.extendrange(repo, state, nodes, good)
1129 if extendnode is not None:
1129 if extendnode is not None:
1130 ui.write(
1130 ui.write(
1131 _(b"Extending search to changeset %d:%s\n")
1131 _(b"Extending search to changeset %d:%s\n")
1132 % (extendnode.rev(), extendnode)
1132 % (extendnode.rev(), extendnode)
1133 )
1133 )
1134 state[b'current'] = [extendnode.node()]
1134 state[b'current'] = [extendnode.node()]
1135 hbisect.save_state(repo, state)
1135 hbisect.save_state(repo, state)
1136 return mayupdate(repo, extendnode.node())
1136 return mayupdate(repo, extendnode.node())
1137 raise error.StateError(_(b"nothing to extend"))
1137 raise error.StateError(_(b"nothing to extend"))
1138
1138
1139 if changesets == 0:
1139 if changesets == 0:
1140 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1140 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1141 else:
1141 else:
1142 assert len(nodes) == 1 # only a single node can be tested next
1142 assert len(nodes) == 1 # only a single node can be tested next
1143 node = nodes[0]
1143 node = nodes[0]
1144 # compute the approximate number of remaining tests
1144 # compute the approximate number of remaining tests
1145 tests, size = 0, 2
1145 tests, size = 0, 2
1146 while size <= changesets:
1146 while size <= changesets:
1147 tests, size = tests + 1, size * 2
1147 tests, size = tests + 1, size * 2
1148 rev = repo.changelog.rev(node)
1148 rev = repo.changelog.rev(node)
1149 ui.write(
1149 ui.write(
1150 _(
1150 _(
1151 b"Testing changeset %d:%s "
1151 b"Testing changeset %d:%s "
1152 b"(%d changesets remaining, ~%d tests)\n"
1152 b"(%d changesets remaining, ~%d tests)\n"
1153 )
1153 )
1154 % (rev, short(node), changesets, tests)
1154 % (rev, short(node), changesets, tests)
1155 )
1155 )
1156 state[b'current'] = [node]
1156 state[b'current'] = [node]
1157 hbisect.save_state(repo, state)
1157 hbisect.save_state(repo, state)
1158 return mayupdate(repo, node)
1158 return mayupdate(repo, node)
1159
1159
1160
1160
1161 @command(
1161 @command(
1162 b'bookmarks|bookmark',
1162 b'bookmarks|bookmark',
1163 [
1163 [
1164 (b'f', b'force', False, _(b'force')),
1164 (b'f', b'force', False, _(b'force')),
1165 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1165 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1166 (b'd', b'delete', False, _(b'delete a given bookmark')),
1166 (b'd', b'delete', False, _(b'delete a given bookmark')),
1167 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1167 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1168 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1168 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1169 (b'l', b'list', False, _(b'list existing bookmarks')),
1169 (b'l', b'list', False, _(b'list existing bookmarks')),
1170 ]
1170 ]
1171 + formatteropts,
1171 + formatteropts,
1172 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1172 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1173 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1173 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1174 )
1174 )
1175 def bookmark(ui, repo, *names, **opts):
1175 def bookmark(ui, repo, *names, **opts):
1176 """create a new bookmark or list existing bookmarks
1176 """create a new bookmark or list existing bookmarks
1177
1177
1178 Bookmarks are labels on changesets to help track lines of development.
1178 Bookmarks are labels on changesets to help track lines of development.
1179 Bookmarks are unversioned and can be moved, renamed and deleted.
1179 Bookmarks are unversioned and can be moved, renamed and deleted.
1180 Deleting or moving a bookmark has no effect on the associated changesets.
1180 Deleting or moving a bookmark has no effect on the associated changesets.
1181
1181
1182 Creating or updating to a bookmark causes it to be marked as 'active'.
1182 Creating or updating to a bookmark causes it to be marked as 'active'.
1183 The active bookmark is indicated with a '*'.
1183 The active bookmark is indicated with a '*'.
1184 When a commit is made, the active bookmark will advance to the new commit.
1184 When a commit is made, the active bookmark will advance to the new commit.
1185 A plain :hg:`update` will also advance an active bookmark, if possible.
1185 A plain :hg:`update` will also advance an active bookmark, if possible.
1186 Updating away from a bookmark will cause it to be deactivated.
1186 Updating away from a bookmark will cause it to be deactivated.
1187
1187
1188 Bookmarks can be pushed and pulled between repositories (see
1188 Bookmarks can be pushed and pulled between repositories (see
1189 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1189 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1190 diverged, a new 'divergent bookmark' of the form 'name@path' will
1190 diverged, a new 'divergent bookmark' of the form 'name@path' will
1191 be created. Using :hg:`merge` will resolve the divergence.
1191 be created. Using :hg:`merge` will resolve the divergence.
1192
1192
1193 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1193 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1194 the active bookmark's name.
1194 the active bookmark's name.
1195
1195
1196 A bookmark named '@' has the special property that :hg:`clone` will
1196 A bookmark named '@' has the special property that :hg:`clone` will
1197 check it out by default if it exists.
1197 check it out by default if it exists.
1198
1198
1199 .. container:: verbose
1199 .. container:: verbose
1200
1200
1201 Template:
1201 Template:
1202
1202
1203 The following keywords are supported in addition to the common template
1203 The following keywords are supported in addition to the common template
1204 keywords and functions such as ``{bookmark}``. See also
1204 keywords and functions such as ``{bookmark}``. See also
1205 :hg:`help templates`.
1205 :hg:`help templates`.
1206
1206
1207 :active: Boolean. True if the bookmark is active.
1207 :active: Boolean. True if the bookmark is active.
1208
1208
1209 Examples:
1209 Examples:
1210
1210
1211 - create an active bookmark for a new line of development::
1211 - create an active bookmark for a new line of development::
1212
1212
1213 hg book new-feature
1213 hg book new-feature
1214
1214
1215 - create an inactive bookmark as a place marker::
1215 - create an inactive bookmark as a place marker::
1216
1216
1217 hg book -i reviewed
1217 hg book -i reviewed
1218
1218
1219 - create an inactive bookmark on another changeset::
1219 - create an inactive bookmark on another changeset::
1220
1220
1221 hg book -r .^ tested
1221 hg book -r .^ tested
1222
1222
1223 - rename bookmark turkey to dinner::
1223 - rename bookmark turkey to dinner::
1224
1224
1225 hg book -m turkey dinner
1225 hg book -m turkey dinner
1226
1226
1227 - move the '@' bookmark from another branch::
1227 - move the '@' bookmark from another branch::
1228
1228
1229 hg book -f @
1229 hg book -f @
1230
1230
1231 - print only the active bookmark name::
1231 - print only the active bookmark name::
1232
1232
1233 hg book -ql .
1233 hg book -ql .
1234 """
1234 """
1235 opts = pycompat.byteskwargs(opts)
1235 opts = pycompat.byteskwargs(opts)
1236 force = opts.get(b'force')
1236 force = opts.get(b'force')
1237 rev = opts.get(b'rev')
1237 rev = opts.get(b'rev')
1238 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1238 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1239
1239
1240 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1240 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1241 if action:
1241 if action:
1242 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1242 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1243 elif names or rev:
1243 elif names or rev:
1244 action = b'add'
1244 action = b'add'
1245 elif inactive:
1245 elif inactive:
1246 action = b'inactive' # meaning deactivate
1246 action = b'inactive' # meaning deactivate
1247 else:
1247 else:
1248 action = b'list'
1248 action = b'list'
1249
1249
1250 cmdutil.check_incompatible_arguments(
1250 cmdutil.check_incompatible_arguments(
1251 opts, b'inactive', [b'delete', b'list']
1251 opts, b'inactive', [b'delete', b'list']
1252 )
1252 )
1253 if not names and action in {b'add', b'delete'}:
1253 if not names and action in {b'add', b'delete'}:
1254 raise error.InputError(_(b"bookmark name required"))
1254 raise error.InputError(_(b"bookmark name required"))
1255
1255
1256 if action in {b'add', b'delete', b'rename', b'inactive'}:
1256 if action in {b'add', b'delete', b'rename', b'inactive'}:
1257 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1257 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1258 if action == b'delete':
1258 if action == b'delete':
1259 names = pycompat.maplist(repo._bookmarks.expandname, names)
1259 names = pycompat.maplist(repo._bookmarks.expandname, names)
1260 bookmarks.delete(repo, tr, names)
1260 bookmarks.delete(repo, tr, names)
1261 elif action == b'rename':
1261 elif action == b'rename':
1262 if not names:
1262 if not names:
1263 raise error.InputError(_(b"new bookmark name required"))
1263 raise error.InputError(_(b"new bookmark name required"))
1264 elif len(names) > 1:
1264 elif len(names) > 1:
1265 raise error.InputError(
1265 raise error.InputError(
1266 _(b"only one new bookmark name allowed")
1266 _(b"only one new bookmark name allowed")
1267 )
1267 )
1268 oldname = repo._bookmarks.expandname(opts[b'rename'])
1268 oldname = repo._bookmarks.expandname(opts[b'rename'])
1269 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1269 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1270 elif action == b'add':
1270 elif action == b'add':
1271 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1271 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1272 elif action == b'inactive':
1272 elif action == b'inactive':
1273 if len(repo._bookmarks) == 0:
1273 if len(repo._bookmarks) == 0:
1274 ui.status(_(b"no bookmarks set\n"))
1274 ui.status(_(b"no bookmarks set\n"))
1275 elif not repo._activebookmark:
1275 elif not repo._activebookmark:
1276 ui.status(_(b"no active bookmark\n"))
1276 ui.status(_(b"no active bookmark\n"))
1277 else:
1277 else:
1278 bookmarks.deactivate(repo)
1278 bookmarks.deactivate(repo)
1279 elif action == b'list':
1279 elif action == b'list':
1280 names = pycompat.maplist(repo._bookmarks.expandname, names)
1280 names = pycompat.maplist(repo._bookmarks.expandname, names)
1281 with ui.formatter(b'bookmarks', opts) as fm:
1281 with ui.formatter(b'bookmarks', opts) as fm:
1282 bookmarks.printbookmarks(ui, repo, fm, names)
1282 bookmarks.printbookmarks(ui, repo, fm, names)
1283 else:
1283 else:
1284 raise error.ProgrammingError(b'invalid action: %s' % action)
1284 raise error.ProgrammingError(b'invalid action: %s' % action)
1285
1285
1286
1286
1287 @command(
1287 @command(
1288 b'branch',
1288 b'branch',
1289 [
1289 [
1290 (
1290 (
1291 b'f',
1291 b'f',
1292 b'force',
1292 b'force',
1293 None,
1293 None,
1294 _(b'set branch name even if it shadows an existing branch'),
1294 _(b'set branch name even if it shadows an existing branch'),
1295 ),
1295 ),
1296 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1296 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1297 (
1297 (
1298 b'r',
1298 b'r',
1299 b'rev',
1299 b'rev',
1300 [],
1300 [],
1301 _(b'change branches of the given revs (EXPERIMENTAL)'),
1301 _(b'change branches of the given revs (EXPERIMENTAL)'),
1302 ),
1302 ),
1303 ],
1303 ],
1304 _(b'[-fC] [NAME]'),
1304 _(b'[-fC] [NAME]'),
1305 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1305 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1306 )
1306 )
1307 def branch(ui, repo, label=None, **opts):
1307 def branch(ui, repo, label=None, **opts):
1308 """set or show the current branch name
1308 """set or show the current branch name
1309
1309
1310 .. note::
1310 .. note::
1311
1311
1312 Branch names are permanent and global. Use :hg:`bookmark` to create a
1312 Branch names are permanent and global. Use :hg:`bookmark` to create a
1313 light-weight bookmark instead. See :hg:`help glossary` for more
1313 light-weight bookmark instead. See :hg:`help glossary` for more
1314 information about named branches and bookmarks.
1314 information about named branches and bookmarks.
1315
1315
1316 With no argument, show the current branch name. With one argument,
1316 With no argument, show the current branch name. With one argument,
1317 set the working directory branch name (the branch will not exist
1317 set the working directory branch name (the branch will not exist
1318 in the repository until the next commit). Standard practice
1318 in the repository until the next commit). Standard practice
1319 recommends that primary development take place on the 'default'
1319 recommends that primary development take place on the 'default'
1320 branch.
1320 branch.
1321
1321
1322 Unless -f/--force is specified, branch will not let you set a
1322 Unless -f/--force is specified, branch will not let you set a
1323 branch name that already exists.
1323 branch name that already exists.
1324
1324
1325 Use -C/--clean to reset the working directory branch to that of
1325 Use -C/--clean to reset the working directory branch to that of
1326 the parent of the working directory, negating a previous branch
1326 the parent of the working directory, negating a previous branch
1327 change.
1327 change.
1328
1328
1329 Use the command :hg:`update` to switch to an existing branch. Use
1329 Use the command :hg:`update` to switch to an existing branch. Use
1330 :hg:`commit --close-branch` to mark this branch head as closed.
1330 :hg:`commit --close-branch` to mark this branch head as closed.
1331 When all heads of a branch are closed, the branch will be
1331 When all heads of a branch are closed, the branch will be
1332 considered closed.
1332 considered closed.
1333
1333
1334 Returns 0 on success.
1334 Returns 0 on success.
1335 """
1335 """
1336 opts = pycompat.byteskwargs(opts)
1336 opts = pycompat.byteskwargs(opts)
1337 revs = opts.get(b'rev')
1337 revs = opts.get(b'rev')
1338 if label:
1338 if label:
1339 label = label.strip()
1339 label = label.strip()
1340
1340
1341 if not opts.get(b'clean') and not label:
1341 if not opts.get(b'clean') and not label:
1342 if revs:
1342 if revs:
1343 raise error.InputError(
1343 raise error.InputError(
1344 _(b"no branch name specified for the revisions")
1344 _(b"no branch name specified for the revisions")
1345 )
1345 )
1346 ui.write(b"%s\n" % repo.dirstate.branch())
1346 ui.write(b"%s\n" % repo.dirstate.branch())
1347 return
1347 return
1348
1348
1349 with repo.wlock():
1349 with repo.wlock():
1350 if opts.get(b'clean'):
1350 if opts.get(b'clean'):
1351 label = repo[b'.'].branch()
1351 label = repo[b'.'].branch()
1352 repo.dirstate.setbranch(label)
1352 repo.dirstate.setbranch(label)
1353 ui.status(_(b'reset working directory to branch %s\n') % label)
1353 ui.status(_(b'reset working directory to branch %s\n') % label)
1354 elif label:
1354 elif label:
1355
1355
1356 scmutil.checknewlabel(repo, label, b'branch')
1356 scmutil.checknewlabel(repo, label, b'branch')
1357 if revs:
1357 if revs:
1358 return cmdutil.changebranch(ui, repo, revs, label, opts)
1358 return cmdutil.changebranch(ui, repo, revs, label, opts)
1359
1359
1360 if not opts.get(b'force') and label in repo.branchmap():
1360 if not opts.get(b'force') and label in repo.branchmap():
1361 if label not in [p.branch() for p in repo[None].parents()]:
1361 if label not in [p.branch() for p in repo[None].parents()]:
1362 raise error.InputError(
1362 raise error.InputError(
1363 _(b'a branch of the same name already exists'),
1363 _(b'a branch of the same name already exists'),
1364 # i18n: "it" refers to an existing branch
1364 # i18n: "it" refers to an existing branch
1365 hint=_(b"use 'hg update' to switch to it"),
1365 hint=_(b"use 'hg update' to switch to it"),
1366 )
1366 )
1367
1367
1368 repo.dirstate.setbranch(label)
1368 repo.dirstate.setbranch(label)
1369 ui.status(_(b'marked working directory as branch %s\n') % label)
1369 ui.status(_(b'marked working directory as branch %s\n') % label)
1370
1370
1371 # find any open named branches aside from default
1371 # find any open named branches aside from default
1372 for n, h, t, c in repo.branchmap().iterbranches():
1372 for n, h, t, c in repo.branchmap().iterbranches():
1373 if n != b"default" and not c:
1373 if n != b"default" and not c:
1374 return 0
1374 return 0
1375 ui.status(
1375 ui.status(
1376 _(
1376 _(
1377 b'(branches are permanent and global, '
1377 b'(branches are permanent and global, '
1378 b'did you want a bookmark?)\n'
1378 b'did you want a bookmark?)\n'
1379 )
1379 )
1380 )
1380 )
1381
1381
1382
1382
1383 @command(
1383 @command(
1384 b'branches',
1384 b'branches',
1385 [
1385 [
1386 (
1386 (
1387 b'a',
1387 b'a',
1388 b'active',
1388 b'active',
1389 False,
1389 False,
1390 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1390 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1391 ),
1391 ),
1392 (b'c', b'closed', False, _(b'show normal and closed branches')),
1392 (b'c', b'closed', False, _(b'show normal and closed branches')),
1393 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1393 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1394 ]
1394 ]
1395 + formatteropts,
1395 + formatteropts,
1396 _(b'[-c]'),
1396 _(b'[-c]'),
1397 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1397 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1398 intents={INTENT_READONLY},
1398 intents={INTENT_READONLY},
1399 )
1399 )
1400 def branches(ui, repo, active=False, closed=False, **opts):
1400 def branches(ui, repo, active=False, closed=False, **opts):
1401 """list repository named branches
1401 """list repository named branches
1402
1402
1403 List the repository's named branches, indicating which ones are
1403 List the repository's named branches, indicating which ones are
1404 inactive. If -c/--closed is specified, also list branches which have
1404 inactive. If -c/--closed is specified, also list branches which have
1405 been marked closed (see :hg:`commit --close-branch`).
1405 been marked closed (see :hg:`commit --close-branch`).
1406
1406
1407 Use the command :hg:`update` to switch to an existing branch.
1407 Use the command :hg:`update` to switch to an existing branch.
1408
1408
1409 .. container:: verbose
1409 .. container:: verbose
1410
1410
1411 Template:
1411 Template:
1412
1412
1413 The following keywords are supported in addition to the common template
1413 The following keywords are supported in addition to the common template
1414 keywords and functions such as ``{branch}``. See also
1414 keywords and functions such as ``{branch}``. See also
1415 :hg:`help templates`.
1415 :hg:`help templates`.
1416
1416
1417 :active: Boolean. True if the branch is active.
1417 :active: Boolean. True if the branch is active.
1418 :closed: Boolean. True if the branch is closed.
1418 :closed: Boolean. True if the branch is closed.
1419 :current: Boolean. True if it is the current branch.
1419 :current: Boolean. True if it is the current branch.
1420
1420
1421 Returns 0.
1421 Returns 0.
1422 """
1422 """
1423
1423
1424 opts = pycompat.byteskwargs(opts)
1424 opts = pycompat.byteskwargs(opts)
1425 revs = opts.get(b'rev')
1425 revs = opts.get(b'rev')
1426 selectedbranches = None
1426 selectedbranches = None
1427 if revs:
1427 if revs:
1428 revs = scmutil.revrange(repo, revs)
1428 revs = scmutil.revrange(repo, revs)
1429 getbi = repo.revbranchcache().branchinfo
1429 getbi = repo.revbranchcache().branchinfo
1430 selectedbranches = {getbi(r)[0] for r in revs}
1430 selectedbranches = {getbi(r)[0] for r in revs}
1431
1431
1432 ui.pager(b'branches')
1432 ui.pager(b'branches')
1433 fm = ui.formatter(b'branches', opts)
1433 fm = ui.formatter(b'branches', opts)
1434 hexfunc = fm.hexfunc
1434 hexfunc = fm.hexfunc
1435
1435
1436 allheads = set(repo.heads())
1436 allheads = set(repo.heads())
1437 branches = []
1437 branches = []
1438 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1438 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1439 if selectedbranches is not None and tag not in selectedbranches:
1439 if selectedbranches is not None and tag not in selectedbranches:
1440 continue
1440 continue
1441 isactive = False
1441 isactive = False
1442 if not isclosed:
1442 if not isclosed:
1443 openheads = set(repo.branchmap().iteropen(heads))
1443 openheads = set(repo.branchmap().iteropen(heads))
1444 isactive = bool(openheads & allheads)
1444 isactive = bool(openheads & allheads)
1445 branches.append((tag, repo[tip], isactive, not isclosed))
1445 branches.append((tag, repo[tip], isactive, not isclosed))
1446 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1446 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1447
1447
1448 for tag, ctx, isactive, isopen in branches:
1448 for tag, ctx, isactive, isopen in branches:
1449 if active and not isactive:
1449 if active and not isactive:
1450 continue
1450 continue
1451 if isactive:
1451 if isactive:
1452 label = b'branches.active'
1452 label = b'branches.active'
1453 notice = b''
1453 notice = b''
1454 elif not isopen:
1454 elif not isopen:
1455 if not closed:
1455 if not closed:
1456 continue
1456 continue
1457 label = b'branches.closed'
1457 label = b'branches.closed'
1458 notice = _(b' (closed)')
1458 notice = _(b' (closed)')
1459 else:
1459 else:
1460 label = b'branches.inactive'
1460 label = b'branches.inactive'
1461 notice = _(b' (inactive)')
1461 notice = _(b' (inactive)')
1462 current = tag == repo.dirstate.branch()
1462 current = tag == repo.dirstate.branch()
1463 if current:
1463 if current:
1464 label = b'branches.current'
1464 label = b'branches.current'
1465
1465
1466 fm.startitem()
1466 fm.startitem()
1467 fm.write(b'branch', b'%s', tag, label=label)
1467 fm.write(b'branch', b'%s', tag, label=label)
1468 rev = ctx.rev()
1468 rev = ctx.rev()
1469 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1469 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1470 fmt = b' ' * padsize + b' %d:%s'
1470 fmt = b' ' * padsize + b' %d:%s'
1471 fm.condwrite(
1471 fm.condwrite(
1472 not ui.quiet,
1472 not ui.quiet,
1473 b'rev node',
1473 b'rev node',
1474 fmt,
1474 fmt,
1475 rev,
1475 rev,
1476 hexfunc(ctx.node()),
1476 hexfunc(ctx.node()),
1477 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1477 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1478 )
1478 )
1479 fm.context(ctx=ctx)
1479 fm.context(ctx=ctx)
1480 fm.data(active=isactive, closed=not isopen, current=current)
1480 fm.data(active=isactive, closed=not isopen, current=current)
1481 if not ui.quiet:
1481 if not ui.quiet:
1482 fm.plain(notice)
1482 fm.plain(notice)
1483 fm.plain(b'\n')
1483 fm.plain(b'\n')
1484 fm.end()
1484 fm.end()
1485
1485
1486
1486
1487 @command(
1487 @command(
1488 b'bundle',
1488 b'bundle',
1489 [
1489 [
1490 (
1490 (
1491 b'f',
1491 b'f',
1492 b'force',
1492 b'force',
1493 None,
1493 None,
1494 _(b'run even when the destination is unrelated'),
1494 _(b'run even when the destination is unrelated'),
1495 ),
1495 ),
1496 (
1496 (
1497 b'r',
1497 b'r',
1498 b'rev',
1498 b'rev',
1499 [],
1499 [],
1500 _(b'a changeset intended to be added to the destination'),
1500 _(b'a changeset intended to be added to the destination'),
1501 _(b'REV'),
1501 _(b'REV'),
1502 ),
1502 ),
1503 (
1503 (
1504 b'b',
1504 b'b',
1505 b'branch',
1505 b'branch',
1506 [],
1506 [],
1507 _(b'a specific branch you would like to bundle'),
1507 _(b'a specific branch you would like to bundle'),
1508 _(b'BRANCH'),
1508 _(b'BRANCH'),
1509 ),
1509 ),
1510 (
1510 (
1511 b'',
1511 b'',
1512 b'base',
1512 b'base',
1513 [],
1513 [],
1514 _(b'a base changeset assumed to be available at the destination'),
1514 _(b'a base changeset assumed to be available at the destination'),
1515 _(b'REV'),
1515 _(b'REV'),
1516 ),
1516 ),
1517 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1517 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1518 (
1518 (
1519 b't',
1519 b't',
1520 b'type',
1520 b'type',
1521 b'bzip2',
1521 b'bzip2',
1522 _(b'bundle compression type to use'),
1522 _(b'bundle compression type to use'),
1523 _(b'TYPE'),
1523 _(b'TYPE'),
1524 ),
1524 ),
1525 ]
1525 ]
1526 + remoteopts,
1526 + remoteopts,
1527 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1527 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1529 )
1529 )
1530 def bundle(ui, repo, fname, dest=None, **opts):
1530 def bundle(ui, repo, fname, dest=None, **opts):
1531 """create a bundle file
1531 """create a bundle file
1532
1532
1533 Generate a bundle file containing data to be transferred to another
1533 Generate a bundle file containing data to be transferred to another
1534 repository.
1534 repository.
1535
1535
1536 To create a bundle containing all changesets, use -a/--all
1536 To create a bundle containing all changesets, use -a/--all
1537 (or --base null). Otherwise, hg assumes the destination will have
1537 (or --base null). Otherwise, hg assumes the destination will have
1538 all the nodes you specify with --base parameters. Otherwise, hg
1538 all the nodes you specify with --base parameters. Otherwise, hg
1539 will assume the repository has all the nodes in destination, or
1539 will assume the repository has all the nodes in destination, or
1540 default-push/default if no destination is specified, where destination
1540 default-push/default if no destination is specified, where destination
1541 is the repository you provide through DEST option.
1541 is the repository you provide through DEST option.
1542
1542
1543 You can change bundle format with the -t/--type option. See
1543 You can change bundle format with the -t/--type option. See
1544 :hg:`help bundlespec` for documentation on this format. By default,
1544 :hg:`help bundlespec` for documentation on this format. By default,
1545 the most appropriate format is used and compression defaults to
1545 the most appropriate format is used and compression defaults to
1546 bzip2.
1546 bzip2.
1547
1547
1548 The bundle file can then be transferred using conventional means
1548 The bundle file can then be transferred using conventional means
1549 and applied to another repository with the unbundle or pull
1549 and applied to another repository with the unbundle or pull
1550 command. This is useful when direct push and pull are not
1550 command. This is useful when direct push and pull are not
1551 available or when exporting an entire repository is undesirable.
1551 available or when exporting an entire repository is undesirable.
1552
1552
1553 Applying bundles preserves all changeset contents including
1553 Applying bundles preserves all changeset contents including
1554 permissions, copy/rename information, and revision history.
1554 permissions, copy/rename information, and revision history.
1555
1555
1556 Returns 0 on success, 1 if no changes found.
1556 Returns 0 on success, 1 if no changes found.
1557 """
1557 """
1558 opts = pycompat.byteskwargs(opts)
1558 opts = pycompat.byteskwargs(opts)
1559 revs = None
1559 revs = None
1560 if b'rev' in opts:
1560 if b'rev' in opts:
1561 revstrings = opts[b'rev']
1561 revstrings = opts[b'rev']
1562 revs = scmutil.revrange(repo, revstrings)
1562 revs = scmutil.revrange(repo, revstrings)
1563 if revstrings and not revs:
1563 if revstrings and not revs:
1564 raise error.InputError(_(b'no commits to bundle'))
1564 raise error.InputError(_(b'no commits to bundle'))
1565
1565
1566 bundletype = opts.get(b'type', b'bzip2').lower()
1566 bundletype = opts.get(b'type', b'bzip2').lower()
1567 try:
1567 try:
1568 bundlespec = bundlecaches.parsebundlespec(
1568 bundlespec = bundlecaches.parsebundlespec(
1569 repo, bundletype, strict=False
1569 repo, bundletype, strict=False
1570 )
1570 )
1571 except error.UnsupportedBundleSpecification as e:
1571 except error.UnsupportedBundleSpecification as e:
1572 raise error.InputError(
1572 raise error.InputError(
1573 pycompat.bytestr(e),
1573 pycompat.bytestr(e),
1574 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1574 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1575 )
1575 )
1576 cgversion = bundlespec.contentopts[b"cg.version"]
1576 cgversion = bundlespec.contentopts[b"cg.version"]
1577
1577
1578 # Packed bundles are a pseudo bundle format for now.
1578 # Packed bundles are a pseudo bundle format for now.
1579 if cgversion == b's1':
1579 if cgversion == b's1':
1580 raise error.InputError(
1580 raise error.InputError(
1581 _(b'packed bundles cannot be produced by "hg bundle"'),
1581 _(b'packed bundles cannot be produced by "hg bundle"'),
1582 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1582 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1583 )
1583 )
1584
1584
1585 if opts.get(b'all'):
1585 if opts.get(b'all'):
1586 if dest:
1586 if dest:
1587 raise error.InputError(
1587 raise error.InputError(
1588 _(b"--all is incompatible with specifying a destination")
1588 _(b"--all is incompatible with specifying a destination")
1589 )
1589 )
1590 if opts.get(b'base'):
1590 if opts.get(b'base'):
1591 ui.warn(_(b"ignoring --base because --all was specified\n"))
1591 ui.warn(_(b"ignoring --base because --all was specified\n"))
1592 base = [nullrev]
1592 base = [nullrev]
1593 else:
1593 else:
1594 base = scmutil.revrange(repo, opts.get(b'base'))
1594 base = scmutil.revrange(repo, opts.get(b'base'))
1595 if cgversion not in changegroup.supportedoutgoingversions(repo):
1595 if cgversion not in changegroup.supportedoutgoingversions(repo):
1596 raise error.Abort(
1596 raise error.Abort(
1597 _(b"repository does not support bundle version %s") % cgversion
1597 _(b"repository does not support bundle version %s") % cgversion
1598 )
1598 )
1599
1599
1600 if base:
1600 if base:
1601 if dest:
1601 if dest:
1602 raise error.InputError(
1602 raise error.InputError(
1603 _(b"--base is incompatible with specifying a destination")
1603 _(b"--base is incompatible with specifying a destination")
1604 )
1604 )
1605 common = [repo[rev].node() for rev in base]
1605 common = [repo[rev].node() for rev in base]
1606 heads = [repo[r].node() for r in revs] if revs else None
1606 heads = [repo[r].node() for r in revs] if revs else None
1607 outgoing = discovery.outgoing(repo, common, heads)
1607 outgoing = discovery.outgoing(repo, common, heads)
1608 else:
1608 else:
1609 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1609 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1610 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1610 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1611 other = hg.peer(repo, opts, dest)
1611 other = hg.peer(repo, opts, dest)
1612 revs = [repo[r].hex() for r in revs]
1612 revs = [repo[r].hex() for r in revs]
1613 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1613 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1614 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1614 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1615 outgoing = discovery.findcommonoutgoing(
1615 outgoing = discovery.findcommonoutgoing(
1616 repo,
1616 repo,
1617 other,
1617 other,
1618 onlyheads=heads,
1618 onlyheads=heads,
1619 force=opts.get(b'force'),
1619 force=opts.get(b'force'),
1620 portable=True,
1620 portable=True,
1621 )
1621 )
1622
1622
1623 if not outgoing.missing:
1623 if not outgoing.missing:
1624 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1624 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1625 return 1
1625 return 1
1626
1626
1627 if cgversion == b'01': # bundle1
1627 if cgversion == b'01': # bundle1
1628 bversion = b'HG10' + bundlespec.wirecompression
1628 bversion = b'HG10' + bundlespec.wirecompression
1629 bcompression = None
1629 bcompression = None
1630 elif cgversion in (b'02', b'03'):
1630 elif cgversion in (b'02', b'03'):
1631 bversion = b'HG20'
1631 bversion = b'HG20'
1632 bcompression = bundlespec.wirecompression
1632 bcompression = bundlespec.wirecompression
1633 else:
1633 else:
1634 raise error.ProgrammingError(
1634 raise error.ProgrammingError(
1635 b'bundle: unexpected changegroup version %s' % cgversion
1635 b'bundle: unexpected changegroup version %s' % cgversion
1636 )
1636 )
1637
1637
1638 # TODO compression options should be derived from bundlespec parsing.
1638 # TODO compression options should be derived from bundlespec parsing.
1639 # This is a temporary hack to allow adjusting bundle compression
1639 # This is a temporary hack to allow adjusting bundle compression
1640 # level without a) formalizing the bundlespec changes to declare it
1640 # level without a) formalizing the bundlespec changes to declare it
1641 # b) introducing a command flag.
1641 # b) introducing a command flag.
1642 compopts = {}
1642 compopts = {}
1643 complevel = ui.configint(
1643 complevel = ui.configint(
1644 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1644 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1645 )
1645 )
1646 if complevel is None:
1646 if complevel is None:
1647 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1647 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1648 if complevel is not None:
1648 if complevel is not None:
1649 compopts[b'level'] = complevel
1649 compopts[b'level'] = complevel
1650
1650
1651 # Bundling of obsmarker and phases is optional as not all clients
1651 # Bundling of obsmarker and phases is optional as not all clients
1652 # support the necessary features.
1652 # support the necessary features.
1653 cfg = ui.configbool
1653 cfg = ui.configbool
1654 contentopts = {
1654 contentopts = {
1655 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1655 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1656 b'obsolescence-mandatory': cfg(
1656 b'obsolescence-mandatory': cfg(
1657 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1657 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1658 ),
1658 ),
1659 b'phases': cfg(b'experimental', b'bundle-phases'),
1659 b'phases': cfg(b'experimental', b'bundle-phases'),
1660 }
1660 }
1661 bundlespec.contentopts.update(contentopts)
1661 bundlespec.contentopts.update(contentopts)
1662
1662
1663 bundle2.writenewbundle(
1663 bundle2.writenewbundle(
1664 ui,
1664 ui,
1665 repo,
1665 repo,
1666 b'bundle',
1666 b'bundle',
1667 fname,
1667 fname,
1668 bversion,
1668 bversion,
1669 outgoing,
1669 outgoing,
1670 bundlespec.contentopts,
1670 bundlespec.contentopts,
1671 compression=bcompression,
1671 compression=bcompression,
1672 compopts=compopts,
1672 compopts=compopts,
1673 )
1673 )
1674
1674
1675
1675
1676 @command(
1676 @command(
1677 b'cat',
1677 b'cat',
1678 [
1678 [
1679 (
1679 (
1680 b'o',
1680 b'o',
1681 b'output',
1681 b'output',
1682 b'',
1682 b'',
1683 _(b'print output to file with formatted name'),
1683 _(b'print output to file with formatted name'),
1684 _(b'FORMAT'),
1684 _(b'FORMAT'),
1685 ),
1685 ),
1686 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1686 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1687 (b'', b'decode', None, _(b'apply any matching decode filter')),
1687 (b'', b'decode', None, _(b'apply any matching decode filter')),
1688 ]
1688 ]
1689 + walkopts
1689 + walkopts
1690 + formatteropts,
1690 + formatteropts,
1691 _(b'[OPTION]... FILE...'),
1691 _(b'[OPTION]... FILE...'),
1692 helpcategory=command.CATEGORY_FILE_CONTENTS,
1692 helpcategory=command.CATEGORY_FILE_CONTENTS,
1693 inferrepo=True,
1693 inferrepo=True,
1694 intents={INTENT_READONLY},
1694 intents={INTENT_READONLY},
1695 )
1695 )
1696 def cat(ui, repo, file1, *pats, **opts):
1696 def cat(ui, repo, file1, *pats, **opts):
1697 """output the current or given revision of files
1697 """output the current or given revision of files
1698
1698
1699 Print the specified files as they were at the given revision. If
1699 Print the specified files as they were at the given revision. If
1700 no revision is given, the parent of the working directory is used.
1700 no revision is given, the parent of the working directory is used.
1701
1701
1702 Output may be to a file, in which case the name of the file is
1702 Output may be to a file, in which case the name of the file is
1703 given using a template string. See :hg:`help templates`. In addition
1703 given using a template string. See :hg:`help templates`. In addition
1704 to the common template keywords, the following formatting rules are
1704 to the common template keywords, the following formatting rules are
1705 supported:
1705 supported:
1706
1706
1707 :``%%``: literal "%" character
1707 :``%%``: literal "%" character
1708 :``%s``: basename of file being printed
1708 :``%s``: basename of file being printed
1709 :``%d``: dirname of file being printed, or '.' if in repository root
1709 :``%d``: dirname of file being printed, or '.' if in repository root
1710 :``%p``: root-relative path name of file being printed
1710 :``%p``: root-relative path name of file being printed
1711 :``%H``: changeset hash (40 hexadecimal digits)
1711 :``%H``: changeset hash (40 hexadecimal digits)
1712 :``%R``: changeset revision number
1712 :``%R``: changeset revision number
1713 :``%h``: short-form changeset hash (12 hexadecimal digits)
1713 :``%h``: short-form changeset hash (12 hexadecimal digits)
1714 :``%r``: zero-padded changeset revision number
1714 :``%r``: zero-padded changeset revision number
1715 :``%b``: basename of the exporting repository
1715 :``%b``: basename of the exporting repository
1716 :``\\``: literal "\\" character
1716 :``\\``: literal "\\" character
1717
1717
1718 .. container:: verbose
1718 .. container:: verbose
1719
1719
1720 Template:
1720 Template:
1721
1721
1722 The following keywords are supported in addition to the common template
1722 The following keywords are supported in addition to the common template
1723 keywords and functions. See also :hg:`help templates`.
1723 keywords and functions. See also :hg:`help templates`.
1724
1724
1725 :data: String. File content.
1725 :data: String. File content.
1726 :path: String. Repository-absolute path of the file.
1726 :path: String. Repository-absolute path of the file.
1727
1727
1728 Returns 0 on success.
1728 Returns 0 on success.
1729 """
1729 """
1730 opts = pycompat.byteskwargs(opts)
1730 opts = pycompat.byteskwargs(opts)
1731 rev = opts.get(b'rev')
1731 rev = opts.get(b'rev')
1732 if rev:
1732 if rev:
1733 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1733 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1734 ctx = scmutil.revsingle(repo, rev)
1734 ctx = scmutil.revsingle(repo, rev)
1735 m = scmutil.match(ctx, (file1,) + pats, opts)
1735 m = scmutil.match(ctx, (file1,) + pats, opts)
1736 fntemplate = opts.pop(b'output', b'')
1736 fntemplate = opts.pop(b'output', b'')
1737 if cmdutil.isstdiofilename(fntemplate):
1737 if cmdutil.isstdiofilename(fntemplate):
1738 fntemplate = b''
1738 fntemplate = b''
1739
1739
1740 if fntemplate:
1740 if fntemplate:
1741 fm = formatter.nullformatter(ui, b'cat', opts)
1741 fm = formatter.nullformatter(ui, b'cat', opts)
1742 else:
1742 else:
1743 ui.pager(b'cat')
1743 ui.pager(b'cat')
1744 fm = ui.formatter(b'cat', opts)
1744 fm = ui.formatter(b'cat', opts)
1745 with fm:
1745 with fm:
1746 return cmdutil.cat(
1746 return cmdutil.cat(
1747 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1747 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1748 )
1748 )
1749
1749
1750
1750
1751 @command(
1751 @command(
1752 b'clone',
1752 b'clone',
1753 [
1753 [
1754 (
1754 (
1755 b'U',
1755 b'U',
1756 b'noupdate',
1756 b'noupdate',
1757 None,
1757 None,
1758 _(
1758 _(
1759 b'the clone will include an empty working '
1759 b'the clone will include an empty working '
1760 b'directory (only a repository)'
1760 b'directory (only a repository)'
1761 ),
1761 ),
1762 ),
1762 ),
1763 (
1763 (
1764 b'u',
1764 b'u',
1765 b'updaterev',
1765 b'updaterev',
1766 b'',
1766 b'',
1767 _(b'revision, tag, or branch to check out'),
1767 _(b'revision, tag, or branch to check out'),
1768 _(b'REV'),
1768 _(b'REV'),
1769 ),
1769 ),
1770 (
1770 (
1771 b'r',
1771 b'r',
1772 b'rev',
1772 b'rev',
1773 [],
1773 [],
1774 _(
1774 _(
1775 b'do not clone everything, but include this changeset'
1775 b'do not clone everything, but include this changeset'
1776 b' and its ancestors'
1776 b' and its ancestors'
1777 ),
1777 ),
1778 _(b'REV'),
1778 _(b'REV'),
1779 ),
1779 ),
1780 (
1780 (
1781 b'b',
1781 b'b',
1782 b'branch',
1782 b'branch',
1783 [],
1783 [],
1784 _(
1784 _(
1785 b'do not clone everything, but include this branch\'s'
1785 b'do not clone everything, but include this branch\'s'
1786 b' changesets and their ancestors'
1786 b' changesets and their ancestors'
1787 ),
1787 ),
1788 _(b'BRANCH'),
1788 _(b'BRANCH'),
1789 ),
1789 ),
1790 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1790 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1791 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1791 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1792 (b'', b'stream', None, _(b'clone with minimal data processing')),
1792 (b'', b'stream', None, _(b'clone with minimal data processing')),
1793 ]
1793 ]
1794 + remoteopts,
1794 + remoteopts,
1795 _(b'[OPTION]... SOURCE [DEST]'),
1795 _(b'[OPTION]... SOURCE [DEST]'),
1796 helpcategory=command.CATEGORY_REPO_CREATION,
1796 helpcategory=command.CATEGORY_REPO_CREATION,
1797 helpbasic=True,
1797 helpbasic=True,
1798 norepo=True,
1798 norepo=True,
1799 )
1799 )
1800 def clone(ui, source, dest=None, **opts):
1800 def clone(ui, source, dest=None, **opts):
1801 """make a copy of an existing repository
1801 """make a copy of an existing repository
1802
1802
1803 Create a copy of an existing repository in a new directory.
1803 Create a copy of an existing repository in a new directory.
1804
1804
1805 If no destination directory name is specified, it defaults to the
1805 If no destination directory name is specified, it defaults to the
1806 basename of the source.
1806 basename of the source.
1807
1807
1808 The location of the source is added to the new repository's
1808 The location of the source is added to the new repository's
1809 ``.hg/hgrc`` file, as the default to be used for future pulls.
1809 ``.hg/hgrc`` file, as the default to be used for future pulls.
1810
1810
1811 Only local paths and ``ssh://`` URLs are supported as
1811 Only local paths and ``ssh://`` URLs are supported as
1812 destinations. For ``ssh://`` destinations, no working directory or
1812 destinations. For ``ssh://`` destinations, no working directory or
1813 ``.hg/hgrc`` will be created on the remote side.
1813 ``.hg/hgrc`` will be created on the remote side.
1814
1814
1815 If the source repository has a bookmark called '@' set, that
1815 If the source repository has a bookmark called '@' set, that
1816 revision will be checked out in the new repository by default.
1816 revision will be checked out in the new repository by default.
1817
1817
1818 To check out a particular version, use -u/--update, or
1818 To check out a particular version, use -u/--update, or
1819 -U/--noupdate to create a clone with no working directory.
1819 -U/--noupdate to create a clone with no working directory.
1820
1820
1821 To pull only a subset of changesets, specify one or more revisions
1821 To pull only a subset of changesets, specify one or more revisions
1822 identifiers with -r/--rev or branches with -b/--branch. The
1822 identifiers with -r/--rev or branches with -b/--branch. The
1823 resulting clone will contain only the specified changesets and
1823 resulting clone will contain only the specified changesets and
1824 their ancestors. These options (or 'clone src#rev dest') imply
1824 their ancestors. These options (or 'clone src#rev dest') imply
1825 --pull, even for local source repositories.
1825 --pull, even for local source repositories.
1826
1826
1827 In normal clone mode, the remote normalizes repository data into a common
1827 In normal clone mode, the remote normalizes repository data into a common
1828 exchange format and the receiving end translates this data into its local
1828 exchange format and the receiving end translates this data into its local
1829 storage format. --stream activates a different clone mode that essentially
1829 storage format. --stream activates a different clone mode that essentially
1830 copies repository files from the remote with minimal data processing. This
1830 copies repository files from the remote with minimal data processing. This
1831 significantly reduces the CPU cost of a clone both remotely and locally.
1831 significantly reduces the CPU cost of a clone both remotely and locally.
1832 However, it often increases the transferred data size by 30-40%. This can
1832 However, it often increases the transferred data size by 30-40%. This can
1833 result in substantially faster clones where I/O throughput is plentiful,
1833 result in substantially faster clones where I/O throughput is plentiful,
1834 especially for larger repositories. A side-effect of --stream clones is
1834 especially for larger repositories. A side-effect of --stream clones is
1835 that storage settings and requirements on the remote are applied locally:
1835 that storage settings and requirements on the remote are applied locally:
1836 a modern client may inherit legacy or inefficient storage used by the
1836 a modern client may inherit legacy or inefficient storage used by the
1837 remote or a legacy Mercurial client may not be able to clone from a
1837 remote or a legacy Mercurial client may not be able to clone from a
1838 modern Mercurial remote.
1838 modern Mercurial remote.
1839
1839
1840 .. note::
1840 .. note::
1841
1841
1842 Specifying a tag will include the tagged changeset but not the
1842 Specifying a tag will include the tagged changeset but not the
1843 changeset containing the tag.
1843 changeset containing the tag.
1844
1844
1845 .. container:: verbose
1845 .. container:: verbose
1846
1846
1847 For efficiency, hardlinks are used for cloning whenever the
1847 For efficiency, hardlinks are used for cloning whenever the
1848 source and destination are on the same filesystem (note this
1848 source and destination are on the same filesystem (note this
1849 applies only to the repository data, not to the working
1849 applies only to the repository data, not to the working
1850 directory). Some filesystems, such as AFS, implement hardlinking
1850 directory). Some filesystems, such as AFS, implement hardlinking
1851 incorrectly, but do not report errors. In these cases, use the
1851 incorrectly, but do not report errors. In these cases, use the
1852 --pull option to avoid hardlinking.
1852 --pull option to avoid hardlinking.
1853
1853
1854 Mercurial will update the working directory to the first applicable
1854 Mercurial will update the working directory to the first applicable
1855 revision from this list:
1855 revision from this list:
1856
1856
1857 a) null if -U or the source repository has no changesets
1857 a) null if -U or the source repository has no changesets
1858 b) if -u . and the source repository is local, the first parent of
1858 b) if -u . and the source repository is local, the first parent of
1859 the source repository's working directory
1859 the source repository's working directory
1860 c) the changeset specified with -u (if a branch name, this means the
1860 c) the changeset specified with -u (if a branch name, this means the
1861 latest head of that branch)
1861 latest head of that branch)
1862 d) the changeset specified with -r
1862 d) the changeset specified with -r
1863 e) the tipmost head specified with -b
1863 e) the tipmost head specified with -b
1864 f) the tipmost head specified with the url#branch source syntax
1864 f) the tipmost head specified with the url#branch source syntax
1865 g) the revision marked with the '@' bookmark, if present
1865 g) the revision marked with the '@' bookmark, if present
1866 h) the tipmost head of the default branch
1866 h) the tipmost head of the default branch
1867 i) tip
1867 i) tip
1868
1868
1869 When cloning from servers that support it, Mercurial may fetch
1869 When cloning from servers that support it, Mercurial may fetch
1870 pre-generated data from a server-advertised URL or inline from the
1870 pre-generated data from a server-advertised URL or inline from the
1871 same stream. When this is done, hooks operating on incoming changesets
1871 same stream. When this is done, hooks operating on incoming changesets
1872 and changegroups may fire more than once, once for each pre-generated
1872 and changegroups may fire more than once, once for each pre-generated
1873 bundle and as well as for any additional remaining data. In addition,
1873 bundle and as well as for any additional remaining data. In addition,
1874 if an error occurs, the repository may be rolled back to a partial
1874 if an error occurs, the repository may be rolled back to a partial
1875 clone. This behavior may change in future releases.
1875 clone. This behavior may change in future releases.
1876 See :hg:`help -e clonebundles` for more.
1876 See :hg:`help -e clonebundles` for more.
1877
1877
1878 Examples:
1878 Examples:
1879
1879
1880 - clone a remote repository to a new directory named hg/::
1880 - clone a remote repository to a new directory named hg/::
1881
1881
1882 hg clone https://www.mercurial-scm.org/repo/hg/
1882 hg clone https://www.mercurial-scm.org/repo/hg/
1883
1883
1884 - create a lightweight local clone::
1884 - create a lightweight local clone::
1885
1885
1886 hg clone project/ project-feature/
1886 hg clone project/ project-feature/
1887
1887
1888 - clone from an absolute path on an ssh server (note double-slash)::
1888 - clone from an absolute path on an ssh server (note double-slash)::
1889
1889
1890 hg clone ssh://user@server//home/projects/alpha/
1890 hg clone ssh://user@server//home/projects/alpha/
1891
1891
1892 - do a streaming clone while checking out a specified version::
1892 - do a streaming clone while checking out a specified version::
1893
1893
1894 hg clone --stream http://server/repo -u 1.5
1894 hg clone --stream http://server/repo -u 1.5
1895
1895
1896 - create a repository without changesets after a particular revision::
1896 - create a repository without changesets after a particular revision::
1897
1897
1898 hg clone -r 04e544 experimental/ good/
1898 hg clone -r 04e544 experimental/ good/
1899
1899
1900 - clone (and track) a particular named branch::
1900 - clone (and track) a particular named branch::
1901
1901
1902 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1902 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1903
1903
1904 See :hg:`help urls` for details on specifying URLs.
1904 See :hg:`help urls` for details on specifying URLs.
1905
1905
1906 Returns 0 on success.
1906 Returns 0 on success.
1907 """
1907 """
1908 opts = pycompat.byteskwargs(opts)
1908 opts = pycompat.byteskwargs(opts)
1909 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1909 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1910
1910
1911 # --include/--exclude can come from narrow or sparse.
1911 # --include/--exclude can come from narrow or sparse.
1912 includepats, excludepats = None, None
1912 includepats, excludepats = None, None
1913
1913
1914 # hg.clone() differentiates between None and an empty set. So make sure
1914 # hg.clone() differentiates between None and an empty set. So make sure
1915 # patterns are sets if narrow is requested without patterns.
1915 # patterns are sets if narrow is requested without patterns.
1916 if opts.get(b'narrow'):
1916 if opts.get(b'narrow'):
1917 includepats = set()
1917 includepats = set()
1918 excludepats = set()
1918 excludepats = set()
1919
1919
1920 if opts.get(b'include'):
1920 if opts.get(b'include'):
1921 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1921 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1922 if opts.get(b'exclude'):
1922 if opts.get(b'exclude'):
1923 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1923 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1924
1924
1925 r = hg.clone(
1925 r = hg.clone(
1926 ui,
1926 ui,
1927 opts,
1927 opts,
1928 source,
1928 source,
1929 dest,
1929 dest,
1930 pull=opts.get(b'pull'),
1930 pull=opts.get(b'pull'),
1931 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1931 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1932 revs=opts.get(b'rev'),
1932 revs=opts.get(b'rev'),
1933 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1933 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1934 branch=opts.get(b'branch'),
1934 branch=opts.get(b'branch'),
1935 shareopts=opts.get(b'shareopts'),
1935 shareopts=opts.get(b'shareopts'),
1936 storeincludepats=includepats,
1936 storeincludepats=includepats,
1937 storeexcludepats=excludepats,
1937 storeexcludepats=excludepats,
1938 depth=opts.get(b'depth') or None,
1938 depth=opts.get(b'depth') or None,
1939 )
1939 )
1940
1940
1941 return r is None
1941 return r is None
1942
1942
1943
1943
1944 @command(
1944 @command(
1945 b'commit|ci',
1945 b'commit|ci',
1946 [
1946 [
1947 (
1947 (
1948 b'A',
1948 b'A',
1949 b'addremove',
1949 b'addremove',
1950 None,
1950 None,
1951 _(b'mark new/missing files as added/removed before committing'),
1951 _(b'mark new/missing files as added/removed before committing'),
1952 ),
1952 ),
1953 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1953 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1954 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1954 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1955 (b's', b'secret', None, _(b'use the secret phase for committing')),
1955 (b's', b'secret', None, _(b'use the secret phase for committing')),
1956 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1956 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1957 (
1957 (
1958 b'',
1958 b'',
1959 b'force-close-branch',
1959 b'force-close-branch',
1960 None,
1960 None,
1961 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1961 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1962 ),
1962 ),
1963 (b'i', b'interactive', None, _(b'use interactive mode')),
1963 (b'i', b'interactive', None, _(b'use interactive mode')),
1964 ]
1964 ]
1965 + walkopts
1965 + walkopts
1966 + commitopts
1966 + commitopts
1967 + commitopts2
1967 + commitopts2
1968 + subrepoopts,
1968 + subrepoopts,
1969 _(b'[OPTION]... [FILE]...'),
1969 _(b'[OPTION]... [FILE]...'),
1970 helpcategory=command.CATEGORY_COMMITTING,
1970 helpcategory=command.CATEGORY_COMMITTING,
1971 helpbasic=True,
1971 helpbasic=True,
1972 inferrepo=True,
1972 inferrepo=True,
1973 )
1973 )
1974 def commit(ui, repo, *pats, **opts):
1974 def commit(ui, repo, *pats, **opts):
1975 """commit the specified files or all outstanding changes
1975 """commit the specified files or all outstanding changes
1976
1976
1977 Commit changes to the given files into the repository. Unlike a
1977 Commit changes to the given files into the repository. Unlike a
1978 centralized SCM, this operation is a local operation. See
1978 centralized SCM, this operation is a local operation. See
1979 :hg:`push` for a way to actively distribute your changes.
1979 :hg:`push` for a way to actively distribute your changes.
1980
1980
1981 If a list of files is omitted, all changes reported by :hg:`status`
1981 If a list of files is omitted, all changes reported by :hg:`status`
1982 will be committed.
1982 will be committed.
1983
1983
1984 If you are committing the result of a merge, do not provide any
1984 If you are committing the result of a merge, do not provide any
1985 filenames or -I/-X filters.
1985 filenames or -I/-X filters.
1986
1986
1987 If no commit message is specified, Mercurial starts your
1987 If no commit message is specified, Mercurial starts your
1988 configured editor where you can enter a message. In case your
1988 configured editor where you can enter a message. In case your
1989 commit fails, you will find a backup of your message in
1989 commit fails, you will find a backup of your message in
1990 ``.hg/last-message.txt``.
1990 ``.hg/last-message.txt``.
1991
1991
1992 The --close-branch flag can be used to mark the current branch
1992 The --close-branch flag can be used to mark the current branch
1993 head closed. When all heads of a branch are closed, the branch
1993 head closed. When all heads of a branch are closed, the branch
1994 will be considered closed and no longer listed.
1994 will be considered closed and no longer listed.
1995
1995
1996 The --amend flag can be used to amend the parent of the
1996 The --amend flag can be used to amend the parent of the
1997 working directory with a new commit that contains the changes
1997 working directory with a new commit that contains the changes
1998 in the parent in addition to those currently reported by :hg:`status`,
1998 in the parent in addition to those currently reported by :hg:`status`,
1999 if there are any. The old commit is stored in a backup bundle in
1999 if there are any. The old commit is stored in a backup bundle in
2000 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2000 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2001 on how to restore it).
2001 on how to restore it).
2002
2002
2003 Message, user and date are taken from the amended commit unless
2003 Message, user and date are taken from the amended commit unless
2004 specified. When a message isn't specified on the command line,
2004 specified. When a message isn't specified on the command line,
2005 the editor will open with the message of the amended commit.
2005 the editor will open with the message of the amended commit.
2006
2006
2007 It is not possible to amend public changesets (see :hg:`help phases`)
2007 It is not possible to amend public changesets (see :hg:`help phases`)
2008 or changesets that have children.
2008 or changesets that have children.
2009
2009
2010 See :hg:`help dates` for a list of formats valid for -d/--date.
2010 See :hg:`help dates` for a list of formats valid for -d/--date.
2011
2011
2012 Returns 0 on success, 1 if nothing changed.
2012 Returns 0 on success, 1 if nothing changed.
2013
2013
2014 .. container:: verbose
2014 .. container:: verbose
2015
2015
2016 Examples:
2016 Examples:
2017
2017
2018 - commit all files ending in .py::
2018 - commit all files ending in .py::
2019
2019
2020 hg commit --include "set:**.py"
2020 hg commit --include "set:**.py"
2021
2021
2022 - commit all non-binary files::
2022 - commit all non-binary files::
2023
2023
2024 hg commit --exclude "set:binary()"
2024 hg commit --exclude "set:binary()"
2025
2025
2026 - amend the current commit and set the date to now::
2026 - amend the current commit and set the date to now::
2027
2027
2028 hg commit --amend --date now
2028 hg commit --amend --date now
2029 """
2029 """
2030 with repo.wlock(), repo.lock():
2030 with repo.wlock(), repo.lock():
2031 return _docommit(ui, repo, *pats, **opts)
2031 return _docommit(ui, repo, *pats, **opts)
2032
2032
2033
2033
2034 def _docommit(ui, repo, *pats, **opts):
2034 def _docommit(ui, repo, *pats, **opts):
2035 if opts.get('interactive'):
2035 if opts.get('interactive'):
2036 opts.pop('interactive')
2036 opts.pop('interactive')
2037 ret = cmdutil.dorecord(
2037 ret = cmdutil.dorecord(
2038 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2038 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2039 )
2039 )
2040 # ret can be 0 (no changes to record) or the value returned by
2040 # ret can be 0 (no changes to record) or the value returned by
2041 # commit(), 1 if nothing changed or None on success.
2041 # commit(), 1 if nothing changed or None on success.
2042 return 1 if ret == 0 else ret
2042 return 1 if ret == 0 else ret
2043
2043
2044 opts = pycompat.byteskwargs(opts)
2044 opts = pycompat.byteskwargs(opts)
2045 if opts.get(b'subrepos'):
2045 if opts.get(b'subrepos'):
2046 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2046 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2047 # Let --subrepos on the command line override config setting.
2047 # Let --subrepos on the command line override config setting.
2048 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2048 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2049
2049
2050 cmdutil.checkunfinished(repo, commit=True)
2050 cmdutil.checkunfinished(repo, commit=True)
2051
2051
2052 branch = repo[None].branch()
2052 branch = repo[None].branch()
2053 bheads = repo.branchheads(branch)
2053 bheads = repo.branchheads(branch)
2054 tip = repo.changelog.tip()
2054 tip = repo.changelog.tip()
2055
2055
2056 extra = {}
2056 extra = {}
2057 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2057 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2058 extra[b'close'] = b'1'
2058 extra[b'close'] = b'1'
2059
2059
2060 if repo[b'.'].closesbranch():
2060 if repo[b'.'].closesbranch():
2061 raise error.InputError(
2061 raise error.InputError(
2062 _(b'current revision is already a branch closing head')
2062 _(b'current revision is already a branch closing head')
2063 )
2063 )
2064 elif not bheads:
2064 elif not bheads:
2065 raise error.InputError(
2065 raise error.InputError(
2066 _(b'branch "%s" has no heads to close') % branch
2066 _(b'branch "%s" has no heads to close') % branch
2067 )
2067 )
2068 elif (
2068 elif (
2069 branch == repo[b'.'].branch()
2069 branch == repo[b'.'].branch()
2070 and repo[b'.'].node() not in bheads
2070 and repo[b'.'].node() not in bheads
2071 and not opts.get(b'force_close_branch')
2071 and not opts.get(b'force_close_branch')
2072 ):
2072 ):
2073 hint = _(
2073 hint = _(
2074 b'use --force-close-branch to close branch from a non-head'
2074 b'use --force-close-branch to close branch from a non-head'
2075 b' changeset'
2075 b' changeset'
2076 )
2076 )
2077 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2077 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2078 elif opts.get(b'amend'):
2078 elif opts.get(b'amend'):
2079 if (
2079 if (
2080 repo[b'.'].p1().branch() != branch
2080 repo[b'.'].p1().branch() != branch
2081 and repo[b'.'].p2().branch() != branch
2081 and repo[b'.'].p2().branch() != branch
2082 ):
2082 ):
2083 raise error.InputError(_(b'can only close branch heads'))
2083 raise error.InputError(_(b'can only close branch heads'))
2084
2084
2085 if opts.get(b'amend'):
2085 if opts.get(b'amend'):
2086 if ui.configbool(b'ui', b'commitsubrepos'):
2086 if ui.configbool(b'ui', b'commitsubrepos'):
2087 raise error.InputError(
2087 raise error.InputError(
2088 _(b'cannot amend with ui.commitsubrepos enabled')
2088 _(b'cannot amend with ui.commitsubrepos enabled')
2089 )
2089 )
2090
2090
2091 old = repo[b'.']
2091 old = repo[b'.']
2092 rewriteutil.precheck(repo, [old.rev()], b'amend')
2092 rewriteutil.precheck(repo, [old.rev()], b'amend')
2093
2093
2094 # Currently histedit gets confused if an amend happens while histedit
2094 # Currently histedit gets confused if an amend happens while histedit
2095 # is in progress. Since we have a checkunfinished command, we are
2095 # is in progress. Since we have a checkunfinished command, we are
2096 # temporarily honoring it.
2096 # temporarily honoring it.
2097 #
2097 #
2098 # Note: eventually this guard will be removed. Please do not expect
2098 # Note: eventually this guard will be removed. Please do not expect
2099 # this behavior to remain.
2099 # this behavior to remain.
2100 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2100 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2101 cmdutil.checkunfinished(repo)
2101 cmdutil.checkunfinished(repo)
2102
2102
2103 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2103 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2104 if node == old.node():
2104 if node == old.node():
2105 ui.status(_(b"nothing changed\n"))
2105 ui.status(_(b"nothing changed\n"))
2106 return 1
2106 return 1
2107 else:
2107 else:
2108
2108
2109 def commitfunc(ui, repo, message, match, opts):
2109 def commitfunc(ui, repo, message, match, opts):
2110 overrides = {}
2110 overrides = {}
2111 if opts.get(b'secret'):
2111 if opts.get(b'secret'):
2112 overrides[(b'phases', b'new-commit')] = b'secret'
2112 overrides[(b'phases', b'new-commit')] = b'secret'
2113
2113
2114 baseui = repo.baseui
2114 baseui = repo.baseui
2115 with baseui.configoverride(overrides, b'commit'):
2115 with baseui.configoverride(overrides, b'commit'):
2116 with ui.configoverride(overrides, b'commit'):
2116 with ui.configoverride(overrides, b'commit'):
2117 editform = cmdutil.mergeeditform(
2117 editform = cmdutil.mergeeditform(
2118 repo[None], b'commit.normal'
2118 repo[None], b'commit.normal'
2119 )
2119 )
2120 editor = cmdutil.getcommiteditor(
2120 editor = cmdutil.getcommiteditor(
2121 editform=editform, **pycompat.strkwargs(opts)
2121 editform=editform, **pycompat.strkwargs(opts)
2122 )
2122 )
2123 return repo.commit(
2123 return repo.commit(
2124 message,
2124 message,
2125 opts.get(b'user'),
2125 opts.get(b'user'),
2126 opts.get(b'date'),
2126 opts.get(b'date'),
2127 match,
2127 match,
2128 editor=editor,
2128 editor=editor,
2129 extra=extra,
2129 extra=extra,
2130 )
2130 )
2131
2131
2132 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2132 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2133
2133
2134 if not node:
2134 if not node:
2135 stat = cmdutil.postcommitstatus(repo, pats, opts)
2135 stat = cmdutil.postcommitstatus(repo, pats, opts)
2136 if stat.deleted:
2136 if stat.deleted:
2137 ui.status(
2137 ui.status(
2138 _(
2138 _(
2139 b"nothing changed (%d missing files, see "
2139 b"nothing changed (%d missing files, see "
2140 b"'hg status')\n"
2140 b"'hg status')\n"
2141 )
2141 )
2142 % len(stat.deleted)
2142 % len(stat.deleted)
2143 )
2143 )
2144 else:
2144 else:
2145 ui.status(_(b"nothing changed\n"))
2145 ui.status(_(b"nothing changed\n"))
2146 return 1
2146 return 1
2147
2147
2148 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2148 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2149
2149
2150 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2150 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2151 status(
2151 status(
2152 ui,
2152 ui,
2153 repo,
2153 repo,
2154 modified=True,
2154 modified=True,
2155 added=True,
2155 added=True,
2156 removed=True,
2156 removed=True,
2157 deleted=True,
2157 deleted=True,
2158 unknown=True,
2158 unknown=True,
2159 subrepos=opts.get(b'subrepos'),
2159 subrepos=opts.get(b'subrepos'),
2160 )
2160 )
2161
2161
2162
2162
2163 @command(
2163 @command(
2164 b'config|showconfig|debugconfig',
2164 b'config|showconfig|debugconfig',
2165 [
2165 [
2166 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2166 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2167 (b'e', b'edit', None, _(b'edit user config')),
2167 (b'e', b'edit', None, _(b'edit user config')),
2168 (b'l', b'local', None, _(b'edit repository config')),
2168 (b'l', b'local', None, _(b'edit repository config')),
2169 (
2169 (
2170 b'',
2170 b'',
2171 b'shared',
2171 b'shared',
2172 None,
2172 None,
2173 _(b'edit shared source repository config (EXPERIMENTAL)'),
2173 _(b'edit shared source repository config (EXPERIMENTAL)'),
2174 ),
2174 ),
2175 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2175 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2176 (b'g', b'global', None, _(b'edit global config')),
2176 (b'g', b'global', None, _(b'edit global config')),
2177 ]
2177 ]
2178 + formatteropts,
2178 + formatteropts,
2179 _(b'[-u] [NAME]...'),
2179 _(b'[-u] [NAME]...'),
2180 helpcategory=command.CATEGORY_HELP,
2180 helpcategory=command.CATEGORY_HELP,
2181 optionalrepo=True,
2181 optionalrepo=True,
2182 intents={INTENT_READONLY},
2182 intents={INTENT_READONLY},
2183 )
2183 )
2184 def config(ui, repo, *values, **opts):
2184 def config(ui, repo, *values, **opts):
2185 """show combined config settings from all hgrc files
2185 """show combined config settings from all hgrc files
2186
2186
2187 With no arguments, print names and values of all config items.
2187 With no arguments, print names and values of all config items.
2188
2188
2189 With one argument of the form section.name, print just the value
2189 With one argument of the form section.name, print just the value
2190 of that config item.
2190 of that config item.
2191
2191
2192 With multiple arguments, print names and values of all config
2192 With multiple arguments, print names and values of all config
2193 items with matching section names or section.names.
2193 items with matching section names or section.names.
2194
2194
2195 With --edit, start an editor on the user-level config file. With
2195 With --edit, start an editor on the user-level config file. With
2196 --global, edit the system-wide config file. With --local, edit the
2196 --global, edit the system-wide config file. With --local, edit the
2197 repository-level config file.
2197 repository-level config file.
2198
2198
2199 With --debug, the source (filename and line number) is printed
2199 With --debug, the source (filename and line number) is printed
2200 for each config item.
2200 for each config item.
2201
2201
2202 See :hg:`help config` for more information about config files.
2202 See :hg:`help config` for more information about config files.
2203
2203
2204 .. container:: verbose
2204 .. container:: verbose
2205
2205
2206 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2206 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2207 This file is not shared across shares when in share-safe mode.
2207 This file is not shared across shares when in share-safe mode.
2208
2208
2209 Template:
2209 Template:
2210
2210
2211 The following keywords are supported. See also :hg:`help templates`.
2211 The following keywords are supported. See also :hg:`help templates`.
2212
2212
2213 :name: String. Config name.
2213 :name: String. Config name.
2214 :source: String. Filename and line number where the item is defined.
2214 :source: String. Filename and line number where the item is defined.
2215 :value: String. Config value.
2215 :value: String. Config value.
2216
2216
2217 The --shared flag can be used to edit the config file of shared source
2217 The --shared flag can be used to edit the config file of shared source
2218 repository. It only works when you have shared using the experimental
2218 repository. It only works when you have shared using the experimental
2219 share safe feature.
2219 share safe feature.
2220
2220
2221 Returns 0 on success, 1 if NAME does not exist.
2221 Returns 0 on success, 1 if NAME does not exist.
2222
2222
2223 """
2223 """
2224
2224
2225 opts = pycompat.byteskwargs(opts)
2225 opts = pycompat.byteskwargs(opts)
2226 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2226 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2227 if any(opts.get(o) for o in editopts):
2227 if any(opts.get(o) for o in editopts):
2228 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2228 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2229 if opts.get(b'local'):
2229 if opts.get(b'local'):
2230 if not repo:
2230 if not repo:
2231 raise error.InputError(
2231 raise error.InputError(
2232 _(b"can't use --local outside a repository")
2232 _(b"can't use --local outside a repository")
2233 )
2233 )
2234 paths = [repo.vfs.join(b'hgrc')]
2234 paths = [repo.vfs.join(b'hgrc')]
2235 elif opts.get(b'global'):
2235 elif opts.get(b'global'):
2236 paths = rcutil.systemrcpath()
2236 paths = rcutil.systemrcpath()
2237 elif opts.get(b'shared'):
2237 elif opts.get(b'shared'):
2238 if not repo.shared():
2238 if not repo.shared():
2239 raise error.InputError(
2239 raise error.InputError(
2240 _(b"repository is not shared; can't use --shared")
2240 _(b"repository is not shared; can't use --shared")
2241 )
2241 )
2242 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2242 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2243 raise error.InputError(
2243 raise error.InputError(
2244 _(
2244 _(
2245 b"share safe feature not enabled; "
2245 b"share safe feature not enabled; "
2246 b"unable to edit shared source repository config"
2246 b"unable to edit shared source repository config"
2247 )
2247 )
2248 )
2248 )
2249 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2249 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2250 elif opts.get(b'non_shared'):
2250 elif opts.get(b'non_shared'):
2251 paths = [repo.vfs.join(b'hgrc-not-shared')]
2251 paths = [repo.vfs.join(b'hgrc-not-shared')]
2252 else:
2252 else:
2253 paths = rcutil.userrcpath()
2253 paths = rcutil.userrcpath()
2254
2254
2255 for f in paths:
2255 for f in paths:
2256 if os.path.exists(f):
2256 if os.path.exists(f):
2257 break
2257 break
2258 else:
2258 else:
2259 if opts.get(b'global'):
2259 if opts.get(b'global'):
2260 samplehgrc = uimod.samplehgrcs[b'global']
2260 samplehgrc = uimod.samplehgrcs[b'global']
2261 elif opts.get(b'local'):
2261 elif opts.get(b'local'):
2262 samplehgrc = uimod.samplehgrcs[b'local']
2262 samplehgrc = uimod.samplehgrcs[b'local']
2263 else:
2263 else:
2264 samplehgrc = uimod.samplehgrcs[b'user']
2264 samplehgrc = uimod.samplehgrcs[b'user']
2265
2265
2266 f = paths[0]
2266 f = paths[0]
2267 fp = open(f, b"wb")
2267 fp = open(f, b"wb")
2268 fp.write(util.tonativeeol(samplehgrc))
2268 fp.write(util.tonativeeol(samplehgrc))
2269 fp.close()
2269 fp.close()
2270
2270
2271 editor = ui.geteditor()
2271 editor = ui.geteditor()
2272 ui.system(
2272 ui.system(
2273 b"%s \"%s\"" % (editor, f),
2273 b"%s \"%s\"" % (editor, f),
2274 onerr=error.InputError,
2274 onerr=error.InputError,
2275 errprefix=_(b"edit failed"),
2275 errprefix=_(b"edit failed"),
2276 blockedtag=b'config_edit',
2276 blockedtag=b'config_edit',
2277 )
2277 )
2278 return
2278 return
2279 ui.pager(b'config')
2279 ui.pager(b'config')
2280 fm = ui.formatter(b'config', opts)
2280 fm = ui.formatter(b'config', opts)
2281 for t, f in rcutil.rccomponents():
2281 for t, f in rcutil.rccomponents():
2282 if t == b'path':
2282 if t == b'path':
2283 ui.debug(b'read config from: %s\n' % f)
2283 ui.debug(b'read config from: %s\n' % f)
2284 elif t == b'resource':
2284 elif t == b'resource':
2285 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2285 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2286 elif t == b'items':
2286 elif t == b'items':
2287 # Don't print anything for 'items'.
2287 # Don't print anything for 'items'.
2288 pass
2288 pass
2289 else:
2289 else:
2290 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2290 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2291 untrusted = bool(opts.get(b'untrusted'))
2291 untrusted = bool(opts.get(b'untrusted'))
2292
2292
2293 selsections = selentries = []
2293 selsections = selentries = []
2294 if values:
2294 if values:
2295 selsections = [v for v in values if b'.' not in v]
2295 selsections = [v for v in values if b'.' not in v]
2296 selentries = [v for v in values if b'.' in v]
2296 selentries = [v for v in values if b'.' in v]
2297 uniquesel = len(selentries) == 1 and not selsections
2297 uniquesel = len(selentries) == 1 and not selsections
2298 selsections = set(selsections)
2298 selsections = set(selsections)
2299 selentries = set(selentries)
2299 selentries = set(selentries)
2300
2300
2301 matched = False
2301 matched = False
2302 for section, name, value in ui.walkconfig(untrusted=untrusted):
2302 for section, name, value in ui.walkconfig(untrusted=untrusted):
2303 source = ui.configsource(section, name, untrusted)
2303 source = ui.configsource(section, name, untrusted)
2304 value = pycompat.bytestr(value)
2304 value = pycompat.bytestr(value)
2305 defaultvalue = ui.configdefault(section, name)
2305 defaultvalue = ui.configdefault(section, name)
2306 if fm.isplain():
2306 if fm.isplain():
2307 source = source or b'none'
2307 source = source or b'none'
2308 value = value.replace(b'\n', b'\\n')
2308 value = value.replace(b'\n', b'\\n')
2309 entryname = section + b'.' + name
2309 entryname = section + b'.' + name
2310 if values and not (section in selsections or entryname in selentries):
2310 if values and not (section in selsections or entryname in selentries):
2311 continue
2311 continue
2312 fm.startitem()
2312 fm.startitem()
2313 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2313 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2314 if uniquesel:
2314 if uniquesel:
2315 fm.data(name=entryname)
2315 fm.data(name=entryname)
2316 fm.write(b'value', b'%s\n', value)
2316 fm.write(b'value', b'%s\n', value)
2317 else:
2317 else:
2318 fm.write(b'name value', b'%s=%s\n', entryname, value)
2318 fm.write(b'name value', b'%s=%s\n', entryname, value)
2319 if formatter.isprintable(defaultvalue):
2319 if formatter.isprintable(defaultvalue):
2320 fm.data(defaultvalue=defaultvalue)
2320 fm.data(defaultvalue=defaultvalue)
2321 elif isinstance(defaultvalue, list) and all(
2321 elif isinstance(defaultvalue, list) and all(
2322 formatter.isprintable(e) for e in defaultvalue
2322 formatter.isprintable(e) for e in defaultvalue
2323 ):
2323 ):
2324 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2324 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2325 # TODO: no idea how to process unsupported defaultvalue types
2325 # TODO: no idea how to process unsupported defaultvalue types
2326 matched = True
2326 matched = True
2327 fm.end()
2327 fm.end()
2328 if matched:
2328 if matched:
2329 return 0
2329 return 0
2330 return 1
2330 return 1
2331
2331
2332
2332
2333 @command(
2333 @command(
2334 b'continue',
2334 b'continue',
2335 dryrunopts,
2335 dryrunopts,
2336 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2336 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2337 helpbasic=True,
2337 helpbasic=True,
2338 )
2338 )
2339 def continuecmd(ui, repo, **opts):
2339 def continuecmd(ui, repo, **opts):
2340 """resumes an interrupted operation (EXPERIMENTAL)
2340 """resumes an interrupted operation (EXPERIMENTAL)
2341
2341
2342 Finishes a multistep operation like graft, histedit, rebase, merge,
2342 Finishes a multistep operation like graft, histedit, rebase, merge,
2343 and unshelve if they are in an interrupted state.
2343 and unshelve if they are in an interrupted state.
2344
2344
2345 use --dry-run/-n to dry run the command.
2345 use --dry-run/-n to dry run the command.
2346 """
2346 """
2347 dryrun = opts.get('dry_run')
2347 dryrun = opts.get('dry_run')
2348 contstate = cmdutil.getunfinishedstate(repo)
2348 contstate = cmdutil.getunfinishedstate(repo)
2349 if not contstate:
2349 if not contstate:
2350 raise error.StateError(_(b'no operation in progress'))
2350 raise error.StateError(_(b'no operation in progress'))
2351 if not contstate.continuefunc:
2351 if not contstate.continuefunc:
2352 raise error.StateError(
2352 raise error.StateError(
2353 (
2353 (
2354 _(b"%s in progress but does not support 'hg continue'")
2354 _(b"%s in progress but does not support 'hg continue'")
2355 % (contstate._opname)
2355 % (contstate._opname)
2356 ),
2356 ),
2357 hint=contstate.continuemsg(),
2357 hint=contstate.continuemsg(),
2358 )
2358 )
2359 if dryrun:
2359 if dryrun:
2360 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2360 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2361 return
2361 return
2362 return contstate.continuefunc(ui, repo)
2362 return contstate.continuefunc(ui, repo)
2363
2363
2364
2364
2365 @command(
2365 @command(
2366 b'copy|cp',
2366 b'copy|cp',
2367 [
2367 [
2368 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2368 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2369 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2369 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2370 (
2370 (
2371 b'',
2371 b'',
2372 b'at-rev',
2372 b'at-rev',
2373 b'',
2373 b'',
2374 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2374 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2375 _(b'REV'),
2375 _(b'REV'),
2376 ),
2376 ),
2377 (
2377 (
2378 b'f',
2378 b'f',
2379 b'force',
2379 b'force',
2380 None,
2380 None,
2381 _(b'forcibly copy over an existing managed file'),
2381 _(b'forcibly copy over an existing managed file'),
2382 ),
2382 ),
2383 ]
2383 ]
2384 + walkopts
2384 + walkopts
2385 + dryrunopts,
2385 + dryrunopts,
2386 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2386 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2387 helpcategory=command.CATEGORY_FILE_CONTENTS,
2387 helpcategory=command.CATEGORY_FILE_CONTENTS,
2388 )
2388 )
2389 def copy(ui, repo, *pats, **opts):
2389 def copy(ui, repo, *pats, **opts):
2390 """mark files as copied for the next commit
2390 """mark files as copied for the next commit
2391
2391
2392 Mark dest as having copies of source files. If dest is a
2392 Mark dest as having copies of source files. If dest is a
2393 directory, copies are put in that directory. If dest is a file,
2393 directory, copies are put in that directory. If dest is a file,
2394 the source must be a single file.
2394 the source must be a single file.
2395
2395
2396 By default, this command copies the contents of files as they
2396 By default, this command copies the contents of files as they
2397 exist in the working directory. If invoked with -A/--after, the
2397 exist in the working directory. If invoked with -A/--after, the
2398 operation is recorded, but no copying is performed.
2398 operation is recorded, but no copying is performed.
2399
2399
2400 To undo marking a destination file as copied, use --forget. With that
2400 To undo marking a destination file as copied, use --forget. With that
2401 option, all given (positional) arguments are unmarked as copies. The
2401 option, all given (positional) arguments are unmarked as copies. The
2402 destination file(s) will be left in place (still tracked).
2402 destination file(s) will be left in place (still tracked).
2403
2403
2404 This command takes effect with the next commit by default.
2404 This command takes effect with the next commit by default.
2405
2405
2406 Returns 0 on success, 1 if errors are encountered.
2406 Returns 0 on success, 1 if errors are encountered.
2407 """
2407 """
2408 opts = pycompat.byteskwargs(opts)
2408 opts = pycompat.byteskwargs(opts)
2409 with repo.wlock():
2409 with repo.wlock():
2410 return cmdutil.copy(ui, repo, pats, opts)
2410 return cmdutil.copy(ui, repo, pats, opts)
2411
2411
2412
2412
2413 @command(
2413 @command(
2414 b'debugcommands',
2414 b'debugcommands',
2415 [],
2415 [],
2416 _(b'[COMMAND]'),
2416 _(b'[COMMAND]'),
2417 helpcategory=command.CATEGORY_HELP,
2417 helpcategory=command.CATEGORY_HELP,
2418 norepo=True,
2418 norepo=True,
2419 )
2419 )
2420 def debugcommands(ui, cmd=b'', *args):
2420 def debugcommands(ui, cmd=b'', *args):
2421 """list all available commands and options"""
2421 """list all available commands and options"""
2422 for cmd, vals in sorted(pycompat.iteritems(table)):
2422 for cmd, vals in sorted(pycompat.iteritems(table)):
2423 cmd = cmd.split(b'|')[0]
2423 cmd = cmd.split(b'|')[0]
2424 opts = b', '.join([i[1] for i in vals[1]])
2424 opts = b', '.join([i[1] for i in vals[1]])
2425 ui.write(b'%s: %s\n' % (cmd, opts))
2425 ui.write(b'%s: %s\n' % (cmd, opts))
2426
2426
2427
2427
2428 @command(
2428 @command(
2429 b'debugcomplete',
2429 b'debugcomplete',
2430 [(b'o', b'options', None, _(b'show the command options'))],
2430 [(b'o', b'options', None, _(b'show the command options'))],
2431 _(b'[-o] CMD'),
2431 _(b'[-o] CMD'),
2432 helpcategory=command.CATEGORY_HELP,
2432 helpcategory=command.CATEGORY_HELP,
2433 norepo=True,
2433 norepo=True,
2434 )
2434 )
2435 def debugcomplete(ui, cmd=b'', **opts):
2435 def debugcomplete(ui, cmd=b'', **opts):
2436 """returns the completion list associated with the given command"""
2436 """returns the completion list associated with the given command"""
2437
2437
2438 if opts.get('options'):
2438 if opts.get('options'):
2439 options = []
2439 options = []
2440 otables = [globalopts]
2440 otables = [globalopts]
2441 if cmd:
2441 if cmd:
2442 aliases, entry = cmdutil.findcmd(cmd, table, False)
2442 aliases, entry = cmdutil.findcmd(cmd, table, False)
2443 otables.append(entry[1])
2443 otables.append(entry[1])
2444 for t in otables:
2444 for t in otables:
2445 for o in t:
2445 for o in t:
2446 if b"(DEPRECATED)" in o[3]:
2446 if b"(DEPRECATED)" in o[3]:
2447 continue
2447 continue
2448 if o[0]:
2448 if o[0]:
2449 options.append(b'-%s' % o[0])
2449 options.append(b'-%s' % o[0])
2450 options.append(b'--%s' % o[1])
2450 options.append(b'--%s' % o[1])
2451 ui.write(b"%s\n" % b"\n".join(options))
2451 ui.write(b"%s\n" % b"\n".join(options))
2452 return
2452 return
2453
2453
2454 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2454 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2455 if ui.verbose:
2455 if ui.verbose:
2456 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2456 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2457 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2457 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2458
2458
2459
2459
2460 @command(
2460 @command(
2461 b'diff',
2461 b'diff',
2462 [
2462 [
2463 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2463 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2464 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2464 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2465 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2465 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2466 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2466 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2467 ]
2467 ]
2468 + diffopts
2468 + diffopts
2469 + diffopts2
2469 + diffopts2
2470 + walkopts
2470 + walkopts
2471 + subrepoopts,
2471 + subrepoopts,
2472 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2472 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2473 helpcategory=command.CATEGORY_FILE_CONTENTS,
2473 helpcategory=command.CATEGORY_FILE_CONTENTS,
2474 helpbasic=True,
2474 helpbasic=True,
2475 inferrepo=True,
2475 inferrepo=True,
2476 intents={INTENT_READONLY},
2476 intents={INTENT_READONLY},
2477 )
2477 )
2478 def diff(ui, repo, *pats, **opts):
2478 def diff(ui, repo, *pats, **opts):
2479 """diff repository (or selected files)
2479 """diff repository (or selected files)
2480
2480
2481 Show differences between revisions for the specified files.
2481 Show differences between revisions for the specified files.
2482
2482
2483 Differences between files are shown using the unified diff format.
2483 Differences between files are shown using the unified diff format.
2484
2484
2485 .. note::
2485 .. note::
2486
2486
2487 :hg:`diff` may generate unexpected results for merges, as it will
2487 :hg:`diff` may generate unexpected results for merges, as it will
2488 default to comparing against the working directory's first
2488 default to comparing against the working directory's first
2489 parent changeset if no revisions are specified.
2489 parent changeset if no revisions are specified.
2490
2490
2491 By default, the working directory files are compared to its first parent. To
2491 By default, the working directory files are compared to its first parent. To
2492 see the differences from another revision, use --from. To see the difference
2492 see the differences from another revision, use --from. To see the difference
2493 to another revision, use --to. For example, :hg:`diff --from .^` will show
2493 to another revision, use --to. For example, :hg:`diff --from .^` will show
2494 the differences from the working copy's grandparent to the working copy,
2494 the differences from the working copy's grandparent to the working copy,
2495 :hg:`diff --to .` will show the diff from the working copy to its parent
2495 :hg:`diff --to .` will show the diff from the working copy to its parent
2496 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2496 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2497 show the diff between those two revisions.
2497 show the diff between those two revisions.
2498
2498
2499 Alternatively you can specify -c/--change with a revision to see the changes
2499 Alternatively you can specify -c/--change with a revision to see the changes
2500 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2500 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2501 equivalent to :hg:`diff --from 42^ --to 42`)
2501 equivalent to :hg:`diff --from 42^ --to 42`)
2502
2502
2503 Without the -a/--text option, diff will avoid generating diffs of
2503 Without the -a/--text option, diff will avoid generating diffs of
2504 files it detects as binary. With -a, diff will generate a diff
2504 files it detects as binary. With -a, diff will generate a diff
2505 anyway, probably with undesirable results.
2505 anyway, probably with undesirable results.
2506
2506
2507 Use the -g/--git option to generate diffs in the git extended diff
2507 Use the -g/--git option to generate diffs in the git extended diff
2508 format. For more information, read :hg:`help diffs`.
2508 format. For more information, read :hg:`help diffs`.
2509
2509
2510 .. container:: verbose
2510 .. container:: verbose
2511
2511
2512 Examples:
2512 Examples:
2513
2513
2514 - compare a file in the current working directory to its parent::
2514 - compare a file in the current working directory to its parent::
2515
2515
2516 hg diff foo.c
2516 hg diff foo.c
2517
2517
2518 - compare two historical versions of a directory, with rename info::
2518 - compare two historical versions of a directory, with rename info::
2519
2519
2520 hg diff --git --from 1.0 --to 1.2 lib/
2520 hg diff --git --from 1.0 --to 1.2 lib/
2521
2521
2522 - get change stats relative to the last change on some date::
2522 - get change stats relative to the last change on some date::
2523
2523
2524 hg diff --stat --from "date('may 2')"
2524 hg diff --stat --from "date('may 2')"
2525
2525
2526 - diff all newly-added files that contain a keyword::
2526 - diff all newly-added files that contain a keyword::
2527
2527
2528 hg diff "set:added() and grep(GNU)"
2528 hg diff "set:added() and grep(GNU)"
2529
2529
2530 - compare a revision and its parents::
2530 - compare a revision and its parents::
2531
2531
2532 hg diff -c 9353 # compare against first parent
2532 hg diff -c 9353 # compare against first parent
2533 hg diff --from 9353^ --to 9353 # same using revset syntax
2533 hg diff --from 9353^ --to 9353 # same using revset syntax
2534 hg diff --from 9353^2 --to 9353 # compare against the second parent
2534 hg diff --from 9353^2 --to 9353 # compare against the second parent
2535
2535
2536 Returns 0 on success.
2536 Returns 0 on success.
2537 """
2537 """
2538
2538
2539 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2539 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2540 opts = pycompat.byteskwargs(opts)
2540 opts = pycompat.byteskwargs(opts)
2541 revs = opts.get(b'rev')
2541 revs = opts.get(b'rev')
2542 change = opts.get(b'change')
2542 change = opts.get(b'change')
2543 from_rev = opts.get(b'from')
2543 from_rev = opts.get(b'from')
2544 to_rev = opts.get(b'to')
2544 to_rev = opts.get(b'to')
2545 stat = opts.get(b'stat')
2545 stat = opts.get(b'stat')
2546 reverse = opts.get(b'reverse')
2546 reverse = opts.get(b'reverse')
2547
2547
2548 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2548 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2549 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2549 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2550 if change:
2550 if change:
2551 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2551 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2552 ctx2 = scmutil.revsingle(repo, change, None)
2552 ctx2 = scmutil.revsingle(repo, change, None)
2553 ctx1 = logcmdutil.diff_parent(ctx2)
2553 ctx1 = logcmdutil.diff_parent(ctx2)
2554 elif from_rev or to_rev:
2554 elif from_rev or to_rev:
2555 repo = scmutil.unhidehashlikerevs(
2555 repo = scmutil.unhidehashlikerevs(
2556 repo, [from_rev] + [to_rev], b'nowarn'
2556 repo, [from_rev] + [to_rev], b'nowarn'
2557 )
2557 )
2558 ctx1 = scmutil.revsingle(repo, from_rev, None)
2558 ctx1 = scmutil.revsingle(repo, from_rev, None)
2559 ctx2 = scmutil.revsingle(repo, to_rev, None)
2559 ctx2 = scmutil.revsingle(repo, to_rev, None)
2560 else:
2560 else:
2561 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2561 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2562 ctx1, ctx2 = scmutil.revpair(repo, revs)
2562 ctx1, ctx2 = scmutil.revpair(repo, revs)
2563
2563
2564 if reverse:
2564 if reverse:
2565 ctxleft = ctx2
2565 ctxleft = ctx2
2566 ctxright = ctx1
2566 ctxright = ctx1
2567 else:
2567 else:
2568 ctxleft = ctx1
2568 ctxleft = ctx1
2569 ctxright = ctx2
2569 ctxright = ctx2
2570
2570
2571 diffopts = patch.diffallopts(ui, opts)
2571 diffopts = patch.diffallopts(ui, opts)
2572 m = scmutil.match(ctx2, pats, opts)
2572 m = scmutil.match(ctx2, pats, opts)
2573 m = repo.narrowmatch(m)
2573 m = repo.narrowmatch(m)
2574 ui.pager(b'diff')
2574 ui.pager(b'diff')
2575 logcmdutil.diffordiffstat(
2575 logcmdutil.diffordiffstat(
2576 ui,
2576 ui,
2577 repo,
2577 repo,
2578 diffopts,
2578 diffopts,
2579 ctxleft,
2579 ctxleft,
2580 ctxright,
2580 ctxright,
2581 m,
2581 m,
2582 stat=stat,
2582 stat=stat,
2583 listsubrepos=opts.get(b'subrepos'),
2583 listsubrepos=opts.get(b'subrepos'),
2584 root=opts.get(b'root'),
2584 root=opts.get(b'root'),
2585 )
2585 )
2586
2586
2587
2587
2588 @command(
2588 @command(
2589 b'export',
2589 b'export',
2590 [
2590 [
2591 (
2591 (
2592 b'B',
2592 b'B',
2593 b'bookmark',
2593 b'bookmark',
2594 b'',
2594 b'',
2595 _(b'export changes only reachable by given bookmark'),
2595 _(b'export changes only reachable by given bookmark'),
2596 _(b'BOOKMARK'),
2596 _(b'BOOKMARK'),
2597 ),
2597 ),
2598 (
2598 (
2599 b'o',
2599 b'o',
2600 b'output',
2600 b'output',
2601 b'',
2601 b'',
2602 _(b'print output to file with formatted name'),
2602 _(b'print output to file with formatted name'),
2603 _(b'FORMAT'),
2603 _(b'FORMAT'),
2604 ),
2604 ),
2605 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2605 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2606 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2606 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2607 ]
2607 ]
2608 + diffopts
2608 + diffopts
2609 + formatteropts,
2609 + formatteropts,
2610 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2610 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2611 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2611 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2612 helpbasic=True,
2612 helpbasic=True,
2613 intents={INTENT_READONLY},
2613 intents={INTENT_READONLY},
2614 )
2614 )
2615 def export(ui, repo, *changesets, **opts):
2615 def export(ui, repo, *changesets, **opts):
2616 """dump the header and diffs for one or more changesets
2616 """dump the header and diffs for one or more changesets
2617
2617
2618 Print the changeset header and diffs for one or more revisions.
2618 Print the changeset header and diffs for one or more revisions.
2619 If no revision is given, the parent of the working directory is used.
2619 If no revision is given, the parent of the working directory is used.
2620
2620
2621 The information shown in the changeset header is: author, date,
2621 The information shown in the changeset header is: author, date,
2622 branch name (if non-default), changeset hash, parent(s) and commit
2622 branch name (if non-default), changeset hash, parent(s) and commit
2623 comment.
2623 comment.
2624
2624
2625 .. note::
2625 .. note::
2626
2626
2627 :hg:`export` may generate unexpected diff output for merge
2627 :hg:`export` may generate unexpected diff output for merge
2628 changesets, as it will compare the merge changeset against its
2628 changesets, as it will compare the merge changeset against its
2629 first parent only.
2629 first parent only.
2630
2630
2631 Output may be to a file, in which case the name of the file is
2631 Output may be to a file, in which case the name of the file is
2632 given using a template string. See :hg:`help templates`. In addition
2632 given using a template string. See :hg:`help templates`. In addition
2633 to the common template keywords, the following formatting rules are
2633 to the common template keywords, the following formatting rules are
2634 supported:
2634 supported:
2635
2635
2636 :``%%``: literal "%" character
2636 :``%%``: literal "%" character
2637 :``%H``: changeset hash (40 hexadecimal digits)
2637 :``%H``: changeset hash (40 hexadecimal digits)
2638 :``%N``: number of patches being generated
2638 :``%N``: number of patches being generated
2639 :``%R``: changeset revision number
2639 :``%R``: changeset revision number
2640 :``%b``: basename of the exporting repository
2640 :``%b``: basename of the exporting repository
2641 :``%h``: short-form changeset hash (12 hexadecimal digits)
2641 :``%h``: short-form changeset hash (12 hexadecimal digits)
2642 :``%m``: first line of the commit message (only alphanumeric characters)
2642 :``%m``: first line of the commit message (only alphanumeric characters)
2643 :``%n``: zero-padded sequence number, starting at 1
2643 :``%n``: zero-padded sequence number, starting at 1
2644 :``%r``: zero-padded changeset revision number
2644 :``%r``: zero-padded changeset revision number
2645 :``\\``: literal "\\" character
2645 :``\\``: literal "\\" character
2646
2646
2647 Without the -a/--text option, export will avoid generating diffs
2647 Without the -a/--text option, export will avoid generating diffs
2648 of files it detects as binary. With -a, export will generate a
2648 of files it detects as binary. With -a, export will generate a
2649 diff anyway, probably with undesirable results.
2649 diff anyway, probably with undesirable results.
2650
2650
2651 With -B/--bookmark changesets reachable by the given bookmark are
2651 With -B/--bookmark changesets reachable by the given bookmark are
2652 selected.
2652 selected.
2653
2653
2654 Use the -g/--git option to generate diffs in the git extended diff
2654 Use the -g/--git option to generate diffs in the git extended diff
2655 format. See :hg:`help diffs` for more information.
2655 format. See :hg:`help diffs` for more information.
2656
2656
2657 With the --switch-parent option, the diff will be against the
2657 With the --switch-parent option, the diff will be against the
2658 second parent. It can be useful to review a merge.
2658 second parent. It can be useful to review a merge.
2659
2659
2660 .. container:: verbose
2660 .. container:: verbose
2661
2661
2662 Template:
2662 Template:
2663
2663
2664 The following keywords are supported in addition to the common template
2664 The following keywords are supported in addition to the common template
2665 keywords and functions. See also :hg:`help templates`.
2665 keywords and functions. See also :hg:`help templates`.
2666
2666
2667 :diff: String. Diff content.
2667 :diff: String. Diff content.
2668 :parents: List of strings. Parent nodes of the changeset.
2668 :parents: List of strings. Parent nodes of the changeset.
2669
2669
2670 Examples:
2670 Examples:
2671
2671
2672 - use export and import to transplant a bugfix to the current
2672 - use export and import to transplant a bugfix to the current
2673 branch::
2673 branch::
2674
2674
2675 hg export -r 9353 | hg import -
2675 hg export -r 9353 | hg import -
2676
2676
2677 - export all the changesets between two revisions to a file with
2677 - export all the changesets between two revisions to a file with
2678 rename information::
2678 rename information::
2679
2679
2680 hg export --git -r 123:150 > changes.txt
2680 hg export --git -r 123:150 > changes.txt
2681
2681
2682 - split outgoing changes into a series of patches with
2682 - split outgoing changes into a series of patches with
2683 descriptive names::
2683 descriptive names::
2684
2684
2685 hg export -r "outgoing()" -o "%n-%m.patch"
2685 hg export -r "outgoing()" -o "%n-%m.patch"
2686
2686
2687 Returns 0 on success.
2687 Returns 0 on success.
2688 """
2688 """
2689 opts = pycompat.byteskwargs(opts)
2689 opts = pycompat.byteskwargs(opts)
2690 bookmark = opts.get(b'bookmark')
2690 bookmark = opts.get(b'bookmark')
2691 changesets += tuple(opts.get(b'rev', []))
2691 changesets += tuple(opts.get(b'rev', []))
2692
2692
2693 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2693 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2694
2694
2695 if bookmark:
2695 if bookmark:
2696 if bookmark not in repo._bookmarks:
2696 if bookmark not in repo._bookmarks:
2697 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2697 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2698
2698
2699 revs = scmutil.bookmarkrevs(repo, bookmark)
2699 revs = scmutil.bookmarkrevs(repo, bookmark)
2700 else:
2700 else:
2701 if not changesets:
2701 if not changesets:
2702 changesets = [b'.']
2702 changesets = [b'.']
2703
2703
2704 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2704 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2705 revs = scmutil.revrange(repo, changesets)
2705 revs = scmutil.revrange(repo, changesets)
2706
2706
2707 if not revs:
2707 if not revs:
2708 raise error.InputError(_(b"export requires at least one changeset"))
2708 raise error.InputError(_(b"export requires at least one changeset"))
2709 if len(revs) > 1:
2709 if len(revs) > 1:
2710 ui.note(_(b'exporting patches:\n'))
2710 ui.note(_(b'exporting patches:\n'))
2711 else:
2711 else:
2712 ui.note(_(b'exporting patch:\n'))
2712 ui.note(_(b'exporting patch:\n'))
2713
2713
2714 fntemplate = opts.get(b'output')
2714 fntemplate = opts.get(b'output')
2715 if cmdutil.isstdiofilename(fntemplate):
2715 if cmdutil.isstdiofilename(fntemplate):
2716 fntemplate = b''
2716 fntemplate = b''
2717
2717
2718 if fntemplate:
2718 if fntemplate:
2719 fm = formatter.nullformatter(ui, b'export', opts)
2719 fm = formatter.nullformatter(ui, b'export', opts)
2720 else:
2720 else:
2721 ui.pager(b'export')
2721 ui.pager(b'export')
2722 fm = ui.formatter(b'export', opts)
2722 fm = ui.formatter(b'export', opts)
2723 with fm:
2723 with fm:
2724 cmdutil.export(
2724 cmdutil.export(
2725 repo,
2725 repo,
2726 revs,
2726 revs,
2727 fm,
2727 fm,
2728 fntemplate=fntemplate,
2728 fntemplate=fntemplate,
2729 switch_parent=opts.get(b'switch_parent'),
2729 switch_parent=opts.get(b'switch_parent'),
2730 opts=patch.diffallopts(ui, opts),
2730 opts=patch.diffallopts(ui, opts),
2731 )
2731 )
2732
2732
2733
2733
2734 @command(
2734 @command(
2735 b'files',
2735 b'files',
2736 [
2736 [
2737 (
2737 (
2738 b'r',
2738 b'r',
2739 b'rev',
2739 b'rev',
2740 b'',
2740 b'',
2741 _(b'search the repository as it is in REV'),
2741 _(b'search the repository as it is in REV'),
2742 _(b'REV'),
2742 _(b'REV'),
2743 ),
2743 ),
2744 (
2744 (
2745 b'0',
2745 b'0',
2746 b'print0',
2746 b'print0',
2747 None,
2747 None,
2748 _(b'end filenames with NUL, for use with xargs'),
2748 _(b'end filenames with NUL, for use with xargs'),
2749 ),
2749 ),
2750 ]
2750 ]
2751 + walkopts
2751 + walkopts
2752 + formatteropts
2752 + formatteropts
2753 + subrepoopts,
2753 + subrepoopts,
2754 _(b'[OPTION]... [FILE]...'),
2754 _(b'[OPTION]... [FILE]...'),
2755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2756 intents={INTENT_READONLY},
2756 intents={INTENT_READONLY},
2757 )
2757 )
2758 def files(ui, repo, *pats, **opts):
2758 def files(ui, repo, *pats, **opts):
2759 """list tracked files
2759 """list tracked files
2760
2760
2761 Print files under Mercurial control in the working directory or
2761 Print files under Mercurial control in the working directory or
2762 specified revision for given files (excluding removed files).
2762 specified revision for given files (excluding removed files).
2763 Files can be specified as filenames or filesets.
2763 Files can be specified as filenames or filesets.
2764
2764
2765 If no files are given to match, this command prints the names
2765 If no files are given to match, this command prints the names
2766 of all files under Mercurial control.
2766 of all files under Mercurial control.
2767
2767
2768 .. container:: verbose
2768 .. container:: verbose
2769
2769
2770 Template:
2770 Template:
2771
2771
2772 The following keywords are supported in addition to the common template
2772 The following keywords are supported in addition to the common template
2773 keywords and functions. See also :hg:`help templates`.
2773 keywords and functions. See also :hg:`help templates`.
2774
2774
2775 :flags: String. Character denoting file's symlink and executable bits.
2775 :flags: String. Character denoting file's symlink and executable bits.
2776 :path: String. Repository-absolute path of the file.
2776 :path: String. Repository-absolute path of the file.
2777 :size: Integer. Size of the file in bytes.
2777 :size: Integer. Size of the file in bytes.
2778
2778
2779 Examples:
2779 Examples:
2780
2780
2781 - list all files under the current directory::
2781 - list all files under the current directory::
2782
2782
2783 hg files .
2783 hg files .
2784
2784
2785 - shows sizes and flags for current revision::
2785 - shows sizes and flags for current revision::
2786
2786
2787 hg files -vr .
2787 hg files -vr .
2788
2788
2789 - list all files named README::
2789 - list all files named README::
2790
2790
2791 hg files -I "**/README"
2791 hg files -I "**/README"
2792
2792
2793 - list all binary files::
2793 - list all binary files::
2794
2794
2795 hg files "set:binary()"
2795 hg files "set:binary()"
2796
2796
2797 - find files containing a regular expression::
2797 - find files containing a regular expression::
2798
2798
2799 hg files "set:grep('bob')"
2799 hg files "set:grep('bob')"
2800
2800
2801 - search tracked file contents with xargs and grep::
2801 - search tracked file contents with xargs and grep::
2802
2802
2803 hg files -0 | xargs -0 grep foo
2803 hg files -0 | xargs -0 grep foo
2804
2804
2805 See :hg:`help patterns` and :hg:`help filesets` for more information
2805 See :hg:`help patterns` and :hg:`help filesets` for more information
2806 on specifying file patterns.
2806 on specifying file patterns.
2807
2807
2808 Returns 0 if a match is found, 1 otherwise.
2808 Returns 0 if a match is found, 1 otherwise.
2809
2809
2810 """
2810 """
2811
2811
2812 opts = pycompat.byteskwargs(opts)
2812 opts = pycompat.byteskwargs(opts)
2813 rev = opts.get(b'rev')
2813 rev = opts.get(b'rev')
2814 if rev:
2814 if rev:
2815 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2815 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2816 ctx = scmutil.revsingle(repo, rev, None)
2816 ctx = scmutil.revsingle(repo, rev, None)
2817
2817
2818 end = b'\n'
2818 end = b'\n'
2819 if opts.get(b'print0'):
2819 if opts.get(b'print0'):
2820 end = b'\0'
2820 end = b'\0'
2821 fmt = b'%s' + end
2821 fmt = b'%s' + end
2822
2822
2823 m = scmutil.match(ctx, pats, opts)
2823 m = scmutil.match(ctx, pats, opts)
2824 ui.pager(b'files')
2824 ui.pager(b'files')
2825 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2825 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2826 with ui.formatter(b'files', opts) as fm:
2826 with ui.formatter(b'files', opts) as fm:
2827 return cmdutil.files(
2827 return cmdutil.files(
2828 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2828 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2829 )
2829 )
2830
2830
2831
2831
2832 @command(
2832 @command(
2833 b'forget',
2833 b'forget',
2834 [
2834 [
2835 (b'i', b'interactive', None, _(b'use interactive mode')),
2835 (b'i', b'interactive', None, _(b'use interactive mode')),
2836 ]
2836 ]
2837 + walkopts
2837 + walkopts
2838 + dryrunopts,
2838 + dryrunopts,
2839 _(b'[OPTION]... FILE...'),
2839 _(b'[OPTION]... FILE...'),
2840 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2840 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2841 helpbasic=True,
2841 helpbasic=True,
2842 inferrepo=True,
2842 inferrepo=True,
2843 )
2843 )
2844 def forget(ui, repo, *pats, **opts):
2844 def forget(ui, repo, *pats, **opts):
2845 """forget the specified files on the next commit
2845 """forget the specified files on the next commit
2846
2846
2847 Mark the specified files so they will no longer be tracked
2847 Mark the specified files so they will no longer be tracked
2848 after the next commit.
2848 after the next commit.
2849
2849
2850 This only removes files from the current branch, not from the
2850 This only removes files from the current branch, not from the
2851 entire project history, and it does not delete them from the
2851 entire project history, and it does not delete them from the
2852 working directory.
2852 working directory.
2853
2853
2854 To delete the file from the working directory, see :hg:`remove`.
2854 To delete the file from the working directory, see :hg:`remove`.
2855
2855
2856 To undo a forget before the next commit, see :hg:`add`.
2856 To undo a forget before the next commit, see :hg:`add`.
2857
2857
2858 .. container:: verbose
2858 .. container:: verbose
2859
2859
2860 Examples:
2860 Examples:
2861
2861
2862 - forget newly-added binary files::
2862 - forget newly-added binary files::
2863
2863
2864 hg forget "set:added() and binary()"
2864 hg forget "set:added() and binary()"
2865
2865
2866 - forget files that would be excluded by .hgignore::
2866 - forget files that would be excluded by .hgignore::
2867
2867
2868 hg forget "set:hgignore()"
2868 hg forget "set:hgignore()"
2869
2869
2870 Returns 0 on success.
2870 Returns 0 on success.
2871 """
2871 """
2872
2872
2873 opts = pycompat.byteskwargs(opts)
2873 opts = pycompat.byteskwargs(opts)
2874 if not pats:
2874 if not pats:
2875 raise error.InputError(_(b'no files specified'))
2875 raise error.InputError(_(b'no files specified'))
2876
2876
2877 m = scmutil.match(repo[None], pats, opts)
2877 m = scmutil.match(repo[None], pats, opts)
2878 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2878 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2879 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2879 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2880 rejected = cmdutil.forget(
2880 rejected = cmdutil.forget(
2881 ui,
2881 ui,
2882 repo,
2882 repo,
2883 m,
2883 m,
2884 prefix=b"",
2884 prefix=b"",
2885 uipathfn=uipathfn,
2885 uipathfn=uipathfn,
2886 explicitonly=False,
2886 explicitonly=False,
2887 dryrun=dryrun,
2887 dryrun=dryrun,
2888 interactive=interactive,
2888 interactive=interactive,
2889 )[0]
2889 )[0]
2890 return rejected and 1 or 0
2890 return rejected and 1 or 0
2891
2891
2892
2892
2893 @command(
2893 @command(
2894 b'graft',
2894 b'graft',
2895 [
2895 [
2896 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2896 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2897 (
2897 (
2898 b'',
2898 b'',
2899 b'base',
2899 b'base',
2900 b'',
2900 b'',
2901 _(b'base revision when doing the graft merge (ADVANCED)'),
2901 _(b'base revision when doing the graft merge (ADVANCED)'),
2902 _(b'REV'),
2902 _(b'REV'),
2903 ),
2903 ),
2904 (b'c', b'continue', False, _(b'resume interrupted graft')),
2904 (b'c', b'continue', False, _(b'resume interrupted graft')),
2905 (b'', b'stop', False, _(b'stop interrupted graft')),
2905 (b'', b'stop', False, _(b'stop interrupted graft')),
2906 (b'', b'abort', False, _(b'abort interrupted graft')),
2906 (b'', b'abort', False, _(b'abort interrupted graft')),
2907 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2907 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2908 (b'', b'log', None, _(b'append graft info to log message')),
2908 (b'', b'log', None, _(b'append graft info to log message')),
2909 (
2909 (
2910 b'',
2910 b'',
2911 b'no-commit',
2911 b'no-commit',
2912 None,
2912 None,
2913 _(b"don't commit, just apply the changes in working directory"),
2913 _(b"don't commit, just apply the changes in working directory"),
2914 ),
2914 ),
2915 (b'f', b'force', False, _(b'force graft')),
2915 (b'f', b'force', False, _(b'force graft')),
2916 (
2916 (
2917 b'D',
2917 b'D',
2918 b'currentdate',
2918 b'currentdate',
2919 False,
2919 False,
2920 _(b'record the current date as commit date'),
2920 _(b'record the current date as commit date'),
2921 ),
2921 ),
2922 (
2922 (
2923 b'U',
2923 b'U',
2924 b'currentuser',
2924 b'currentuser',
2925 False,
2925 False,
2926 _(b'record the current user as committer'),
2926 _(b'record the current user as committer'),
2927 ),
2927 ),
2928 ]
2928 ]
2929 + commitopts2
2929 + commitopts2
2930 + mergetoolopts
2930 + mergetoolopts
2931 + dryrunopts,
2931 + dryrunopts,
2932 _(b'[OPTION]... [-r REV]... REV...'),
2932 _(b'[OPTION]... [-r REV]... REV...'),
2933 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2933 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2934 )
2934 )
2935 def graft(ui, repo, *revs, **opts):
2935 def graft(ui, repo, *revs, **opts):
2936 """copy changes from other branches onto the current branch
2936 """copy changes from other branches onto the current branch
2937
2937
2938 This command uses Mercurial's merge logic to copy individual
2938 This command uses Mercurial's merge logic to copy individual
2939 changes from other branches without merging branches in the
2939 changes from other branches without merging branches in the
2940 history graph. This is sometimes known as 'backporting' or
2940 history graph. This is sometimes known as 'backporting' or
2941 'cherry-picking'. By default, graft will copy user, date, and
2941 'cherry-picking'. By default, graft will copy user, date, and
2942 description from the source changesets.
2942 description from the source changesets.
2943
2943
2944 Changesets that are ancestors of the current revision, that have
2944 Changesets that are ancestors of the current revision, that have
2945 already been grafted, or that are merges will be skipped.
2945 already been grafted, or that are merges will be skipped.
2946
2946
2947 If --log is specified, log messages will have a comment appended
2947 If --log is specified, log messages will have a comment appended
2948 of the form::
2948 of the form::
2949
2949
2950 (grafted from CHANGESETHASH)
2950 (grafted from CHANGESETHASH)
2951
2951
2952 If --force is specified, revisions will be grafted even if they
2952 If --force is specified, revisions will be grafted even if they
2953 are already ancestors of, or have been grafted to, the destination.
2953 are already ancestors of, or have been grafted to, the destination.
2954 This is useful when the revisions have since been backed out.
2954 This is useful when the revisions have since been backed out.
2955
2955
2956 If a graft merge results in conflicts, the graft process is
2956 If a graft merge results in conflicts, the graft process is
2957 interrupted so that the current merge can be manually resolved.
2957 interrupted so that the current merge can be manually resolved.
2958 Once all conflicts are addressed, the graft process can be
2958 Once all conflicts are addressed, the graft process can be
2959 continued with the -c/--continue option.
2959 continued with the -c/--continue option.
2960
2960
2961 The -c/--continue option reapplies all the earlier options.
2961 The -c/--continue option reapplies all the earlier options.
2962
2962
2963 .. container:: verbose
2963 .. container:: verbose
2964
2964
2965 The --base option exposes more of how graft internally uses merge with a
2965 The --base option exposes more of how graft internally uses merge with a
2966 custom base revision. --base can be used to specify another ancestor than
2966 custom base revision. --base can be used to specify another ancestor than
2967 the first and only parent.
2967 the first and only parent.
2968
2968
2969 The command::
2969 The command::
2970
2970
2971 hg graft -r 345 --base 234
2971 hg graft -r 345 --base 234
2972
2972
2973 is thus pretty much the same as::
2973 is thus pretty much the same as::
2974
2974
2975 hg diff --from 234 --to 345 | hg import
2975 hg diff --from 234 --to 345 | hg import
2976
2976
2977 but using merge to resolve conflicts and track moved files.
2977 but using merge to resolve conflicts and track moved files.
2978
2978
2979 The result of a merge can thus be backported as a single commit by
2979 The result of a merge can thus be backported as a single commit by
2980 specifying one of the merge parents as base, and thus effectively
2980 specifying one of the merge parents as base, and thus effectively
2981 grafting the changes from the other side.
2981 grafting the changes from the other side.
2982
2982
2983 It is also possible to collapse multiple changesets and clean up history
2983 It is also possible to collapse multiple changesets and clean up history
2984 by specifying another ancestor as base, much like rebase --collapse
2984 by specifying another ancestor as base, much like rebase --collapse
2985 --keep.
2985 --keep.
2986
2986
2987 The commit message can be tweaked after the fact using commit --amend .
2987 The commit message can be tweaked after the fact using commit --amend .
2988
2988
2989 For using non-ancestors as the base to backout changes, see the backout
2989 For using non-ancestors as the base to backout changes, see the backout
2990 command and the hidden --parent option.
2990 command and the hidden --parent option.
2991
2991
2992 .. container:: verbose
2992 .. container:: verbose
2993
2993
2994 Examples:
2994 Examples:
2995
2995
2996 - copy a single change to the stable branch and edit its description::
2996 - copy a single change to the stable branch and edit its description::
2997
2997
2998 hg update stable
2998 hg update stable
2999 hg graft --edit 9393
2999 hg graft --edit 9393
3000
3000
3001 - graft a range of changesets with one exception, updating dates::
3001 - graft a range of changesets with one exception, updating dates::
3002
3002
3003 hg graft -D "2085::2093 and not 2091"
3003 hg graft -D "2085::2093 and not 2091"
3004
3004
3005 - continue a graft after resolving conflicts::
3005 - continue a graft after resolving conflicts::
3006
3006
3007 hg graft -c
3007 hg graft -c
3008
3008
3009 - show the source of a grafted changeset::
3009 - show the source of a grafted changeset::
3010
3010
3011 hg log --debug -r .
3011 hg log --debug -r .
3012
3012
3013 - show revisions sorted by date::
3013 - show revisions sorted by date::
3014
3014
3015 hg log -r "sort(all(), date)"
3015 hg log -r "sort(all(), date)"
3016
3016
3017 - backport the result of a merge as a single commit::
3017 - backport the result of a merge as a single commit::
3018
3018
3019 hg graft -r 123 --base 123^
3019 hg graft -r 123 --base 123^
3020
3020
3021 - land a feature branch as one changeset::
3021 - land a feature branch as one changeset::
3022
3022
3023 hg up -cr default
3023 hg up -cr default
3024 hg graft -r featureX --base "ancestor('featureX', 'default')"
3024 hg graft -r featureX --base "ancestor('featureX', 'default')"
3025
3025
3026 See :hg:`help revisions` for more about specifying revisions.
3026 See :hg:`help revisions` for more about specifying revisions.
3027
3027
3028 Returns 0 on successful completion, 1 if there are unresolved files.
3028 Returns 0 on successful completion, 1 if there are unresolved files.
3029 """
3029 """
3030 with repo.wlock():
3030 with repo.wlock():
3031 return _dograft(ui, repo, *revs, **opts)
3031 return _dograft(ui, repo, *revs, **opts)
3032
3032
3033
3033
3034 def _dograft(ui, repo, *revs, **opts):
3034 def _dograft(ui, repo, *revs, **opts):
3035 opts = pycompat.byteskwargs(opts)
3035 opts = pycompat.byteskwargs(opts)
3036 if revs and opts.get(b'rev'):
3036 if revs and opts.get(b'rev'):
3037 ui.warn(
3037 ui.warn(
3038 _(
3038 _(
3039 b'warning: inconsistent use of --rev might give unexpected '
3039 b'warning: inconsistent use of --rev might give unexpected '
3040 b'revision ordering!\n'
3040 b'revision ordering!\n'
3041 )
3041 )
3042 )
3042 )
3043
3043
3044 revs = list(revs)
3044 revs = list(revs)
3045 revs.extend(opts.get(b'rev'))
3045 revs.extend(opts.get(b'rev'))
3046 # a dict of data to be stored in state file
3046 # a dict of data to be stored in state file
3047 statedata = {}
3047 statedata = {}
3048 # list of new nodes created by ongoing graft
3048 # list of new nodes created by ongoing graft
3049 statedata[b'newnodes'] = []
3049 statedata[b'newnodes'] = []
3050
3050
3051 cmdutil.resolvecommitoptions(ui, opts)
3051 cmdutil.resolvecommitoptions(ui, opts)
3052
3052
3053 editor = cmdutil.getcommiteditor(
3053 editor = cmdutil.getcommiteditor(
3054 editform=b'graft', **pycompat.strkwargs(opts)
3054 editform=b'graft', **pycompat.strkwargs(opts)
3055 )
3055 )
3056
3056
3057 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3057 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3058
3058
3059 cont = False
3059 cont = False
3060 if opts.get(b'no_commit'):
3060 if opts.get(b'no_commit'):
3061 cmdutil.check_incompatible_arguments(
3061 cmdutil.check_incompatible_arguments(
3062 opts,
3062 opts,
3063 b'no_commit',
3063 b'no_commit',
3064 [b'edit', b'currentuser', b'currentdate', b'log'],
3064 [b'edit', b'currentuser', b'currentdate', b'log'],
3065 )
3065 )
3066
3066
3067 graftstate = statemod.cmdstate(repo, b'graftstate')
3067 graftstate = statemod.cmdstate(repo, b'graftstate')
3068
3068
3069 if opts.get(b'stop'):
3069 if opts.get(b'stop'):
3070 cmdutil.check_incompatible_arguments(
3070 cmdutil.check_incompatible_arguments(
3071 opts,
3071 opts,
3072 b'stop',
3072 b'stop',
3073 [
3073 [
3074 b'edit',
3074 b'edit',
3075 b'log',
3075 b'log',
3076 b'user',
3076 b'user',
3077 b'date',
3077 b'date',
3078 b'currentdate',
3078 b'currentdate',
3079 b'currentuser',
3079 b'currentuser',
3080 b'rev',
3080 b'rev',
3081 ],
3081 ],
3082 )
3082 )
3083 return _stopgraft(ui, repo, graftstate)
3083 return _stopgraft(ui, repo, graftstate)
3084 elif opts.get(b'abort'):
3084 elif opts.get(b'abort'):
3085 cmdutil.check_incompatible_arguments(
3085 cmdutil.check_incompatible_arguments(
3086 opts,
3086 opts,
3087 b'abort',
3087 b'abort',
3088 [
3088 [
3089 b'edit',
3089 b'edit',
3090 b'log',
3090 b'log',
3091 b'user',
3091 b'user',
3092 b'date',
3092 b'date',
3093 b'currentdate',
3093 b'currentdate',
3094 b'currentuser',
3094 b'currentuser',
3095 b'rev',
3095 b'rev',
3096 ],
3096 ],
3097 )
3097 )
3098 return cmdutil.abortgraft(ui, repo, graftstate)
3098 return cmdutil.abortgraft(ui, repo, graftstate)
3099 elif opts.get(b'continue'):
3099 elif opts.get(b'continue'):
3100 cont = True
3100 cont = True
3101 if revs:
3101 if revs:
3102 raise error.InputError(_(b"can't specify --continue and revisions"))
3102 raise error.InputError(_(b"can't specify --continue and revisions"))
3103 # read in unfinished revisions
3103 # read in unfinished revisions
3104 if graftstate.exists():
3104 if graftstate.exists():
3105 statedata = cmdutil.readgraftstate(repo, graftstate)
3105 statedata = cmdutil.readgraftstate(repo, graftstate)
3106 if statedata.get(b'date'):
3106 if statedata.get(b'date'):
3107 opts[b'date'] = statedata[b'date']
3107 opts[b'date'] = statedata[b'date']
3108 if statedata.get(b'user'):
3108 if statedata.get(b'user'):
3109 opts[b'user'] = statedata[b'user']
3109 opts[b'user'] = statedata[b'user']
3110 if statedata.get(b'log'):
3110 if statedata.get(b'log'):
3111 opts[b'log'] = True
3111 opts[b'log'] = True
3112 if statedata.get(b'no_commit'):
3112 if statedata.get(b'no_commit'):
3113 opts[b'no_commit'] = statedata.get(b'no_commit')
3113 opts[b'no_commit'] = statedata.get(b'no_commit')
3114 if statedata.get(b'base'):
3114 if statedata.get(b'base'):
3115 opts[b'base'] = statedata.get(b'base')
3115 opts[b'base'] = statedata.get(b'base')
3116 nodes = statedata[b'nodes']
3116 nodes = statedata[b'nodes']
3117 revs = [repo[node].rev() for node in nodes]
3117 revs = [repo[node].rev() for node in nodes]
3118 else:
3118 else:
3119 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3119 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3120 else:
3120 else:
3121 if not revs:
3121 if not revs:
3122 raise error.InputError(_(b'no revisions specified'))
3122 raise error.InputError(_(b'no revisions specified'))
3123 cmdutil.checkunfinished(repo)
3123 cmdutil.checkunfinished(repo)
3124 cmdutil.bailifchanged(repo)
3124 cmdutil.bailifchanged(repo)
3125 revs = scmutil.revrange(repo, revs)
3125 revs = scmutil.revrange(repo, revs)
3126
3126
3127 skipped = set()
3127 skipped = set()
3128 basectx = None
3128 basectx = None
3129 if opts.get(b'base'):
3129 if opts.get(b'base'):
3130 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3130 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3131 if basectx is None:
3131 if basectx is None:
3132 # check for merges
3132 # check for merges
3133 for rev in repo.revs(b'%ld and merge()', revs):
3133 for rev in repo.revs(b'%ld and merge()', revs):
3134 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3134 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3135 skipped.add(rev)
3135 skipped.add(rev)
3136 revs = [r for r in revs if r not in skipped]
3136 revs = [r for r in revs if r not in skipped]
3137 if not revs:
3137 if not revs:
3138 return -1
3138 return -1
3139 if basectx is not None and len(revs) != 1:
3139 if basectx is not None and len(revs) != 1:
3140 raise error.InputError(_(b'only one revision allowed with --base '))
3140 raise error.InputError(_(b'only one revision allowed with --base '))
3141
3141
3142 # Don't check in the --continue case, in effect retaining --force across
3142 # Don't check in the --continue case, in effect retaining --force across
3143 # --continues. That's because without --force, any revisions we decided to
3143 # --continues. That's because without --force, any revisions we decided to
3144 # skip would have been filtered out here, so they wouldn't have made their
3144 # skip would have been filtered out here, so they wouldn't have made their
3145 # way to the graftstate. With --force, any revisions we would have otherwise
3145 # way to the graftstate. With --force, any revisions we would have otherwise
3146 # skipped would not have been filtered out, and if they hadn't been applied
3146 # skipped would not have been filtered out, and if they hadn't been applied
3147 # already, they'd have been in the graftstate.
3147 # already, they'd have been in the graftstate.
3148 if not (cont or opts.get(b'force')) and basectx is None:
3148 if not (cont or opts.get(b'force')) and basectx is None:
3149 # check for ancestors of dest branch
3149 # check for ancestors of dest branch
3150 ancestors = repo.revs(b'%ld & (::.)', revs)
3150 ancestors = repo.revs(b'%ld & (::.)', revs)
3151 for rev in ancestors:
3151 for rev in ancestors:
3152 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3152 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3153
3153
3154 revs = [r for r in revs if r not in ancestors]
3154 revs = [r for r in revs if r not in ancestors]
3155
3155
3156 if not revs:
3156 if not revs:
3157 return -1
3157 return -1
3158
3158
3159 # analyze revs for earlier grafts
3159 # analyze revs for earlier grafts
3160 ids = {}
3160 ids = {}
3161 for ctx in repo.set(b"%ld", revs):
3161 for ctx in repo.set(b"%ld", revs):
3162 ids[ctx.hex()] = ctx.rev()
3162 ids[ctx.hex()] = ctx.rev()
3163 n = ctx.extra().get(b'source')
3163 n = ctx.extra().get(b'source')
3164 if n:
3164 if n:
3165 ids[n] = ctx.rev()
3165 ids[n] = ctx.rev()
3166
3166
3167 # check ancestors for earlier grafts
3167 # check ancestors for earlier grafts
3168 ui.debug(b'scanning for duplicate grafts\n')
3168 ui.debug(b'scanning for duplicate grafts\n')
3169
3169
3170 # The only changesets we can be sure doesn't contain grafts of any
3170 # The only changesets we can be sure doesn't contain grafts of any
3171 # revs, are the ones that are common ancestors of *all* revs:
3171 # revs, are the ones that are common ancestors of *all* revs:
3172 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3172 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3173 ctx = repo[rev]
3173 ctx = repo[rev]
3174 n = ctx.extra().get(b'source')
3174 n = ctx.extra().get(b'source')
3175 if n in ids:
3175 if n in ids:
3176 try:
3176 try:
3177 r = repo[n].rev()
3177 r = repo[n].rev()
3178 except error.RepoLookupError:
3178 except error.RepoLookupError:
3179 r = None
3179 r = None
3180 if r in revs:
3180 if r in revs:
3181 ui.warn(
3181 ui.warn(
3182 _(
3182 _(
3183 b'skipping revision %d:%s '
3183 b'skipping revision %d:%s '
3184 b'(already grafted to %d:%s)\n'
3184 b'(already grafted to %d:%s)\n'
3185 )
3185 )
3186 % (r, repo[r], rev, ctx)
3186 % (r, repo[r], rev, ctx)
3187 )
3187 )
3188 revs.remove(r)
3188 revs.remove(r)
3189 elif ids[n] in revs:
3189 elif ids[n] in revs:
3190 if r is None:
3190 if r is None:
3191 ui.warn(
3191 ui.warn(
3192 _(
3192 _(
3193 b'skipping already grafted revision %d:%s '
3193 b'skipping already grafted revision %d:%s '
3194 b'(%d:%s also has unknown origin %s)\n'
3194 b'(%d:%s also has unknown origin %s)\n'
3195 )
3195 )
3196 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3196 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3197 )
3197 )
3198 else:
3198 else:
3199 ui.warn(
3199 ui.warn(
3200 _(
3200 _(
3201 b'skipping already grafted revision %d:%s '
3201 b'skipping already grafted revision %d:%s '
3202 b'(%d:%s also has origin %d:%s)\n'
3202 b'(%d:%s also has origin %d:%s)\n'
3203 )
3203 )
3204 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3204 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3205 )
3205 )
3206 revs.remove(ids[n])
3206 revs.remove(ids[n])
3207 elif ctx.hex() in ids:
3207 elif ctx.hex() in ids:
3208 r = ids[ctx.hex()]
3208 r = ids[ctx.hex()]
3209 if r in revs:
3209 if r in revs:
3210 ui.warn(
3210 ui.warn(
3211 _(
3211 _(
3212 b'skipping already grafted revision %d:%s '
3212 b'skipping already grafted revision %d:%s '
3213 b'(was grafted from %d:%s)\n'
3213 b'(was grafted from %d:%s)\n'
3214 )
3214 )
3215 % (r, repo[r], rev, ctx)
3215 % (r, repo[r], rev, ctx)
3216 )
3216 )
3217 revs.remove(r)
3217 revs.remove(r)
3218 if not revs:
3218 if not revs:
3219 return -1
3219 return -1
3220
3220
3221 if opts.get(b'no_commit'):
3221 if opts.get(b'no_commit'):
3222 statedata[b'no_commit'] = True
3222 statedata[b'no_commit'] = True
3223 if opts.get(b'base'):
3223 if opts.get(b'base'):
3224 statedata[b'base'] = opts[b'base']
3224 statedata[b'base'] = opts[b'base']
3225 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3225 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3226 desc = b'%d:%s "%s"' % (
3226 desc = b'%d:%s "%s"' % (
3227 ctx.rev(),
3227 ctx.rev(),
3228 ctx,
3228 ctx,
3229 ctx.description().split(b'\n', 1)[0],
3229 ctx.description().split(b'\n', 1)[0],
3230 )
3230 )
3231 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3231 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3232 if names:
3232 if names:
3233 desc += b' (%s)' % b' '.join(names)
3233 desc += b' (%s)' % b' '.join(names)
3234 ui.status(_(b'grafting %s\n') % desc)
3234 ui.status(_(b'grafting %s\n') % desc)
3235 if opts.get(b'dry_run'):
3235 if opts.get(b'dry_run'):
3236 continue
3236 continue
3237
3237
3238 source = ctx.extra().get(b'source')
3238 source = ctx.extra().get(b'source')
3239 extra = {}
3239 extra = {}
3240 if source:
3240 if source:
3241 extra[b'source'] = source
3241 extra[b'source'] = source
3242 extra[b'intermediate-source'] = ctx.hex()
3242 extra[b'intermediate-source'] = ctx.hex()
3243 else:
3243 else:
3244 extra[b'source'] = ctx.hex()
3244 extra[b'source'] = ctx.hex()
3245 user = ctx.user()
3245 user = ctx.user()
3246 if opts.get(b'user'):
3246 if opts.get(b'user'):
3247 user = opts[b'user']
3247 user = opts[b'user']
3248 statedata[b'user'] = user
3248 statedata[b'user'] = user
3249 date = ctx.date()
3249 date = ctx.date()
3250 if opts.get(b'date'):
3250 if opts.get(b'date'):
3251 date = opts[b'date']
3251 date = opts[b'date']
3252 statedata[b'date'] = date
3252 statedata[b'date'] = date
3253 message = ctx.description()
3253 message = ctx.description()
3254 if opts.get(b'log'):
3254 if opts.get(b'log'):
3255 message += b'\n(grafted from %s)' % ctx.hex()
3255 message += b'\n(grafted from %s)' % ctx.hex()
3256 statedata[b'log'] = True
3256 statedata[b'log'] = True
3257
3257
3258 # we don't merge the first commit when continuing
3258 # we don't merge the first commit when continuing
3259 if not cont:
3259 if not cont:
3260 # perform the graft merge with p1(rev) as 'ancestor'
3260 # perform the graft merge with p1(rev) as 'ancestor'
3261 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3261 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3262 base = ctx.p1() if basectx is None else basectx
3262 base = ctx.p1() if basectx is None else basectx
3263 with ui.configoverride(overrides, b'graft'):
3263 with ui.configoverride(overrides, b'graft'):
3264 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3264 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3265 # report any conflicts
3265 # report any conflicts
3266 if stats.unresolvedcount > 0:
3266 if stats.unresolvedcount > 0:
3267 # write out state for --continue
3267 # write out state for --continue
3268 nodes = [repo[rev].hex() for rev in revs[pos:]]
3268 nodes = [repo[rev].hex() for rev in revs[pos:]]
3269 statedata[b'nodes'] = nodes
3269 statedata[b'nodes'] = nodes
3270 stateversion = 1
3270 stateversion = 1
3271 graftstate.save(stateversion, statedata)
3271 graftstate.save(stateversion, statedata)
3272 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3272 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3273 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3273 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3274 return 1
3274 return 1
3275 else:
3275 else:
3276 cont = False
3276 cont = False
3277
3277
3278 # commit if --no-commit is false
3278 # commit if --no-commit is false
3279 if not opts.get(b'no_commit'):
3279 if not opts.get(b'no_commit'):
3280 node = repo.commit(
3280 node = repo.commit(
3281 text=message, user=user, date=date, extra=extra, editor=editor
3281 text=message, user=user, date=date, extra=extra, editor=editor
3282 )
3282 )
3283 if node is None:
3283 if node is None:
3284 ui.warn(
3284 ui.warn(
3285 _(b'note: graft of %d:%s created no changes to commit\n')
3285 _(b'note: graft of %d:%s created no changes to commit\n')
3286 % (ctx.rev(), ctx)
3286 % (ctx.rev(), ctx)
3287 )
3287 )
3288 # checking that newnodes exist because old state files won't have it
3288 # checking that newnodes exist because old state files won't have it
3289 elif statedata.get(b'newnodes') is not None:
3289 elif statedata.get(b'newnodes') is not None:
3290 statedata[b'newnodes'].append(node)
3290 statedata[b'newnodes'].append(node)
3291
3291
3292 # remove state when we complete successfully
3292 # remove state when we complete successfully
3293 if not opts.get(b'dry_run'):
3293 if not opts.get(b'dry_run'):
3294 graftstate.delete()
3294 graftstate.delete()
3295
3295
3296 return 0
3296 return 0
3297
3297
3298
3298
3299 def _stopgraft(ui, repo, graftstate):
3299 def _stopgraft(ui, repo, graftstate):
3300 """stop the interrupted graft"""
3300 """stop the interrupted graft"""
3301 if not graftstate.exists():
3301 if not graftstate.exists():
3302 raise error.StateError(_(b"no interrupted graft found"))
3302 raise error.StateError(_(b"no interrupted graft found"))
3303 pctx = repo[b'.']
3303 pctx = repo[b'.']
3304 mergemod.clean_update(pctx)
3304 mergemod.clean_update(pctx)
3305 graftstate.delete()
3305 graftstate.delete()
3306 ui.status(_(b"stopped the interrupted graft\n"))
3306 ui.status(_(b"stopped the interrupted graft\n"))
3307 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3307 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3308 return 0
3308 return 0
3309
3309
3310
3310
3311 statemod.addunfinished(
3311 statemod.addunfinished(
3312 b'graft',
3312 b'graft',
3313 fname=b'graftstate',
3313 fname=b'graftstate',
3314 clearable=True,
3314 clearable=True,
3315 stopflag=True,
3315 stopflag=True,
3316 continueflag=True,
3316 continueflag=True,
3317 abortfunc=cmdutil.hgabortgraft,
3317 abortfunc=cmdutil.hgabortgraft,
3318 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3318 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3319 )
3319 )
3320
3320
3321
3321
3322 @command(
3322 @command(
3323 b'grep',
3323 b'grep',
3324 [
3324 [
3325 (b'0', b'print0', None, _(b'end fields with NUL')),
3325 (b'0', b'print0', None, _(b'end fields with NUL')),
3326 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3326 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3327 (
3327 (
3328 b'',
3328 b'',
3329 b'diff',
3329 b'diff',
3330 None,
3330 None,
3331 _(
3331 _(
3332 b'search revision differences for when the pattern was added '
3332 b'search revision differences for when the pattern was added '
3333 b'or removed'
3333 b'or removed'
3334 ),
3334 ),
3335 ),
3335 ),
3336 (b'a', b'text', None, _(b'treat all files as text')),
3336 (b'a', b'text', None, _(b'treat all files as text')),
3337 (
3337 (
3338 b'f',
3338 b'f',
3339 b'follow',
3339 b'follow',
3340 None,
3340 None,
3341 _(
3341 _(
3342 b'follow changeset history,'
3342 b'follow changeset history,'
3343 b' or file history across copies and renames'
3343 b' or file history across copies and renames'
3344 ),
3344 ),
3345 ),
3345 ),
3346 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3346 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3347 (
3347 (
3348 b'l',
3348 b'l',
3349 b'files-with-matches',
3349 b'files-with-matches',
3350 None,
3350 None,
3351 _(b'print only filenames and revisions that match'),
3351 _(b'print only filenames and revisions that match'),
3352 ),
3352 ),
3353 (b'n', b'line-number', None, _(b'print matching line numbers')),
3353 (b'n', b'line-number', None, _(b'print matching line numbers')),
3354 (
3354 (
3355 b'r',
3355 b'r',
3356 b'rev',
3356 b'rev',
3357 [],
3357 [],
3358 _(b'search files changed within revision range'),
3358 _(b'search files changed within revision range'),
3359 _(b'REV'),
3359 _(b'REV'),
3360 ),
3360 ),
3361 (
3361 (
3362 b'',
3362 b'',
3363 b'all-files',
3363 b'all-files',
3364 None,
3364 None,
3365 _(
3365 _(
3366 b'include all files in the changeset while grepping (DEPRECATED)'
3366 b'include all files in the changeset while grepping (DEPRECATED)'
3367 ),
3367 ),
3368 ),
3368 ),
3369 (b'u', b'user', None, _(b'list the author (long with -v)')),
3369 (b'u', b'user', None, _(b'list the author (long with -v)')),
3370 (b'd', b'date', None, _(b'list the date (short with -q)')),
3370 (b'd', b'date', None, _(b'list the date (short with -q)')),
3371 ]
3371 ]
3372 + formatteropts
3372 + formatteropts
3373 + walkopts,
3373 + walkopts,
3374 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3374 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3375 helpcategory=command.CATEGORY_FILE_CONTENTS,
3375 helpcategory=command.CATEGORY_FILE_CONTENTS,
3376 inferrepo=True,
3376 inferrepo=True,
3377 intents={INTENT_READONLY},
3377 intents={INTENT_READONLY},
3378 )
3378 )
3379 def grep(ui, repo, pattern, *pats, **opts):
3379 def grep(ui, repo, pattern, *pats, **opts):
3380 """search for a pattern in specified files
3380 """search for a pattern in specified files
3381
3381
3382 Search the working directory or revision history for a regular
3382 Search the working directory or revision history for a regular
3383 expression in the specified files for the entire repository.
3383 expression in the specified files for the entire repository.
3384
3384
3385 By default, grep searches the repository files in the working
3385 By default, grep searches the repository files in the working
3386 directory and prints the files where it finds a match. To specify
3386 directory and prints the files where it finds a match. To specify
3387 historical revisions instead of the working directory, use the
3387 historical revisions instead of the working directory, use the
3388 --rev flag.
3388 --rev flag.
3389
3389
3390 To search instead historical revision differences that contains a
3390 To search instead historical revision differences that contains a
3391 change in match status ("-" for a match that becomes a non-match,
3391 change in match status ("-" for a match that becomes a non-match,
3392 or "+" for a non-match that becomes a match), use the --diff flag.
3392 or "+" for a non-match that becomes a match), use the --diff flag.
3393
3393
3394 PATTERN can be any Python (roughly Perl-compatible) regular
3394 PATTERN can be any Python (roughly Perl-compatible) regular
3395 expression.
3395 expression.
3396
3396
3397 If no FILEs are specified and the --rev flag isn't supplied, all
3397 If no FILEs are specified and the --rev flag isn't supplied, all
3398 files in the working directory are searched. When using the --rev
3398 files in the working directory are searched. When using the --rev
3399 flag and specifying FILEs, use the --follow argument to also
3399 flag and specifying FILEs, use the --follow argument to also
3400 follow the specified FILEs across renames and copies.
3400 follow the specified FILEs across renames and copies.
3401
3401
3402 .. container:: verbose
3402 .. container:: verbose
3403
3403
3404 Template:
3404 Template:
3405
3405
3406 The following keywords are supported in addition to the common template
3406 The following keywords are supported in addition to the common template
3407 keywords and functions. See also :hg:`help templates`.
3407 keywords and functions. See also :hg:`help templates`.
3408
3408
3409 :change: String. Character denoting insertion ``+`` or removal ``-``.
3409 :change: String. Character denoting insertion ``+`` or removal ``-``.
3410 Available if ``--diff`` is specified.
3410 Available if ``--diff`` is specified.
3411 :lineno: Integer. Line number of the match.
3411 :lineno: Integer. Line number of the match.
3412 :path: String. Repository-absolute path of the file.
3412 :path: String. Repository-absolute path of the file.
3413 :texts: List of text chunks.
3413 :texts: List of text chunks.
3414
3414
3415 And each entry of ``{texts}`` provides the following sub-keywords.
3415 And each entry of ``{texts}`` provides the following sub-keywords.
3416
3416
3417 :matched: Boolean. True if the chunk matches the specified pattern.
3417 :matched: Boolean. True if the chunk matches the specified pattern.
3418 :text: String. Chunk content.
3418 :text: String. Chunk content.
3419
3419
3420 See :hg:`help templates.operators` for the list expansion syntax.
3420 See :hg:`help templates.operators` for the list expansion syntax.
3421
3421
3422 Returns 0 if a match is found, 1 otherwise.
3422 Returns 0 if a match is found, 1 otherwise.
3423
3423
3424 """
3424 """
3425 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3425 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3426 opts = pycompat.byteskwargs(opts)
3426 opts = pycompat.byteskwargs(opts)
3427 diff = opts.get(b'all') or opts.get(b'diff')
3427 diff = opts.get(b'all') or opts.get(b'diff')
3428 follow = opts.get(b'follow')
3428 follow = opts.get(b'follow')
3429 if opts.get(b'all_files') is None and not diff:
3429 if opts.get(b'all_files') is None and not diff:
3430 opts[b'all_files'] = True
3430 opts[b'all_files'] = True
3431 plaingrep = (
3431 plaingrep = (
3432 opts.get(b'all_files')
3432 opts.get(b'all_files')
3433 and not opts.get(b'rev')
3433 and not opts.get(b'rev')
3434 and not opts.get(b'follow')
3434 and not opts.get(b'follow')
3435 )
3435 )
3436 all_files = opts.get(b'all_files')
3436 all_files = opts.get(b'all_files')
3437 if plaingrep:
3437 if plaingrep:
3438 opts[b'rev'] = [b'wdir()']
3438 opts[b'rev'] = [b'wdir()']
3439
3439
3440 reflags = re.M
3440 reflags = re.M
3441 if opts.get(b'ignore_case'):
3441 if opts.get(b'ignore_case'):
3442 reflags |= re.I
3442 reflags |= re.I
3443 try:
3443 try:
3444 regexp = util.re.compile(pattern, reflags)
3444 regexp = util.re.compile(pattern, reflags)
3445 except re.error as inst:
3445 except re.error as inst:
3446 ui.warn(
3446 ui.warn(
3447 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3447 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3448 )
3448 )
3449 return 1
3449 return 1
3450 sep, eol = b':', b'\n'
3450 sep, eol = b':', b'\n'
3451 if opts.get(b'print0'):
3451 if opts.get(b'print0'):
3452 sep = eol = b'\0'
3452 sep = eol = b'\0'
3453
3453
3454 searcher = grepmod.grepsearcher(
3454 searcher = grepmod.grepsearcher(
3455 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3455 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3456 )
3456 )
3457
3457
3458 getfile = searcher._getfile
3458 getfile = searcher._getfile
3459
3459
3460 uipathfn = scmutil.getuipathfn(repo)
3460 uipathfn = scmutil.getuipathfn(repo)
3461
3461
3462 def display(fm, fn, ctx, pstates, states):
3462 def display(fm, fn, ctx, pstates, states):
3463 rev = scmutil.intrev(ctx)
3463 rev = scmutil.intrev(ctx)
3464 if fm.isplain():
3464 if fm.isplain():
3465 formatuser = ui.shortuser
3465 formatuser = ui.shortuser
3466 else:
3466 else:
3467 formatuser = pycompat.bytestr
3467 formatuser = pycompat.bytestr
3468 if ui.quiet:
3468 if ui.quiet:
3469 datefmt = b'%Y-%m-%d'
3469 datefmt = b'%Y-%m-%d'
3470 else:
3470 else:
3471 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3471 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3472 found = False
3472 found = False
3473
3473
3474 @util.cachefunc
3474 @util.cachefunc
3475 def binary():
3475 def binary():
3476 flog = getfile(fn)
3476 flog = getfile(fn)
3477 try:
3477 try:
3478 return stringutil.binary(flog.read(ctx.filenode(fn)))
3478 return stringutil.binary(flog.read(ctx.filenode(fn)))
3479 except error.WdirUnsupported:
3479 except error.WdirUnsupported:
3480 return ctx[fn].isbinary()
3480 return ctx[fn].isbinary()
3481
3481
3482 fieldnamemap = {b'linenumber': b'lineno'}
3482 fieldnamemap = {b'linenumber': b'lineno'}
3483 if diff:
3483 if diff:
3484 iter = grepmod.difflinestates(pstates, states)
3484 iter = grepmod.difflinestates(pstates, states)
3485 else:
3485 else:
3486 iter = [(b'', l) for l in states]
3486 iter = [(b'', l) for l in states]
3487 for change, l in iter:
3487 for change, l in iter:
3488 fm.startitem()
3488 fm.startitem()
3489 fm.context(ctx=ctx)
3489 fm.context(ctx=ctx)
3490 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3490 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3491 fm.plain(uipathfn(fn), label=b'grep.filename')
3491 fm.plain(uipathfn(fn), label=b'grep.filename')
3492
3492
3493 cols = [
3493 cols = [
3494 (b'rev', b'%d', rev, not plaingrep, b''),
3494 (b'rev', b'%d', rev, not plaingrep, b''),
3495 (
3495 (
3496 b'linenumber',
3496 b'linenumber',
3497 b'%d',
3497 b'%d',
3498 l.linenum,
3498 l.linenum,
3499 opts.get(b'line_number'),
3499 opts.get(b'line_number'),
3500 b'',
3500 b'',
3501 ),
3501 ),
3502 ]
3502 ]
3503 if diff:
3503 if diff:
3504 cols.append(
3504 cols.append(
3505 (
3505 (
3506 b'change',
3506 b'change',
3507 b'%s',
3507 b'%s',
3508 change,
3508 change,
3509 True,
3509 True,
3510 b'grep.inserted '
3510 b'grep.inserted '
3511 if change == b'+'
3511 if change == b'+'
3512 else b'grep.deleted ',
3512 else b'grep.deleted ',
3513 )
3513 )
3514 )
3514 )
3515 cols.extend(
3515 cols.extend(
3516 [
3516 [
3517 (
3517 (
3518 b'user',
3518 b'user',
3519 b'%s',
3519 b'%s',
3520 formatuser(ctx.user()),
3520 formatuser(ctx.user()),
3521 opts.get(b'user'),
3521 opts.get(b'user'),
3522 b'',
3522 b'',
3523 ),
3523 ),
3524 (
3524 (
3525 b'date',
3525 b'date',
3526 b'%s',
3526 b'%s',
3527 fm.formatdate(ctx.date(), datefmt),
3527 fm.formatdate(ctx.date(), datefmt),
3528 opts.get(b'date'),
3528 opts.get(b'date'),
3529 b'',
3529 b'',
3530 ),
3530 ),
3531 ]
3531 ]
3532 )
3532 )
3533 for name, fmt, data, cond, extra_label in cols:
3533 for name, fmt, data, cond, extra_label in cols:
3534 if cond:
3534 if cond:
3535 fm.plain(sep, label=b'grep.sep')
3535 fm.plain(sep, label=b'grep.sep')
3536 field = fieldnamemap.get(name, name)
3536 field = fieldnamemap.get(name, name)
3537 label = extra_label + (b'grep.%s' % name)
3537 label = extra_label + (b'grep.%s' % name)
3538 fm.condwrite(cond, field, fmt, data, label=label)
3538 fm.condwrite(cond, field, fmt, data, label=label)
3539 if not opts.get(b'files_with_matches'):
3539 if not opts.get(b'files_with_matches'):
3540 fm.plain(sep, label=b'grep.sep')
3540 fm.plain(sep, label=b'grep.sep')
3541 if not opts.get(b'text') and binary():
3541 if not opts.get(b'text') and binary():
3542 fm.plain(_(b" Binary file matches"))
3542 fm.plain(_(b" Binary file matches"))
3543 else:
3543 else:
3544 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3544 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3545 fm.plain(eol)
3545 fm.plain(eol)
3546 found = True
3546 found = True
3547 if opts.get(b'files_with_matches'):
3547 if opts.get(b'files_with_matches'):
3548 break
3548 break
3549 return found
3549 return found
3550
3550
3551 def displaymatches(fm, l):
3551 def displaymatches(fm, l):
3552 p = 0
3552 p = 0
3553 for s, e in l.findpos(regexp):
3553 for s, e in l.findpos(regexp):
3554 if p < s:
3554 if p < s:
3555 fm.startitem()
3555 fm.startitem()
3556 fm.write(b'text', b'%s', l.line[p:s])
3556 fm.write(b'text', b'%s', l.line[p:s])
3557 fm.data(matched=False)
3557 fm.data(matched=False)
3558 fm.startitem()
3558 fm.startitem()
3559 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3559 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3560 fm.data(matched=True)
3560 fm.data(matched=True)
3561 p = e
3561 p = e
3562 if p < len(l.line):
3562 if p < len(l.line):
3563 fm.startitem()
3563 fm.startitem()
3564 fm.write(b'text', b'%s', l.line[p:])
3564 fm.write(b'text', b'%s', l.line[p:])
3565 fm.data(matched=False)
3565 fm.data(matched=False)
3566 fm.end()
3566 fm.end()
3567
3567
3568 found = False
3568 found = False
3569
3569
3570 wopts = logcmdutil.walkopts(
3570 wopts = logcmdutil.walkopts(
3571 pats=pats,
3571 pats=pats,
3572 opts=opts,
3572 opts=opts,
3573 revspec=opts[b'rev'],
3573 revspec=opts[b'rev'],
3574 include_pats=opts[b'include'],
3574 include_pats=opts[b'include'],
3575 exclude_pats=opts[b'exclude'],
3575 exclude_pats=opts[b'exclude'],
3576 follow=follow,
3576 follow=follow,
3577 force_changelog_traversal=all_files,
3577 force_changelog_traversal=all_files,
3578 filter_revisions_by_pats=not all_files,
3578 filter_revisions_by_pats=not all_files,
3579 )
3579 )
3580 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3580 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3581
3581
3582 ui.pager(b'grep')
3582 ui.pager(b'grep')
3583 fm = ui.formatter(b'grep', opts)
3583 fm = ui.formatter(b'grep', opts)
3584 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3584 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3585 r = display(fm, fn, ctx, pstates, states)
3585 r = display(fm, fn, ctx, pstates, states)
3586 found = found or r
3586 found = found or r
3587 if r and not diff and not all_files:
3587 if r and not diff and not all_files:
3588 searcher.skipfile(fn, ctx.rev())
3588 searcher.skipfile(fn, ctx.rev())
3589 fm.end()
3589 fm.end()
3590
3590
3591 return not found
3591 return not found
3592
3592
3593
3593
3594 @command(
3594 @command(
3595 b'heads',
3595 b'heads',
3596 [
3596 [
3597 (
3597 (
3598 b'r',
3598 b'r',
3599 b'rev',
3599 b'rev',
3600 b'',
3600 b'',
3601 _(b'show only heads which are descendants of STARTREV'),
3601 _(b'show only heads which are descendants of STARTREV'),
3602 _(b'STARTREV'),
3602 _(b'STARTREV'),
3603 ),
3603 ),
3604 (b't', b'topo', False, _(b'show topological heads only')),
3604 (b't', b'topo', False, _(b'show topological heads only')),
3605 (
3605 (
3606 b'a',
3606 b'a',
3607 b'active',
3607 b'active',
3608 False,
3608 False,
3609 _(b'show active branchheads only (DEPRECATED)'),
3609 _(b'show active branchheads only (DEPRECATED)'),
3610 ),
3610 ),
3611 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3611 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3612 ]
3612 ]
3613 + templateopts,
3613 + templateopts,
3614 _(b'[-ct] [-r STARTREV] [REV]...'),
3614 _(b'[-ct] [-r STARTREV] [REV]...'),
3615 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3615 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3616 intents={INTENT_READONLY},
3616 intents={INTENT_READONLY},
3617 )
3617 )
3618 def heads(ui, repo, *branchrevs, **opts):
3618 def heads(ui, repo, *branchrevs, **opts):
3619 """show branch heads
3619 """show branch heads
3620
3620
3621 With no arguments, show all open branch heads in the repository.
3621 With no arguments, show all open branch heads in the repository.
3622 Branch heads are changesets that have no descendants on the
3622 Branch heads are changesets that have no descendants on the
3623 same branch. They are where development generally takes place and
3623 same branch. They are where development generally takes place and
3624 are the usual targets for update and merge operations.
3624 are the usual targets for update and merge operations.
3625
3625
3626 If one or more REVs are given, only open branch heads on the
3626 If one or more REVs are given, only open branch heads on the
3627 branches associated with the specified changesets are shown. This
3627 branches associated with the specified changesets are shown. This
3628 means that you can use :hg:`heads .` to see the heads on the
3628 means that you can use :hg:`heads .` to see the heads on the
3629 currently checked-out branch.
3629 currently checked-out branch.
3630
3630
3631 If -c/--closed is specified, also show branch heads marked closed
3631 If -c/--closed is specified, also show branch heads marked closed
3632 (see :hg:`commit --close-branch`).
3632 (see :hg:`commit --close-branch`).
3633
3633
3634 If STARTREV is specified, only those heads that are descendants of
3634 If STARTREV is specified, only those heads that are descendants of
3635 STARTREV will be displayed.
3635 STARTREV will be displayed.
3636
3636
3637 If -t/--topo is specified, named branch mechanics will be ignored and only
3637 If -t/--topo is specified, named branch mechanics will be ignored and only
3638 topological heads (changesets with no children) will be shown.
3638 topological heads (changesets with no children) will be shown.
3639
3639
3640 Returns 0 if matching heads are found, 1 if not.
3640 Returns 0 if matching heads are found, 1 if not.
3641 """
3641 """
3642
3642
3643 opts = pycompat.byteskwargs(opts)
3643 opts = pycompat.byteskwargs(opts)
3644 start = None
3644 start = None
3645 rev = opts.get(b'rev')
3645 rev = opts.get(b'rev')
3646 if rev:
3646 if rev:
3647 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3647 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3648 start = scmutil.revsingle(repo, rev, None).node()
3648 start = scmutil.revsingle(repo, rev, None).node()
3649
3649
3650 if opts.get(b'topo'):
3650 if opts.get(b'topo'):
3651 heads = [repo[h] for h in repo.heads(start)]
3651 heads = [repo[h] for h in repo.heads(start)]
3652 else:
3652 else:
3653 heads = []
3653 heads = []
3654 for branch in repo.branchmap():
3654 for branch in repo.branchmap():
3655 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3655 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3656 heads = [repo[h] for h in heads]
3656 heads = [repo[h] for h in heads]
3657
3657
3658 if branchrevs:
3658 if branchrevs:
3659 branches = {
3659 branches = {
3660 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3660 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3661 }
3661 }
3662 heads = [h for h in heads if h.branch() in branches]
3662 heads = [h for h in heads if h.branch() in branches]
3663
3663
3664 if opts.get(b'active') and branchrevs:
3664 if opts.get(b'active') and branchrevs:
3665 dagheads = repo.heads(start)
3665 dagheads = repo.heads(start)
3666 heads = [h for h in heads if h.node() in dagheads]
3666 heads = [h for h in heads if h.node() in dagheads]
3667
3667
3668 if branchrevs:
3668 if branchrevs:
3669 haveheads = {h.branch() for h in heads}
3669 haveheads = {h.branch() for h in heads}
3670 if branches - haveheads:
3670 if branches - haveheads:
3671 headless = b', '.join(b for b in branches - haveheads)
3671 headless = b', '.join(b for b in branches - haveheads)
3672 msg = _(b'no open branch heads found on branches %s')
3672 msg = _(b'no open branch heads found on branches %s')
3673 if opts.get(b'rev'):
3673 if opts.get(b'rev'):
3674 msg += _(b' (started at %s)') % opts[b'rev']
3674 msg += _(b' (started at %s)') % opts[b'rev']
3675 ui.warn((msg + b'\n') % headless)
3675 ui.warn((msg + b'\n') % headless)
3676
3676
3677 if not heads:
3677 if not heads:
3678 return 1
3678 return 1
3679
3679
3680 ui.pager(b'heads')
3680 ui.pager(b'heads')
3681 heads = sorted(heads, key=lambda x: -(x.rev()))
3681 heads = sorted(heads, key=lambda x: -(x.rev()))
3682 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3682 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3683 for ctx in heads:
3683 for ctx in heads:
3684 displayer.show(ctx)
3684 displayer.show(ctx)
3685 displayer.close()
3685 displayer.close()
3686
3686
3687
3687
3688 @command(
3688 @command(
3689 b'help',
3689 b'help',
3690 [
3690 [
3691 (b'e', b'extension', None, _(b'show only help for extensions')),
3691 (b'e', b'extension', None, _(b'show only help for extensions')),
3692 (b'c', b'command', None, _(b'show only help for commands')),
3692 (b'c', b'command', None, _(b'show only help for commands')),
3693 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3693 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3694 (
3694 (
3695 b's',
3695 b's',
3696 b'system',
3696 b'system',
3697 [],
3697 [],
3698 _(b'show help for specific platform(s)'),
3698 _(b'show help for specific platform(s)'),
3699 _(b'PLATFORM'),
3699 _(b'PLATFORM'),
3700 ),
3700 ),
3701 ],
3701 ],
3702 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3702 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3703 helpcategory=command.CATEGORY_HELP,
3703 helpcategory=command.CATEGORY_HELP,
3704 norepo=True,
3704 norepo=True,
3705 intents={INTENT_READONLY},
3705 intents={INTENT_READONLY},
3706 )
3706 )
3707 def help_(ui, name=None, **opts):
3707 def help_(ui, name=None, **opts):
3708 """show help for a given topic or a help overview
3708 """show help for a given topic or a help overview
3709
3709
3710 With no arguments, print a list of commands with short help messages.
3710 With no arguments, print a list of commands with short help messages.
3711
3711
3712 Given a topic, extension, or command name, print help for that
3712 Given a topic, extension, or command name, print help for that
3713 topic.
3713 topic.
3714
3714
3715 Returns 0 if successful.
3715 Returns 0 if successful.
3716 """
3716 """
3717
3717
3718 keep = opts.get('system') or []
3718 keep = opts.get('system') or []
3719 if len(keep) == 0:
3719 if len(keep) == 0:
3720 if pycompat.sysplatform.startswith(b'win'):
3720 if pycompat.sysplatform.startswith(b'win'):
3721 keep.append(b'windows')
3721 keep.append(b'windows')
3722 elif pycompat.sysplatform == b'OpenVMS':
3722 elif pycompat.sysplatform == b'OpenVMS':
3723 keep.append(b'vms')
3723 keep.append(b'vms')
3724 elif pycompat.sysplatform == b'plan9':
3724 elif pycompat.sysplatform == b'plan9':
3725 keep.append(b'plan9')
3725 keep.append(b'plan9')
3726 else:
3726 else:
3727 keep.append(b'unix')
3727 keep.append(b'unix')
3728 keep.append(pycompat.sysplatform.lower())
3728 keep.append(pycompat.sysplatform.lower())
3729 if ui.verbose:
3729 if ui.verbose:
3730 keep.append(b'verbose')
3730 keep.append(b'verbose')
3731
3731
3732 commands = sys.modules[__name__]
3732 commands = sys.modules[__name__]
3733 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3733 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3734 ui.pager(b'help')
3734 ui.pager(b'help')
3735 ui.write(formatted)
3735 ui.write(formatted)
3736
3736
3737
3737
3738 @command(
3738 @command(
3739 b'identify|id',
3739 b'identify|id',
3740 [
3740 [
3741 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3741 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3742 (b'n', b'num', None, _(b'show local revision number')),
3742 (b'n', b'num', None, _(b'show local revision number')),
3743 (b'i', b'id', None, _(b'show global revision id')),
3743 (b'i', b'id', None, _(b'show global revision id')),
3744 (b'b', b'branch', None, _(b'show branch')),
3744 (b'b', b'branch', None, _(b'show branch')),
3745 (b't', b'tags', None, _(b'show tags')),
3745 (b't', b'tags', None, _(b'show tags')),
3746 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3746 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3747 ]
3747 ]
3748 + remoteopts
3748 + remoteopts
3749 + formatteropts,
3749 + formatteropts,
3750 _(b'[-nibtB] [-r REV] [SOURCE]'),
3750 _(b'[-nibtB] [-r REV] [SOURCE]'),
3751 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3751 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3752 optionalrepo=True,
3752 optionalrepo=True,
3753 intents={INTENT_READONLY},
3753 intents={INTENT_READONLY},
3754 )
3754 )
3755 def identify(
3755 def identify(
3756 ui,
3756 ui,
3757 repo,
3757 repo,
3758 source=None,
3758 source=None,
3759 rev=None,
3759 rev=None,
3760 num=None,
3760 num=None,
3761 id=None,
3761 id=None,
3762 branch=None,
3762 branch=None,
3763 tags=None,
3763 tags=None,
3764 bookmarks=None,
3764 bookmarks=None,
3765 **opts
3765 **opts
3766 ):
3766 ):
3767 """identify the working directory or specified revision
3767 """identify the working directory or specified revision
3768
3768
3769 Print a summary identifying the repository state at REV using one or
3769 Print a summary identifying the repository state at REV using one or
3770 two parent hash identifiers, followed by a "+" if the working
3770 two parent hash identifiers, followed by a "+" if the working
3771 directory has uncommitted changes, the branch name (if not default),
3771 directory has uncommitted changes, the branch name (if not default),
3772 a list of tags, and a list of bookmarks.
3772 a list of tags, and a list of bookmarks.
3773
3773
3774 When REV is not given, print a summary of the current state of the
3774 When REV is not given, print a summary of the current state of the
3775 repository including the working directory. Specify -r. to get information
3775 repository including the working directory. Specify -r. to get information
3776 of the working directory parent without scanning uncommitted changes.
3776 of the working directory parent without scanning uncommitted changes.
3777
3777
3778 Specifying a path to a repository root or Mercurial bundle will
3778 Specifying a path to a repository root or Mercurial bundle will
3779 cause lookup to operate on that repository/bundle.
3779 cause lookup to operate on that repository/bundle.
3780
3780
3781 .. container:: verbose
3781 .. container:: verbose
3782
3782
3783 Template:
3783 Template:
3784
3784
3785 The following keywords are supported in addition to the common template
3785 The following keywords are supported in addition to the common template
3786 keywords and functions. See also :hg:`help templates`.
3786 keywords and functions. See also :hg:`help templates`.
3787
3787
3788 :dirty: String. Character ``+`` denoting if the working directory has
3788 :dirty: String. Character ``+`` denoting if the working directory has
3789 uncommitted changes.
3789 uncommitted changes.
3790 :id: String. One or two nodes, optionally followed by ``+``.
3790 :id: String. One or two nodes, optionally followed by ``+``.
3791 :parents: List of strings. Parent nodes of the changeset.
3791 :parents: List of strings. Parent nodes of the changeset.
3792
3792
3793 Examples:
3793 Examples:
3794
3794
3795 - generate a build identifier for the working directory::
3795 - generate a build identifier for the working directory::
3796
3796
3797 hg id --id > build-id.dat
3797 hg id --id > build-id.dat
3798
3798
3799 - find the revision corresponding to a tag::
3799 - find the revision corresponding to a tag::
3800
3800
3801 hg id -n -r 1.3
3801 hg id -n -r 1.3
3802
3802
3803 - check the most recent revision of a remote repository::
3803 - check the most recent revision of a remote repository::
3804
3804
3805 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3805 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3806
3806
3807 See :hg:`log` for generating more information about specific revisions,
3807 See :hg:`log` for generating more information about specific revisions,
3808 including full hash identifiers.
3808 including full hash identifiers.
3809
3809
3810 Returns 0 if successful.
3810 Returns 0 if successful.
3811 """
3811 """
3812
3812
3813 opts = pycompat.byteskwargs(opts)
3813 opts = pycompat.byteskwargs(opts)
3814 if not repo and not source:
3814 if not repo and not source:
3815 raise error.InputError(
3815 raise error.InputError(
3816 _(b"there is no Mercurial repository here (.hg not found)")
3816 _(b"there is no Mercurial repository here (.hg not found)")
3817 )
3817 )
3818
3818
3819 default = not (num or id or branch or tags or bookmarks)
3819 default = not (num or id or branch or tags or bookmarks)
3820 output = []
3820 output = []
3821 revs = []
3821 revs = []
3822
3822
3823 peer = None
3823 peer = None
3824 try:
3824 try:
3825 if source:
3825 if source:
3826 source, branches = hg.parseurl(ui.expandpath(source))
3826 source, branches = hg.parseurl(ui.expandpath(source))
3827 # only pass ui when no repo
3827 # only pass ui when no repo
3828 peer = hg.peer(repo or ui, opts, source)
3828 peer = hg.peer(repo or ui, opts, source)
3829 repo = peer.local()
3829 repo = peer.local()
3830 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3830 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3831
3831
3832 fm = ui.formatter(b'identify', opts)
3832 fm = ui.formatter(b'identify', opts)
3833 fm.startitem()
3833 fm.startitem()
3834
3834
3835 if not repo:
3835 if not repo:
3836 if num or branch or tags:
3836 if num or branch or tags:
3837 raise error.InputError(
3837 raise error.InputError(
3838 _(b"can't query remote revision number, branch, or tags")
3838 _(b"can't query remote revision number, branch, or tags")
3839 )
3839 )
3840 if not rev and revs:
3840 if not rev and revs:
3841 rev = revs[0]
3841 rev = revs[0]
3842 if not rev:
3842 if not rev:
3843 rev = b"tip"
3843 rev = b"tip"
3844
3844
3845 remoterev = peer.lookup(rev)
3845 remoterev = peer.lookup(rev)
3846 hexrev = fm.hexfunc(remoterev)
3846 hexrev = fm.hexfunc(remoterev)
3847 if default or id:
3847 if default or id:
3848 output = [hexrev]
3848 output = [hexrev]
3849 fm.data(id=hexrev)
3849 fm.data(id=hexrev)
3850
3850
3851 @util.cachefunc
3851 @util.cachefunc
3852 def getbms():
3852 def getbms():
3853 bms = []
3853 bms = []
3854
3854
3855 if b'bookmarks' in peer.listkeys(b'namespaces'):
3855 if b'bookmarks' in peer.listkeys(b'namespaces'):
3856 hexremoterev = hex(remoterev)
3856 hexremoterev = hex(remoterev)
3857 bms = [
3857 bms = [
3858 bm
3858 bm
3859 for bm, bmr in pycompat.iteritems(
3859 for bm, bmr in pycompat.iteritems(
3860 peer.listkeys(b'bookmarks')
3860 peer.listkeys(b'bookmarks')
3861 )
3861 )
3862 if bmr == hexremoterev
3862 if bmr == hexremoterev
3863 ]
3863 ]
3864
3864
3865 return sorted(bms)
3865 return sorted(bms)
3866
3866
3867 if fm.isplain():
3867 if fm.isplain():
3868 if bookmarks:
3868 if bookmarks:
3869 output.extend(getbms())
3869 output.extend(getbms())
3870 elif default and not ui.quiet:
3870 elif default and not ui.quiet:
3871 # multiple bookmarks for a single parent separated by '/'
3871 # multiple bookmarks for a single parent separated by '/'
3872 bm = b'/'.join(getbms())
3872 bm = b'/'.join(getbms())
3873 if bm:
3873 if bm:
3874 output.append(bm)
3874 output.append(bm)
3875 else:
3875 else:
3876 fm.data(node=hex(remoterev))
3876 fm.data(node=hex(remoterev))
3877 if bookmarks or b'bookmarks' in fm.datahint():
3877 if bookmarks or b'bookmarks' in fm.datahint():
3878 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3878 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3879 else:
3879 else:
3880 if rev:
3880 if rev:
3881 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3881 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3882 ctx = scmutil.revsingle(repo, rev, None)
3882 ctx = scmutil.revsingle(repo, rev, None)
3883
3883
3884 if ctx.rev() is None:
3884 if ctx.rev() is None:
3885 ctx = repo[None]
3885 ctx = repo[None]
3886 parents = ctx.parents()
3886 parents = ctx.parents()
3887 taglist = []
3887 taglist = []
3888 for p in parents:
3888 for p in parents:
3889 taglist.extend(p.tags())
3889 taglist.extend(p.tags())
3890
3890
3891 dirty = b""
3891 dirty = b""
3892 if ctx.dirty(missing=True, merge=False, branch=False):
3892 if ctx.dirty(missing=True, merge=False, branch=False):
3893 dirty = b'+'
3893 dirty = b'+'
3894 fm.data(dirty=dirty)
3894 fm.data(dirty=dirty)
3895
3895
3896 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3896 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3897 if default or id:
3897 if default or id:
3898 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3898 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3899 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3899 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3900
3900
3901 if num:
3901 if num:
3902 numoutput = [b"%d" % p.rev() for p in parents]
3902 numoutput = [b"%d" % p.rev() for p in parents]
3903 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3903 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3904
3904
3905 fm.data(
3905 fm.data(
3906 parents=fm.formatlist(
3906 parents=fm.formatlist(
3907 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3907 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3908 )
3908 )
3909 )
3909 )
3910 else:
3910 else:
3911 hexoutput = fm.hexfunc(ctx.node())
3911 hexoutput = fm.hexfunc(ctx.node())
3912 if default or id:
3912 if default or id:
3913 output = [hexoutput]
3913 output = [hexoutput]
3914 fm.data(id=hexoutput)
3914 fm.data(id=hexoutput)
3915
3915
3916 if num:
3916 if num:
3917 output.append(pycompat.bytestr(ctx.rev()))
3917 output.append(pycompat.bytestr(ctx.rev()))
3918 taglist = ctx.tags()
3918 taglist = ctx.tags()
3919
3919
3920 if default and not ui.quiet:
3920 if default and not ui.quiet:
3921 b = ctx.branch()
3921 b = ctx.branch()
3922 if b != b'default':
3922 if b != b'default':
3923 output.append(b"(%s)" % b)
3923 output.append(b"(%s)" % b)
3924
3924
3925 # multiple tags for a single parent separated by '/'
3925 # multiple tags for a single parent separated by '/'
3926 t = b'/'.join(taglist)
3926 t = b'/'.join(taglist)
3927 if t:
3927 if t:
3928 output.append(t)
3928 output.append(t)
3929
3929
3930 # multiple bookmarks for a single parent separated by '/'
3930 # multiple bookmarks for a single parent separated by '/'
3931 bm = b'/'.join(ctx.bookmarks())
3931 bm = b'/'.join(ctx.bookmarks())
3932 if bm:
3932 if bm:
3933 output.append(bm)
3933 output.append(bm)
3934 else:
3934 else:
3935 if branch:
3935 if branch:
3936 output.append(ctx.branch())
3936 output.append(ctx.branch())
3937
3937
3938 if tags:
3938 if tags:
3939 output.extend(taglist)
3939 output.extend(taglist)
3940
3940
3941 if bookmarks:
3941 if bookmarks:
3942 output.extend(ctx.bookmarks())
3942 output.extend(ctx.bookmarks())
3943
3943
3944 fm.data(node=ctx.hex())
3944 fm.data(node=ctx.hex())
3945 fm.data(branch=ctx.branch())
3945 fm.data(branch=ctx.branch())
3946 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3946 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3947 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3947 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3948 fm.context(ctx=ctx)
3948 fm.context(ctx=ctx)
3949
3949
3950 fm.plain(b"%s\n" % b' '.join(output))
3950 fm.plain(b"%s\n" % b' '.join(output))
3951 fm.end()
3951 fm.end()
3952 finally:
3952 finally:
3953 if peer:
3953 if peer:
3954 peer.close()
3954 peer.close()
3955
3955
3956
3956
3957 @command(
3957 @command(
3958 b'import|patch',
3958 b'import|patch',
3959 [
3959 [
3960 (
3960 (
3961 b'p',
3961 b'p',
3962 b'strip',
3962 b'strip',
3963 1,
3963 1,
3964 _(
3964 _(
3965 b'directory strip option for patch. This has the same '
3965 b'directory strip option for patch. This has the same '
3966 b'meaning as the corresponding patch option'
3966 b'meaning as the corresponding patch option'
3967 ),
3967 ),
3968 _(b'NUM'),
3968 _(b'NUM'),
3969 ),
3969 ),
3970 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3970 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3971 (b'', b'secret', None, _(b'use the secret phase for committing')),
3971 (b'', b'secret', None, _(b'use the secret phase for committing')),
3972 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3972 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3973 (
3973 (
3974 b'f',
3974 b'f',
3975 b'force',
3975 b'force',
3976 None,
3976 None,
3977 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3977 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3978 ),
3978 ),
3979 (
3979 (
3980 b'',
3980 b'',
3981 b'no-commit',
3981 b'no-commit',
3982 None,
3982 None,
3983 _(b"don't commit, just update the working directory"),
3983 _(b"don't commit, just update the working directory"),
3984 ),
3984 ),
3985 (
3985 (
3986 b'',
3986 b'',
3987 b'bypass',
3987 b'bypass',
3988 None,
3988 None,
3989 _(b"apply patch without touching the working directory"),
3989 _(b"apply patch without touching the working directory"),
3990 ),
3990 ),
3991 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3991 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3992 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3992 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3993 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3993 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3994 (
3994 (
3995 b'',
3995 b'',
3996 b'import-branch',
3996 b'import-branch',
3997 None,
3997 None,
3998 _(b'use any branch information in patch (implied by --exact)'),
3998 _(b'use any branch information in patch (implied by --exact)'),
3999 ),
3999 ),
4000 ]
4000 ]
4001 + commitopts
4001 + commitopts
4002 + commitopts2
4002 + commitopts2
4003 + similarityopts,
4003 + similarityopts,
4004 _(b'[OPTION]... PATCH...'),
4004 _(b'[OPTION]... PATCH...'),
4005 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4005 helpcategory=command.CATEGORY_IMPORT_EXPORT,
4006 )
4006 )
4007 def import_(ui, repo, patch1=None, *patches, **opts):
4007 def import_(ui, repo, patch1=None, *patches, **opts):
4008 """import an ordered set of patches
4008 """import an ordered set of patches
4009
4009
4010 Import a list of patches and commit them individually (unless
4010 Import a list of patches and commit them individually (unless
4011 --no-commit is specified).
4011 --no-commit is specified).
4012
4012
4013 To read a patch from standard input (stdin), use "-" as the patch
4013 To read a patch from standard input (stdin), use "-" as the patch
4014 name. If a URL is specified, the patch will be downloaded from
4014 name. If a URL is specified, the patch will be downloaded from
4015 there.
4015 there.
4016
4016
4017 Import first applies changes to the working directory (unless
4017 Import first applies changes to the working directory (unless
4018 --bypass is specified), import will abort if there are outstanding
4018 --bypass is specified), import will abort if there are outstanding
4019 changes.
4019 changes.
4020
4020
4021 Use --bypass to apply and commit patches directly to the
4021 Use --bypass to apply and commit patches directly to the
4022 repository, without affecting the working directory. Without
4022 repository, without affecting the working directory. Without
4023 --exact, patches will be applied on top of the working directory
4023 --exact, patches will be applied on top of the working directory
4024 parent revision.
4024 parent revision.
4025
4025
4026 You can import a patch straight from a mail message. Even patches
4026 You can import a patch straight from a mail message. Even patches
4027 as attachments work (to use the body part, it must have type
4027 as attachments work (to use the body part, it must have type
4028 text/plain or text/x-patch). From and Subject headers of email
4028 text/plain or text/x-patch). From and Subject headers of email
4029 message are used as default committer and commit message. All
4029 message are used as default committer and commit message. All
4030 text/plain body parts before first diff are added to the commit
4030 text/plain body parts before first diff are added to the commit
4031 message.
4031 message.
4032
4032
4033 If the imported patch was generated by :hg:`export`, user and
4033 If the imported patch was generated by :hg:`export`, user and
4034 description from patch override values from message headers and
4034 description from patch override values from message headers and
4035 body. Values given on command line with -m/--message and -u/--user
4035 body. Values given on command line with -m/--message and -u/--user
4036 override these.
4036 override these.
4037
4037
4038 If --exact is specified, import will set the working directory to
4038 If --exact is specified, import will set the working directory to
4039 the parent of each patch before applying it, and will abort if the
4039 the parent of each patch before applying it, and will abort if the
4040 resulting changeset has a different ID than the one recorded in
4040 resulting changeset has a different ID than the one recorded in
4041 the patch. This will guard against various ways that portable
4041 the patch. This will guard against various ways that portable
4042 patch formats and mail systems might fail to transfer Mercurial
4042 patch formats and mail systems might fail to transfer Mercurial
4043 data or metadata. See :hg:`bundle` for lossless transmission.
4043 data or metadata. See :hg:`bundle` for lossless transmission.
4044
4044
4045 Use --partial to ensure a changeset will be created from the patch
4045 Use --partial to ensure a changeset will be created from the patch
4046 even if some hunks fail to apply. Hunks that fail to apply will be
4046 even if some hunks fail to apply. Hunks that fail to apply will be
4047 written to a <target-file>.rej file. Conflicts can then be resolved
4047 written to a <target-file>.rej file. Conflicts can then be resolved
4048 by hand before :hg:`commit --amend` is run to update the created
4048 by hand before :hg:`commit --amend` is run to update the created
4049 changeset. This flag exists to let people import patches that
4049 changeset. This flag exists to let people import patches that
4050 partially apply without losing the associated metadata (author,
4050 partially apply without losing the associated metadata (author,
4051 date, description, ...).
4051 date, description, ...).
4052
4052
4053 .. note::
4053 .. note::
4054
4054
4055 When no hunks apply cleanly, :hg:`import --partial` will create
4055 When no hunks apply cleanly, :hg:`import --partial` will create
4056 an empty changeset, importing only the patch metadata.
4056 an empty changeset, importing only the patch metadata.
4057
4057
4058 With -s/--similarity, hg will attempt to discover renames and
4058 With -s/--similarity, hg will attempt to discover renames and
4059 copies in the patch in the same way as :hg:`addremove`.
4059 copies in the patch in the same way as :hg:`addremove`.
4060
4060
4061 It is possible to use external patch programs to perform the patch
4061 It is possible to use external patch programs to perform the patch
4062 by setting the ``ui.patch`` configuration option. For the default
4062 by setting the ``ui.patch`` configuration option. For the default
4063 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4063 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4064 See :hg:`help config` for more information about configuration
4064 See :hg:`help config` for more information about configuration
4065 files and how to use these options.
4065 files and how to use these options.
4066
4066
4067 See :hg:`help dates` for a list of formats valid for -d/--date.
4067 See :hg:`help dates` for a list of formats valid for -d/--date.
4068
4068
4069 .. container:: verbose
4069 .. container:: verbose
4070
4070
4071 Examples:
4071 Examples:
4072
4072
4073 - import a traditional patch from a website and detect renames::
4073 - import a traditional patch from a website and detect renames::
4074
4074
4075 hg import -s 80 http://example.com/bugfix.patch
4075 hg import -s 80 http://example.com/bugfix.patch
4076
4076
4077 - import a changeset from an hgweb server::
4077 - import a changeset from an hgweb server::
4078
4078
4079 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4079 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4080
4080
4081 - import all the patches in an Unix-style mbox::
4081 - import all the patches in an Unix-style mbox::
4082
4082
4083 hg import incoming-patches.mbox
4083 hg import incoming-patches.mbox
4084
4084
4085 - import patches from stdin::
4085 - import patches from stdin::
4086
4086
4087 hg import -
4087 hg import -
4088
4088
4089 - attempt to exactly restore an exported changeset (not always
4089 - attempt to exactly restore an exported changeset (not always
4090 possible)::
4090 possible)::
4091
4091
4092 hg import --exact proposed-fix.patch
4092 hg import --exact proposed-fix.patch
4093
4093
4094 - use an external tool to apply a patch which is too fuzzy for
4094 - use an external tool to apply a patch which is too fuzzy for
4095 the default internal tool.
4095 the default internal tool.
4096
4096
4097 hg import --config ui.patch="patch --merge" fuzzy.patch
4097 hg import --config ui.patch="patch --merge" fuzzy.patch
4098
4098
4099 - change the default fuzzing from 2 to a less strict 7
4099 - change the default fuzzing from 2 to a less strict 7
4100
4100
4101 hg import --config ui.fuzz=7 fuzz.patch
4101 hg import --config ui.fuzz=7 fuzz.patch
4102
4102
4103 Returns 0 on success, 1 on partial success (see --partial).
4103 Returns 0 on success, 1 on partial success (see --partial).
4104 """
4104 """
4105
4105
4106 cmdutil.check_incompatible_arguments(
4106 cmdutil.check_incompatible_arguments(
4107 opts, 'no_commit', ['bypass', 'secret']
4107 opts, 'no_commit', ['bypass', 'secret']
4108 )
4108 )
4109 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4109 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4110 opts = pycompat.byteskwargs(opts)
4110 opts = pycompat.byteskwargs(opts)
4111 if not patch1:
4111 if not patch1:
4112 raise error.InputError(_(b'need at least one patch to import'))
4112 raise error.InputError(_(b'need at least one patch to import'))
4113
4113
4114 patches = (patch1,) + patches
4114 patches = (patch1,) + patches
4115
4115
4116 date = opts.get(b'date')
4116 date = opts.get(b'date')
4117 if date:
4117 if date:
4118 opts[b'date'] = dateutil.parsedate(date)
4118 opts[b'date'] = dateutil.parsedate(date)
4119
4119
4120 exact = opts.get(b'exact')
4120 exact = opts.get(b'exact')
4121 update = not opts.get(b'bypass')
4121 update = not opts.get(b'bypass')
4122 try:
4122 try:
4123 sim = float(opts.get(b'similarity') or 0)
4123 sim = float(opts.get(b'similarity') or 0)
4124 except ValueError:
4124 except ValueError:
4125 raise error.InputError(_(b'similarity must be a number'))
4125 raise error.InputError(_(b'similarity must be a number'))
4126 if sim < 0 or sim > 100:
4126 if sim < 0 or sim > 100:
4127 raise error.InputError(_(b'similarity must be between 0 and 100'))
4127 raise error.InputError(_(b'similarity must be between 0 and 100'))
4128 if sim and not update:
4128 if sim and not update:
4129 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4129 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4130
4130
4131 base = opts[b"base"]
4131 base = opts[b"base"]
4132 msgs = []
4132 msgs = []
4133 ret = 0
4133 ret = 0
4134
4134
4135 with repo.wlock():
4135 with repo.wlock():
4136 if update:
4136 if update:
4137 cmdutil.checkunfinished(repo)
4137 cmdutil.checkunfinished(repo)
4138 if exact or not opts.get(b'force'):
4138 if exact or not opts.get(b'force'):
4139 cmdutil.bailifchanged(repo)
4139 cmdutil.bailifchanged(repo)
4140
4140
4141 if not opts.get(b'no_commit'):
4141 if not opts.get(b'no_commit'):
4142 lock = repo.lock
4142 lock = repo.lock
4143 tr = lambda: repo.transaction(b'import')
4143 tr = lambda: repo.transaction(b'import')
4144 dsguard = util.nullcontextmanager
4144 dsguard = util.nullcontextmanager
4145 else:
4145 else:
4146 lock = util.nullcontextmanager
4146 lock = util.nullcontextmanager
4147 tr = util.nullcontextmanager
4147 tr = util.nullcontextmanager
4148 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4148 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4149 with lock(), tr(), dsguard():
4149 with lock(), tr(), dsguard():
4150 parents = repo[None].parents()
4150 parents = repo[None].parents()
4151 for patchurl in patches:
4151 for patchurl in patches:
4152 if patchurl == b'-':
4152 if patchurl == b'-':
4153 ui.status(_(b'applying patch from stdin\n'))
4153 ui.status(_(b'applying patch from stdin\n'))
4154 patchfile = ui.fin
4154 patchfile = ui.fin
4155 patchurl = b'stdin' # for error message
4155 patchurl = b'stdin' # for error message
4156 else:
4156 else:
4157 patchurl = os.path.join(base, patchurl)
4157 patchurl = os.path.join(base, patchurl)
4158 ui.status(_(b'applying %s\n') % patchurl)
4158 ui.status(_(b'applying %s\n') % patchurl)
4159 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4159 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4160
4160
4161 haspatch = False
4161 haspatch = False
4162 for hunk in patch.split(patchfile):
4162 for hunk in patch.split(patchfile):
4163 with patch.extract(ui, hunk) as patchdata:
4163 with patch.extract(ui, hunk) as patchdata:
4164 msg, node, rej = cmdutil.tryimportone(
4164 msg, node, rej = cmdutil.tryimportone(
4165 ui, repo, patchdata, parents, opts, msgs, hg.clean
4165 ui, repo, patchdata, parents, opts, msgs, hg.clean
4166 )
4166 )
4167 if msg:
4167 if msg:
4168 haspatch = True
4168 haspatch = True
4169 ui.note(msg + b'\n')
4169 ui.note(msg + b'\n')
4170 if update or exact:
4170 if update or exact:
4171 parents = repo[None].parents()
4171 parents = repo[None].parents()
4172 else:
4172 else:
4173 parents = [repo[node]]
4173 parents = [repo[node]]
4174 if rej:
4174 if rej:
4175 ui.write_err(_(b"patch applied partially\n"))
4175 ui.write_err(_(b"patch applied partially\n"))
4176 ui.write_err(
4176 ui.write_err(
4177 _(
4177 _(
4178 b"(fix the .rej files and run "
4178 b"(fix the .rej files and run "
4179 b"`hg commit --amend`)\n"
4179 b"`hg commit --amend`)\n"
4180 )
4180 )
4181 )
4181 )
4182 ret = 1
4182 ret = 1
4183 break
4183 break
4184
4184
4185 if not haspatch:
4185 if not haspatch:
4186 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4186 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4187
4187
4188 if msgs:
4188 if msgs:
4189 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4189 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4190 return ret
4190 return ret
4191
4191
4192
4192
4193 @command(
4193 @command(
4194 b'incoming|in',
4194 b'incoming|in',
4195 [
4195 [
4196 (
4196 (
4197 b'f',
4197 b'f',
4198 b'force',
4198 b'force',
4199 None,
4199 None,
4200 _(b'run even if remote repository is unrelated'),
4200 _(b'run even if remote repository is unrelated'),
4201 ),
4201 ),
4202 (b'n', b'newest-first', None, _(b'show newest record first')),
4202 (b'n', b'newest-first', None, _(b'show newest record first')),
4203 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4203 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4204 (
4204 (
4205 b'r',
4205 b'r',
4206 b'rev',
4206 b'rev',
4207 [],
4207 [],
4208 _(b'a remote changeset intended to be added'),
4208 _(b'a remote changeset intended to be added'),
4209 _(b'REV'),
4209 _(b'REV'),
4210 ),
4210 ),
4211 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4211 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4212 (
4212 (
4213 b'b',
4213 b'b',
4214 b'branch',
4214 b'branch',
4215 [],
4215 [],
4216 _(b'a specific branch you would like to pull'),
4216 _(b'a specific branch you would like to pull'),
4217 _(b'BRANCH'),
4217 _(b'BRANCH'),
4218 ),
4218 ),
4219 ]
4219 ]
4220 + logopts
4220 + logopts
4221 + remoteopts
4221 + remoteopts
4222 + subrepoopts,
4222 + subrepoopts,
4223 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4223 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4224 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4224 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4225 )
4225 )
4226 def incoming(ui, repo, source=b"default", **opts):
4226 def incoming(ui, repo, source=b"default", **opts):
4227 """show new changesets found in source
4227 """show new changesets found in source
4228
4228
4229 Show new changesets found in the specified path/URL or the default
4229 Show new changesets found in the specified path/URL or the default
4230 pull location. These are the changesets that would have been pulled
4230 pull location. These are the changesets that would have been pulled
4231 by :hg:`pull` at the time you issued this command.
4231 by :hg:`pull` at the time you issued this command.
4232
4232
4233 See pull for valid source format details.
4233 See pull for valid source format details.
4234
4234
4235 .. container:: verbose
4235 .. container:: verbose
4236
4236
4237 With -B/--bookmarks, the result of bookmark comparison between
4237 With -B/--bookmarks, the result of bookmark comparison between
4238 local and remote repositories is displayed. With -v/--verbose,
4238 local and remote repositories is displayed. With -v/--verbose,
4239 status is also displayed for each bookmark like below::
4239 status is also displayed for each bookmark like below::
4240
4240
4241 BM1 01234567890a added
4241 BM1 01234567890a added
4242 BM2 1234567890ab advanced
4242 BM2 1234567890ab advanced
4243 BM3 234567890abc diverged
4243 BM3 234567890abc diverged
4244 BM4 34567890abcd changed
4244 BM4 34567890abcd changed
4245
4245
4246 The action taken locally when pulling depends on the
4246 The action taken locally when pulling depends on the
4247 status of each bookmark:
4247 status of each bookmark:
4248
4248
4249 :``added``: pull will create it
4249 :``added``: pull will create it
4250 :``advanced``: pull will update it
4250 :``advanced``: pull will update it
4251 :``diverged``: pull will create a divergent bookmark
4251 :``diverged``: pull will create a divergent bookmark
4252 :``changed``: result depends on remote changesets
4252 :``changed``: result depends on remote changesets
4253
4253
4254 From the point of view of pulling behavior, bookmark
4254 From the point of view of pulling behavior, bookmark
4255 existing only in the remote repository are treated as ``added``,
4255 existing only in the remote repository are treated as ``added``,
4256 even if it is in fact locally deleted.
4256 even if it is in fact locally deleted.
4257
4257
4258 .. container:: verbose
4258 .. container:: verbose
4259
4259
4260 For remote repository, using --bundle avoids downloading the
4260 For remote repository, using --bundle avoids downloading the
4261 changesets twice if the incoming is followed by a pull.
4261 changesets twice if the incoming is followed by a pull.
4262
4262
4263 Examples:
4263 Examples:
4264
4264
4265 - show incoming changes with patches and full description::
4265 - show incoming changes with patches and full description::
4266
4266
4267 hg incoming -vp
4267 hg incoming -vp
4268
4268
4269 - show incoming changes excluding merges, store a bundle::
4269 - show incoming changes excluding merges, store a bundle::
4270
4270
4271 hg in -vpM --bundle incoming.hg
4271 hg in -vpM --bundle incoming.hg
4272 hg pull incoming.hg
4272 hg pull incoming.hg
4273
4273
4274 - briefly list changes inside a bundle::
4274 - briefly list changes inside a bundle::
4275
4275
4276 hg in changes.hg -T "{desc|firstline}\\n"
4276 hg in changes.hg -T "{desc|firstline}\\n"
4277
4277
4278 Returns 0 if there are incoming changes, 1 otherwise.
4278 Returns 0 if there are incoming changes, 1 otherwise.
4279 """
4279 """
4280 opts = pycompat.byteskwargs(opts)
4280 opts = pycompat.byteskwargs(opts)
4281 if opts.get(b'graph'):
4281 if opts.get(b'graph'):
4282 logcmdutil.checkunsupportedgraphflags([], opts)
4282 logcmdutil.checkunsupportedgraphflags([], opts)
4283
4283
4284 def display(other, chlist, displayer):
4284 def display(other, chlist, displayer):
4285 revdag = logcmdutil.graphrevs(other, chlist, opts)
4285 revdag = logcmdutil.graphrevs(other, chlist, opts)
4286 logcmdutil.displaygraph(
4286 logcmdutil.displaygraph(
4287 ui, repo, revdag, displayer, graphmod.asciiedges
4287 ui, repo, revdag, displayer, graphmod.asciiedges
4288 )
4288 )
4289
4289
4290 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4290 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4291 return 0
4291 return 0
4292
4292
4293 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4293 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4294
4294
4295 if opts.get(b'bookmarks'):
4295 if opts.get(b'bookmarks'):
4296 source, branches = hg.parseurl(
4296 source, branches = hg.parseurl(
4297 ui.expandpath(source), opts.get(b'branch')
4297 ui.expandpath(source), opts.get(b'branch')
4298 )
4298 )
4299 other = hg.peer(repo, opts, source)
4299 other = hg.peer(repo, opts, source)
4300 try:
4300 try:
4301 if b'bookmarks' not in other.listkeys(b'namespaces'):
4301 if b'bookmarks' not in other.listkeys(b'namespaces'):
4302 ui.warn(_(b"remote doesn't support bookmarks\n"))
4302 ui.warn(_(b"remote doesn't support bookmarks\n"))
4303 return 0
4303 return 0
4304 ui.pager(b'incoming')
4304 ui.pager(b'incoming')
4305 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4305 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4306 return bookmarks.incoming(ui, repo, other)
4306 return bookmarks.incoming(ui, repo, other)
4307 finally:
4307 finally:
4308 other.close()
4308 other.close()
4309
4309
4310 repo._subtoppath = ui.expandpath(source)
4310 repo._subtoppath = ui.expandpath(source)
4311 try:
4311 try:
4312 return hg.incoming(ui, repo, source, opts)
4312 return hg.incoming(ui, repo, source, opts)
4313 finally:
4313 finally:
4314 del repo._subtoppath
4314 del repo._subtoppath
4315
4315
4316
4316
4317 @command(
4317 @command(
4318 b'init',
4318 b'init',
4319 remoteopts,
4319 remoteopts,
4320 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4320 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4321 helpcategory=command.CATEGORY_REPO_CREATION,
4321 helpcategory=command.CATEGORY_REPO_CREATION,
4322 helpbasic=True,
4322 helpbasic=True,
4323 norepo=True,
4323 norepo=True,
4324 )
4324 )
4325 def init(ui, dest=b".", **opts):
4325 def init(ui, dest=b".", **opts):
4326 """create a new repository in the given directory
4326 """create a new repository in the given directory
4327
4327
4328 Initialize a new repository in the given directory. If the given
4328 Initialize a new repository in the given directory. If the given
4329 directory does not exist, it will be created.
4329 directory does not exist, it will be created.
4330
4330
4331 If no directory is given, the current directory is used.
4331 If no directory is given, the current directory is used.
4332
4332
4333 It is possible to specify an ``ssh://`` URL as the destination.
4333 It is possible to specify an ``ssh://`` URL as the destination.
4334 See :hg:`help urls` for more information.
4334 See :hg:`help urls` for more information.
4335
4335
4336 Returns 0 on success.
4336 Returns 0 on success.
4337 """
4337 """
4338 opts = pycompat.byteskwargs(opts)
4338 opts = pycompat.byteskwargs(opts)
4339 peer = hg.peer(ui, opts, ui.expandpath(dest), create=True)
4339 peer = hg.peer(ui, opts, ui.expandpath(dest), create=True)
4340 peer.close()
4340 peer.close()
4341
4341
4342
4342
4343 @command(
4343 @command(
4344 b'locate',
4344 b'locate',
4345 [
4345 [
4346 (
4346 (
4347 b'r',
4347 b'r',
4348 b'rev',
4348 b'rev',
4349 b'',
4349 b'',
4350 _(b'search the repository as it is in REV'),
4350 _(b'search the repository as it is in REV'),
4351 _(b'REV'),
4351 _(b'REV'),
4352 ),
4352 ),
4353 (
4353 (
4354 b'0',
4354 b'0',
4355 b'print0',
4355 b'print0',
4356 None,
4356 None,
4357 _(b'end filenames with NUL, for use with xargs'),
4357 _(b'end filenames with NUL, for use with xargs'),
4358 ),
4358 ),
4359 (
4359 (
4360 b'f',
4360 b'f',
4361 b'fullpath',
4361 b'fullpath',
4362 None,
4362 None,
4363 _(b'print complete paths from the filesystem root'),
4363 _(b'print complete paths from the filesystem root'),
4364 ),
4364 ),
4365 ]
4365 ]
4366 + walkopts,
4366 + walkopts,
4367 _(b'[OPTION]... [PATTERN]...'),
4367 _(b'[OPTION]... [PATTERN]...'),
4368 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4368 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4369 )
4369 )
4370 def locate(ui, repo, *pats, **opts):
4370 def locate(ui, repo, *pats, **opts):
4371 """locate files matching specific patterns (DEPRECATED)
4371 """locate files matching specific patterns (DEPRECATED)
4372
4372
4373 Print files under Mercurial control in the working directory whose
4373 Print files under Mercurial control in the working directory whose
4374 names match the given patterns.
4374 names match the given patterns.
4375
4375
4376 By default, this command searches all directories in the working
4376 By default, this command searches all directories in the working
4377 directory. To search just the current directory and its
4377 directory. To search just the current directory and its
4378 subdirectories, use "--include .".
4378 subdirectories, use "--include .".
4379
4379
4380 If no patterns are given to match, this command prints the names
4380 If no patterns are given to match, this command prints the names
4381 of all files under Mercurial control in the working directory.
4381 of all files under Mercurial control in the working directory.
4382
4382
4383 If you want to feed the output of this command into the "xargs"
4383 If you want to feed the output of this command into the "xargs"
4384 command, use the -0 option to both this command and "xargs". This
4384 command, use the -0 option to both this command and "xargs". This
4385 will avoid the problem of "xargs" treating single filenames that
4385 will avoid the problem of "xargs" treating single filenames that
4386 contain whitespace as multiple filenames.
4386 contain whitespace as multiple filenames.
4387
4387
4388 See :hg:`help files` for a more versatile command.
4388 See :hg:`help files` for a more versatile command.
4389
4389
4390 Returns 0 if a match is found, 1 otherwise.
4390 Returns 0 if a match is found, 1 otherwise.
4391 """
4391 """
4392 opts = pycompat.byteskwargs(opts)
4392 opts = pycompat.byteskwargs(opts)
4393 if opts.get(b'print0'):
4393 if opts.get(b'print0'):
4394 end = b'\0'
4394 end = b'\0'
4395 else:
4395 else:
4396 end = b'\n'
4396 end = b'\n'
4397 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4397 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4398
4398
4399 ret = 1
4399 ret = 1
4400 m = scmutil.match(
4400 m = scmutil.match(
4401 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4401 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4402 )
4402 )
4403
4403
4404 ui.pager(b'locate')
4404 ui.pager(b'locate')
4405 if ctx.rev() is None:
4405 if ctx.rev() is None:
4406 # When run on the working copy, "locate" includes removed files, so
4406 # When run on the working copy, "locate" includes removed files, so
4407 # we get the list of files from the dirstate.
4407 # we get the list of files from the dirstate.
4408 filesgen = sorted(repo.dirstate.matches(m))
4408 filesgen = sorted(repo.dirstate.matches(m))
4409 else:
4409 else:
4410 filesgen = ctx.matches(m)
4410 filesgen = ctx.matches(m)
4411 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4411 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4412 for abs in filesgen:
4412 for abs in filesgen:
4413 if opts.get(b'fullpath'):
4413 if opts.get(b'fullpath'):
4414 ui.write(repo.wjoin(abs), end)
4414 ui.write(repo.wjoin(abs), end)
4415 else:
4415 else:
4416 ui.write(uipathfn(abs), end)
4416 ui.write(uipathfn(abs), end)
4417 ret = 0
4417 ret = 0
4418
4418
4419 return ret
4419 return ret
4420
4420
4421
4421
4422 @command(
4422 @command(
4423 b'log|history',
4423 b'log|history',
4424 [
4424 [
4425 (
4425 (
4426 b'f',
4426 b'f',
4427 b'follow',
4427 b'follow',
4428 None,
4428 None,
4429 _(
4429 _(
4430 b'follow changeset history, or file history across copies and renames'
4430 b'follow changeset history, or file history across copies and renames'
4431 ),
4431 ),
4432 ),
4432 ),
4433 (
4433 (
4434 b'',
4434 b'',
4435 b'follow-first',
4435 b'follow-first',
4436 None,
4436 None,
4437 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4437 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4438 ),
4438 ),
4439 (
4439 (
4440 b'd',
4440 b'd',
4441 b'date',
4441 b'date',
4442 b'',
4442 b'',
4443 _(b'show revisions matching date spec'),
4443 _(b'show revisions matching date spec'),
4444 _(b'DATE'),
4444 _(b'DATE'),
4445 ),
4445 ),
4446 (b'C', b'copies', None, _(b'show copied files')),
4446 (b'C', b'copies', None, _(b'show copied files')),
4447 (
4447 (
4448 b'k',
4448 b'k',
4449 b'keyword',
4449 b'keyword',
4450 [],
4450 [],
4451 _(b'do case-insensitive search for a given text'),
4451 _(b'do case-insensitive search for a given text'),
4452 _(b'TEXT'),
4452 _(b'TEXT'),
4453 ),
4453 ),
4454 (
4454 (
4455 b'r',
4455 b'r',
4456 b'rev',
4456 b'rev',
4457 [],
4457 [],
4458 _(b'revisions to select or follow from'),
4458 _(b'revisions to select or follow from'),
4459 _(b'REV'),
4459 _(b'REV'),
4460 ),
4460 ),
4461 (
4461 (
4462 b'L',
4462 b'L',
4463 b'line-range',
4463 b'line-range',
4464 [],
4464 [],
4465 _(b'follow line range of specified file (EXPERIMENTAL)'),
4465 _(b'follow line range of specified file (EXPERIMENTAL)'),
4466 _(b'FILE,RANGE'),
4466 _(b'FILE,RANGE'),
4467 ),
4467 ),
4468 (
4468 (
4469 b'',
4469 b'',
4470 b'removed',
4470 b'removed',
4471 None,
4471 None,
4472 _(b'include revisions where files were removed'),
4472 _(b'include revisions where files were removed'),
4473 ),
4473 ),
4474 (
4474 (
4475 b'm',
4475 b'm',
4476 b'only-merges',
4476 b'only-merges',
4477 None,
4477 None,
4478 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4478 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4479 ),
4479 ),
4480 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4480 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4481 (
4481 (
4482 b'',
4482 b'',
4483 b'only-branch',
4483 b'only-branch',
4484 [],
4484 [],
4485 _(
4485 _(
4486 b'show only changesets within the given named branch (DEPRECATED)'
4486 b'show only changesets within the given named branch (DEPRECATED)'
4487 ),
4487 ),
4488 _(b'BRANCH'),
4488 _(b'BRANCH'),
4489 ),
4489 ),
4490 (
4490 (
4491 b'b',
4491 b'b',
4492 b'branch',
4492 b'branch',
4493 [],
4493 [],
4494 _(b'show changesets within the given named branch'),
4494 _(b'show changesets within the given named branch'),
4495 _(b'BRANCH'),
4495 _(b'BRANCH'),
4496 ),
4496 ),
4497 (
4497 (
4498 b'B',
4498 b'B',
4499 b'bookmark',
4499 b'bookmark',
4500 [],
4500 [],
4501 _(b"show changesets within the given bookmark"),
4501 _(b"show changesets within the given bookmark"),
4502 _(b'BOOKMARK'),
4502 _(b'BOOKMARK'),
4503 ),
4503 ),
4504 (
4504 (
4505 b'P',
4505 b'P',
4506 b'prune',
4506 b'prune',
4507 [],
4507 [],
4508 _(b'do not display revision or any of its ancestors'),
4508 _(b'do not display revision or any of its ancestors'),
4509 _(b'REV'),
4509 _(b'REV'),
4510 ),
4510 ),
4511 ]
4511 ]
4512 + logopts
4512 + logopts
4513 + walkopts,
4513 + walkopts,
4514 _(b'[OPTION]... [FILE]'),
4514 _(b'[OPTION]... [FILE]'),
4515 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4515 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4516 helpbasic=True,
4516 helpbasic=True,
4517 inferrepo=True,
4517 inferrepo=True,
4518 intents={INTENT_READONLY},
4518 intents={INTENT_READONLY},
4519 )
4519 )
4520 def log(ui, repo, *pats, **opts):
4520 def log(ui, repo, *pats, **opts):
4521 """show revision history of entire repository or files
4521 """show revision history of entire repository or files
4522
4522
4523 Print the revision history of the specified files or the entire
4523 Print the revision history of the specified files or the entire
4524 project.
4524 project.
4525
4525
4526 If no revision range is specified, the default is ``tip:0`` unless
4526 If no revision range is specified, the default is ``tip:0`` unless
4527 --follow is set.
4527 --follow is set.
4528
4528
4529 File history is shown without following rename or copy history of
4529 File history is shown without following rename or copy history of
4530 files. Use -f/--follow with a filename to follow history across
4530 files. Use -f/--follow with a filename to follow history across
4531 renames and copies. --follow without a filename will only show
4531 renames and copies. --follow without a filename will only show
4532 ancestors of the starting revisions. The starting revisions can be
4532 ancestors of the starting revisions. The starting revisions can be
4533 specified by -r/--rev, which default to the working directory parent.
4533 specified by -r/--rev, which default to the working directory parent.
4534
4534
4535 By default this command prints revision number and changeset id,
4535 By default this command prints revision number and changeset id,
4536 tags, non-trivial parents, user, date and time, and a summary for
4536 tags, non-trivial parents, user, date and time, and a summary for
4537 each commit. When the -v/--verbose switch is used, the list of
4537 each commit. When the -v/--verbose switch is used, the list of
4538 changed files and full commit message are shown.
4538 changed files and full commit message are shown.
4539
4539
4540 With --graph the revisions are shown as an ASCII art DAG with the most
4540 With --graph the revisions are shown as an ASCII art DAG with the most
4541 recent changeset at the top.
4541 recent changeset at the top.
4542 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4542 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4543 involved in an unresolved merge conflict, '_' closes a branch,
4543 involved in an unresolved merge conflict, '_' closes a branch,
4544 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4544 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4545 changeset from the lines below is a parent of the 'o' merge on the same
4545 changeset from the lines below is a parent of the 'o' merge on the same
4546 line.
4546 line.
4547 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4547 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4548 of a '|' indicates one or more revisions in a path are omitted.
4548 of a '|' indicates one or more revisions in a path are omitted.
4549
4549
4550 .. container:: verbose
4550 .. container:: verbose
4551
4551
4552 Use -L/--line-range FILE,M:N options to follow the history of lines
4552 Use -L/--line-range FILE,M:N options to follow the history of lines
4553 from M to N in FILE. With -p/--patch only diff hunks affecting
4553 from M to N in FILE. With -p/--patch only diff hunks affecting
4554 specified line range will be shown. This option requires --follow;
4554 specified line range will be shown. This option requires --follow;
4555 it can be specified multiple times. Currently, this option is not
4555 it can be specified multiple times. Currently, this option is not
4556 compatible with --graph. This option is experimental.
4556 compatible with --graph. This option is experimental.
4557
4557
4558 .. note::
4558 .. note::
4559
4559
4560 :hg:`log --patch` may generate unexpected diff output for merge
4560 :hg:`log --patch` may generate unexpected diff output for merge
4561 changesets, as it will only compare the merge changeset against
4561 changesets, as it will only compare the merge changeset against
4562 its first parent. Also, only files different from BOTH parents
4562 its first parent. Also, only files different from BOTH parents
4563 will appear in files:.
4563 will appear in files:.
4564
4564
4565 .. note::
4565 .. note::
4566
4566
4567 For performance reasons, :hg:`log FILE` may omit duplicate changes
4567 For performance reasons, :hg:`log FILE` may omit duplicate changes
4568 made on branches and will not show removals or mode changes. To
4568 made on branches and will not show removals or mode changes. To
4569 see all such changes, use the --removed switch.
4569 see all such changes, use the --removed switch.
4570
4570
4571 .. container:: verbose
4571 .. container:: verbose
4572
4572
4573 .. note::
4573 .. note::
4574
4574
4575 The history resulting from -L/--line-range options depends on diff
4575 The history resulting from -L/--line-range options depends on diff
4576 options; for instance if white-spaces are ignored, respective changes
4576 options; for instance if white-spaces are ignored, respective changes
4577 with only white-spaces in specified line range will not be listed.
4577 with only white-spaces in specified line range will not be listed.
4578
4578
4579 .. container:: verbose
4579 .. container:: verbose
4580
4580
4581 Some examples:
4581 Some examples:
4582
4582
4583 - changesets with full descriptions and file lists::
4583 - changesets with full descriptions and file lists::
4584
4584
4585 hg log -v
4585 hg log -v
4586
4586
4587 - changesets ancestral to the working directory::
4587 - changesets ancestral to the working directory::
4588
4588
4589 hg log -f
4589 hg log -f
4590
4590
4591 - last 10 commits on the current branch::
4591 - last 10 commits on the current branch::
4592
4592
4593 hg log -l 10 -b .
4593 hg log -l 10 -b .
4594
4594
4595 - changesets showing all modifications of a file, including removals::
4595 - changesets showing all modifications of a file, including removals::
4596
4596
4597 hg log --removed file.c
4597 hg log --removed file.c
4598
4598
4599 - all changesets that touch a directory, with diffs, excluding merges::
4599 - all changesets that touch a directory, with diffs, excluding merges::
4600
4600
4601 hg log -Mp lib/
4601 hg log -Mp lib/
4602
4602
4603 - all revision numbers that match a keyword::
4603 - all revision numbers that match a keyword::
4604
4604
4605 hg log -k bug --template "{rev}\\n"
4605 hg log -k bug --template "{rev}\\n"
4606
4606
4607 - the full hash identifier of the working directory parent::
4607 - the full hash identifier of the working directory parent::
4608
4608
4609 hg log -r . --template "{node}\\n"
4609 hg log -r . --template "{node}\\n"
4610
4610
4611 - list available log templates::
4611 - list available log templates::
4612
4612
4613 hg log -T list
4613 hg log -T list
4614
4614
4615 - check if a given changeset is included in a tagged release::
4615 - check if a given changeset is included in a tagged release::
4616
4616
4617 hg log -r "a21ccf and ancestor(1.9)"
4617 hg log -r "a21ccf and ancestor(1.9)"
4618
4618
4619 - find all changesets by some user in a date range::
4619 - find all changesets by some user in a date range::
4620
4620
4621 hg log -k alice -d "may 2008 to jul 2008"
4621 hg log -k alice -d "may 2008 to jul 2008"
4622
4622
4623 - summary of all changesets after the last tag::
4623 - summary of all changesets after the last tag::
4624
4624
4625 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4625 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4626
4626
4627 - changesets touching lines 13 to 23 for file.c::
4627 - changesets touching lines 13 to 23 for file.c::
4628
4628
4629 hg log -L file.c,13:23
4629 hg log -L file.c,13:23
4630
4630
4631 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4631 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4632 main.c with patch::
4632 main.c with patch::
4633
4633
4634 hg log -L file.c,13:23 -L main.c,2:6 -p
4634 hg log -L file.c,13:23 -L main.c,2:6 -p
4635
4635
4636 See :hg:`help dates` for a list of formats valid for -d/--date.
4636 See :hg:`help dates` for a list of formats valid for -d/--date.
4637
4637
4638 See :hg:`help revisions` for more about specifying and ordering
4638 See :hg:`help revisions` for more about specifying and ordering
4639 revisions.
4639 revisions.
4640
4640
4641 See :hg:`help templates` for more about pre-packaged styles and
4641 See :hg:`help templates` for more about pre-packaged styles and
4642 specifying custom templates. The default template used by the log
4642 specifying custom templates. The default template used by the log
4643 command can be customized via the ``command-templates.log`` configuration
4643 command can be customized via the ``command-templates.log`` configuration
4644 setting.
4644 setting.
4645
4645
4646 Returns 0 on success.
4646 Returns 0 on success.
4647
4647
4648 """
4648 """
4649 opts = pycompat.byteskwargs(opts)
4649 opts = pycompat.byteskwargs(opts)
4650 linerange = opts.get(b'line_range')
4650 linerange = opts.get(b'line_range')
4651
4651
4652 if linerange and not opts.get(b'follow'):
4652 if linerange and not opts.get(b'follow'):
4653 raise error.InputError(_(b'--line-range requires --follow'))
4653 raise error.InputError(_(b'--line-range requires --follow'))
4654
4654
4655 if linerange and pats:
4655 if linerange and pats:
4656 # TODO: take pats as patterns with no line-range filter
4656 # TODO: take pats as patterns with no line-range filter
4657 raise error.InputError(
4657 raise error.InputError(
4658 _(b'FILE arguments are not compatible with --line-range option')
4658 _(b'FILE arguments are not compatible with --line-range option')
4659 )
4659 )
4660
4660
4661 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4661 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4662 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4662 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4663 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4663 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4664 if linerange:
4664 if linerange:
4665 # TODO: should follow file history from logcmdutil._initialrevs(),
4665 # TODO: should follow file history from logcmdutil._initialrevs(),
4666 # then filter the result by logcmdutil._makerevset() and --limit
4666 # then filter the result by logcmdutil._makerevset() and --limit
4667 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4667 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4668
4668
4669 getcopies = None
4669 getcopies = None
4670 if opts.get(b'copies'):
4670 if opts.get(b'copies'):
4671 endrev = None
4671 endrev = None
4672 if revs:
4672 if revs:
4673 endrev = revs.max() + 1
4673 endrev = revs.max() + 1
4674 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4674 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4675
4675
4676 ui.pager(b'log')
4676 ui.pager(b'log')
4677 displayer = logcmdutil.changesetdisplayer(
4677 displayer = logcmdutil.changesetdisplayer(
4678 ui, repo, opts, differ, buffered=True
4678 ui, repo, opts, differ, buffered=True
4679 )
4679 )
4680 if opts.get(b'graph'):
4680 if opts.get(b'graph'):
4681 displayfn = logcmdutil.displaygraphrevs
4681 displayfn = logcmdutil.displaygraphrevs
4682 else:
4682 else:
4683 displayfn = logcmdutil.displayrevs
4683 displayfn = logcmdutil.displayrevs
4684 displayfn(ui, repo, revs, displayer, getcopies)
4684 displayfn(ui, repo, revs, displayer, getcopies)
4685
4685
4686
4686
4687 @command(
4687 @command(
4688 b'manifest',
4688 b'manifest',
4689 [
4689 [
4690 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4690 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4691 (b'', b'all', False, _(b"list files from all revisions")),
4691 (b'', b'all', False, _(b"list files from all revisions")),
4692 ]
4692 ]
4693 + formatteropts,
4693 + formatteropts,
4694 _(b'[-r REV]'),
4694 _(b'[-r REV]'),
4695 helpcategory=command.CATEGORY_MAINTENANCE,
4695 helpcategory=command.CATEGORY_MAINTENANCE,
4696 intents={INTENT_READONLY},
4696 intents={INTENT_READONLY},
4697 )
4697 )
4698 def manifest(ui, repo, node=None, rev=None, **opts):
4698 def manifest(ui, repo, node=None, rev=None, **opts):
4699 """output the current or given revision of the project manifest
4699 """output the current or given revision of the project manifest
4700
4700
4701 Print a list of version controlled files for the given revision.
4701 Print a list of version controlled files for the given revision.
4702 If no revision is given, the first parent of the working directory
4702 If no revision is given, the first parent of the working directory
4703 is used, or the null revision if no revision is checked out.
4703 is used, or the null revision if no revision is checked out.
4704
4704
4705 With -v, print file permissions, symlink and executable bits.
4705 With -v, print file permissions, symlink and executable bits.
4706 With --debug, print file revision hashes.
4706 With --debug, print file revision hashes.
4707
4707
4708 If option --all is specified, the list of all files from all revisions
4708 If option --all is specified, the list of all files from all revisions
4709 is printed. This includes deleted and renamed files.
4709 is printed. This includes deleted and renamed files.
4710
4710
4711 Returns 0 on success.
4711 Returns 0 on success.
4712 """
4712 """
4713 opts = pycompat.byteskwargs(opts)
4713 opts = pycompat.byteskwargs(opts)
4714 fm = ui.formatter(b'manifest', opts)
4714 fm = ui.formatter(b'manifest', opts)
4715
4715
4716 if opts.get(b'all'):
4716 if opts.get(b'all'):
4717 if rev or node:
4717 if rev or node:
4718 raise error.InputError(_(b"can't specify a revision with --all"))
4718 raise error.InputError(_(b"can't specify a revision with --all"))
4719
4719
4720 res = set()
4720 res = set()
4721 for rev in repo:
4721 for rev in repo:
4722 ctx = repo[rev]
4722 ctx = repo[rev]
4723 res |= set(ctx.files())
4723 res |= set(ctx.files())
4724
4724
4725 ui.pager(b'manifest')
4725 ui.pager(b'manifest')
4726 for f in sorted(res):
4726 for f in sorted(res):
4727 fm.startitem()
4727 fm.startitem()
4728 fm.write(b"path", b'%s\n', f)
4728 fm.write(b"path", b'%s\n', f)
4729 fm.end()
4729 fm.end()
4730 return
4730 return
4731
4731
4732 if rev and node:
4732 if rev and node:
4733 raise error.InputError(_(b"please specify just one revision"))
4733 raise error.InputError(_(b"please specify just one revision"))
4734
4734
4735 if not node:
4735 if not node:
4736 node = rev
4736 node = rev
4737
4737
4738 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4738 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4739 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4739 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4740 if node:
4740 if node:
4741 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4741 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4742 ctx = scmutil.revsingle(repo, node)
4742 ctx = scmutil.revsingle(repo, node)
4743 mf = ctx.manifest()
4743 mf = ctx.manifest()
4744 ui.pager(b'manifest')
4744 ui.pager(b'manifest')
4745 for f in ctx:
4745 for f in ctx:
4746 fm.startitem()
4746 fm.startitem()
4747 fm.context(ctx=ctx)
4747 fm.context(ctx=ctx)
4748 fl = ctx[f].flags()
4748 fl = ctx[f].flags()
4749 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4749 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4750 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4750 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4751 fm.write(b'path', b'%s\n', f)
4751 fm.write(b'path', b'%s\n', f)
4752 fm.end()
4752 fm.end()
4753
4753
4754
4754
4755 @command(
4755 @command(
4756 b'merge',
4756 b'merge',
4757 [
4757 [
4758 (
4758 (
4759 b'f',
4759 b'f',
4760 b'force',
4760 b'force',
4761 None,
4761 None,
4762 _(b'force a merge including outstanding changes (DEPRECATED)'),
4762 _(b'force a merge including outstanding changes (DEPRECATED)'),
4763 ),
4763 ),
4764 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4764 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4765 (
4765 (
4766 b'P',
4766 b'P',
4767 b'preview',
4767 b'preview',
4768 None,
4768 None,
4769 _(b'review revisions to merge (no merge is performed)'),
4769 _(b'review revisions to merge (no merge is performed)'),
4770 ),
4770 ),
4771 (b'', b'abort', None, _(b'abort the ongoing merge')),
4771 (b'', b'abort', None, _(b'abort the ongoing merge')),
4772 ]
4772 ]
4773 + mergetoolopts,
4773 + mergetoolopts,
4774 _(b'[-P] [[-r] REV]'),
4774 _(b'[-P] [[-r] REV]'),
4775 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4775 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4776 helpbasic=True,
4776 helpbasic=True,
4777 )
4777 )
4778 def merge(ui, repo, node=None, **opts):
4778 def merge(ui, repo, node=None, **opts):
4779 """merge another revision into working directory
4779 """merge another revision into working directory
4780
4780
4781 The current working directory is updated with all changes made in
4781 The current working directory is updated with all changes made in
4782 the requested revision since the last common predecessor revision.
4782 the requested revision since the last common predecessor revision.
4783
4783
4784 Files that changed between either parent are marked as changed for
4784 Files that changed between either parent are marked as changed for
4785 the next commit and a commit must be performed before any further
4785 the next commit and a commit must be performed before any further
4786 updates to the repository are allowed. The next commit will have
4786 updates to the repository are allowed. The next commit will have
4787 two parents.
4787 two parents.
4788
4788
4789 ``--tool`` can be used to specify the merge tool used for file
4789 ``--tool`` can be used to specify the merge tool used for file
4790 merges. It overrides the HGMERGE environment variable and your
4790 merges. It overrides the HGMERGE environment variable and your
4791 configuration files. See :hg:`help merge-tools` for options.
4791 configuration files. See :hg:`help merge-tools` for options.
4792
4792
4793 If no revision is specified, the working directory's parent is a
4793 If no revision is specified, the working directory's parent is a
4794 head revision, and the current branch contains exactly one other
4794 head revision, and the current branch contains exactly one other
4795 head, the other head is merged with by default. Otherwise, an
4795 head, the other head is merged with by default. Otherwise, an
4796 explicit revision with which to merge must be provided.
4796 explicit revision with which to merge must be provided.
4797
4797
4798 See :hg:`help resolve` for information on handling file conflicts.
4798 See :hg:`help resolve` for information on handling file conflicts.
4799
4799
4800 To undo an uncommitted merge, use :hg:`merge --abort` which
4800 To undo an uncommitted merge, use :hg:`merge --abort` which
4801 will check out a clean copy of the original merge parent, losing
4801 will check out a clean copy of the original merge parent, losing
4802 all changes.
4802 all changes.
4803
4803
4804 Returns 0 on success, 1 if there are unresolved files.
4804 Returns 0 on success, 1 if there are unresolved files.
4805 """
4805 """
4806
4806
4807 opts = pycompat.byteskwargs(opts)
4807 opts = pycompat.byteskwargs(opts)
4808 abort = opts.get(b'abort')
4808 abort = opts.get(b'abort')
4809 if abort and repo.dirstate.p2() == nullid:
4809 if abort and repo.dirstate.p2() == nullid:
4810 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4810 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4811 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4811 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4812 if abort:
4812 if abort:
4813 state = cmdutil.getunfinishedstate(repo)
4813 state = cmdutil.getunfinishedstate(repo)
4814 if state and state._opname != b'merge':
4814 if state and state._opname != b'merge':
4815 raise error.StateError(
4815 raise error.StateError(
4816 _(b'cannot abort merge with %s in progress') % (state._opname),
4816 _(b'cannot abort merge with %s in progress') % (state._opname),
4817 hint=state.hint(),
4817 hint=state.hint(),
4818 )
4818 )
4819 if node:
4819 if node:
4820 raise error.InputError(_(b"cannot specify a node with --abort"))
4820 raise error.InputError(_(b"cannot specify a node with --abort"))
4821 return hg.abortmerge(repo.ui, repo)
4821 return hg.abortmerge(repo.ui, repo)
4822
4822
4823 if opts.get(b'rev') and node:
4823 if opts.get(b'rev') and node:
4824 raise error.InputError(_(b"please specify just one revision"))
4824 raise error.InputError(_(b"please specify just one revision"))
4825 if not node:
4825 if not node:
4826 node = opts.get(b'rev')
4826 node = opts.get(b'rev')
4827
4827
4828 if node:
4828 if node:
4829 ctx = scmutil.revsingle(repo, node)
4829 ctx = scmutil.revsingle(repo, node)
4830 else:
4830 else:
4831 if ui.configbool(b'commands', b'merge.require-rev'):
4831 if ui.configbool(b'commands', b'merge.require-rev'):
4832 raise error.InputError(
4832 raise error.InputError(
4833 _(
4833 _(
4834 b'configuration requires specifying revision to merge '
4834 b'configuration requires specifying revision to merge '
4835 b'with'
4835 b'with'
4836 )
4836 )
4837 )
4837 )
4838 ctx = repo[destutil.destmerge(repo)]
4838 ctx = repo[destutil.destmerge(repo)]
4839
4839
4840 if ctx.node() is None:
4840 if ctx.node() is None:
4841 raise error.InputError(
4841 raise error.InputError(
4842 _(b'merging with the working copy has no effect')
4842 _(b'merging with the working copy has no effect')
4843 )
4843 )
4844
4844
4845 if opts.get(b'preview'):
4845 if opts.get(b'preview'):
4846 # find nodes that are ancestors of p2 but not of p1
4846 # find nodes that are ancestors of p2 but not of p1
4847 p1 = repo[b'.'].node()
4847 p1 = repo[b'.'].node()
4848 p2 = ctx.node()
4848 p2 = ctx.node()
4849 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4849 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4850
4850
4851 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4851 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4852 for node in nodes:
4852 for node in nodes:
4853 displayer.show(repo[node])
4853 displayer.show(repo[node])
4854 displayer.close()
4854 displayer.close()
4855 return 0
4855 return 0
4856
4856
4857 # ui.forcemerge is an internal variable, do not document
4857 # ui.forcemerge is an internal variable, do not document
4858 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4858 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4859 with ui.configoverride(overrides, b'merge'):
4859 with ui.configoverride(overrides, b'merge'):
4860 force = opts.get(b'force')
4860 force = opts.get(b'force')
4861 labels = [b'working copy', b'merge rev']
4861 labels = [b'working copy', b'merge rev']
4862 return hg.merge(ctx, force=force, labels=labels)
4862 return hg.merge(ctx, force=force, labels=labels)
4863
4863
4864
4864
4865 statemod.addunfinished(
4865 statemod.addunfinished(
4866 b'merge',
4866 b'merge',
4867 fname=None,
4867 fname=None,
4868 clearable=True,
4868 clearable=True,
4869 allowcommit=True,
4869 allowcommit=True,
4870 cmdmsg=_(b'outstanding uncommitted merge'),
4870 cmdmsg=_(b'outstanding uncommitted merge'),
4871 abortfunc=hg.abortmerge,
4871 abortfunc=hg.abortmerge,
4872 statushint=_(
4872 statushint=_(
4873 b'To continue: hg commit\nTo abort: hg merge --abort'
4873 b'To continue: hg commit\nTo abort: hg merge --abort'
4874 ),
4874 ),
4875 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4875 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4876 )
4876 )
4877
4877
4878
4878
4879 @command(
4879 @command(
4880 b'outgoing|out',
4880 b'outgoing|out',
4881 [
4881 [
4882 (
4882 (
4883 b'f',
4883 b'f',
4884 b'force',
4884 b'force',
4885 None,
4885 None,
4886 _(b'run even when the destination is unrelated'),
4886 _(b'run even when the destination is unrelated'),
4887 ),
4887 ),
4888 (
4888 (
4889 b'r',
4889 b'r',
4890 b'rev',
4890 b'rev',
4891 [],
4891 [],
4892 _(b'a changeset intended to be included in the destination'),
4892 _(b'a changeset intended to be included in the destination'),
4893 _(b'REV'),
4893 _(b'REV'),
4894 ),
4894 ),
4895 (b'n', b'newest-first', None, _(b'show newest record first')),
4895 (b'n', b'newest-first', None, _(b'show newest record first')),
4896 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4896 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4897 (
4897 (
4898 b'b',
4898 b'b',
4899 b'branch',
4899 b'branch',
4900 [],
4900 [],
4901 _(b'a specific branch you would like to push'),
4901 _(b'a specific branch you would like to push'),
4902 _(b'BRANCH'),
4902 _(b'BRANCH'),
4903 ),
4903 ),
4904 ]
4904 ]
4905 + logopts
4905 + logopts
4906 + remoteopts
4906 + remoteopts
4907 + subrepoopts,
4907 + subrepoopts,
4908 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4908 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4909 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4909 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4910 )
4910 )
4911 def outgoing(ui, repo, dest=None, **opts):
4911 def outgoing(ui, repo, dest=None, **opts):
4912 """show changesets not found in the destination
4912 """show changesets not found in the destination
4913
4913
4914 Show changesets not found in the specified destination repository
4914 Show changesets not found in the specified destination repository
4915 or the default push location. These are the changesets that would
4915 or the default push location. These are the changesets that would
4916 be pushed if a push was requested.
4916 be pushed if a push was requested.
4917
4917
4918 See pull for details of valid destination formats.
4918 See pull for details of valid destination formats.
4919
4919
4920 .. container:: verbose
4920 .. container:: verbose
4921
4921
4922 With -B/--bookmarks, the result of bookmark comparison between
4922 With -B/--bookmarks, the result of bookmark comparison between
4923 local and remote repositories is displayed. With -v/--verbose,
4923 local and remote repositories is displayed. With -v/--verbose,
4924 status is also displayed for each bookmark like below::
4924 status is also displayed for each bookmark like below::
4925
4925
4926 BM1 01234567890a added
4926 BM1 01234567890a added
4927 BM2 deleted
4927 BM2 deleted
4928 BM3 234567890abc advanced
4928 BM3 234567890abc advanced
4929 BM4 34567890abcd diverged
4929 BM4 34567890abcd diverged
4930 BM5 4567890abcde changed
4930 BM5 4567890abcde changed
4931
4931
4932 The action taken when pushing depends on the
4932 The action taken when pushing depends on the
4933 status of each bookmark:
4933 status of each bookmark:
4934
4934
4935 :``added``: push with ``-B`` will create it
4935 :``added``: push with ``-B`` will create it
4936 :``deleted``: push with ``-B`` will delete it
4936 :``deleted``: push with ``-B`` will delete it
4937 :``advanced``: push will update it
4937 :``advanced``: push will update it
4938 :``diverged``: push with ``-B`` will update it
4938 :``diverged``: push with ``-B`` will update it
4939 :``changed``: push with ``-B`` will update it
4939 :``changed``: push with ``-B`` will update it
4940
4940
4941 From the point of view of pushing behavior, bookmarks
4941 From the point of view of pushing behavior, bookmarks
4942 existing only in the remote repository are treated as
4942 existing only in the remote repository are treated as
4943 ``deleted``, even if it is in fact added remotely.
4943 ``deleted``, even if it is in fact added remotely.
4944
4944
4945 Returns 0 if there are outgoing changes, 1 otherwise.
4945 Returns 0 if there are outgoing changes, 1 otherwise.
4946 """
4946 """
4947 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4947 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4948 # style URLs, so don't overwrite dest.
4948 # style URLs, so don't overwrite dest.
4949 path = ui.getpath(dest, default=(b'default-push', b'default'))
4949 path = ui.getpath(dest, default=(b'default-push', b'default'))
4950 if not path:
4950 if not path:
4951 raise error.ConfigError(
4951 raise error.ConfigError(
4952 _(b'default repository not configured!'),
4952 _(b'default repository not configured!'),
4953 hint=_(b"see 'hg help config.paths'"),
4953 hint=_(b"see 'hg help config.paths'"),
4954 )
4954 )
4955
4955
4956 opts = pycompat.byteskwargs(opts)
4956 opts = pycompat.byteskwargs(opts)
4957 if opts.get(b'graph'):
4957 if opts.get(b'graph'):
4958 logcmdutil.checkunsupportedgraphflags([], opts)
4958 logcmdutil.checkunsupportedgraphflags([], opts)
4959 o, other = hg._outgoing(ui, repo, dest, opts)
4959 o, other = hg._outgoing(ui, repo, dest, opts)
4960 if not o:
4960 if not o:
4961 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4961 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4962 return
4962 return
4963
4963
4964 revdag = logcmdutil.graphrevs(repo, o, opts)
4964 revdag = logcmdutil.graphrevs(repo, o, opts)
4965 ui.pager(b'outgoing')
4965 ui.pager(b'outgoing')
4966 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4966 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4967 logcmdutil.displaygraph(
4967 logcmdutil.displaygraph(
4968 ui, repo, revdag, displayer, graphmod.asciiedges
4968 ui, repo, revdag, displayer, graphmod.asciiedges
4969 )
4969 )
4970 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4970 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4971 return 0
4971 return 0
4972
4972
4973 if opts.get(b'bookmarks'):
4973 if opts.get(b'bookmarks'):
4974 dest = path.pushloc or path.loc
4974 dest = path.pushloc or path.loc
4975 other = hg.peer(repo, opts, dest)
4975 other = hg.peer(repo, opts, dest)
4976 try:
4976 try:
4977 if b'bookmarks' not in other.listkeys(b'namespaces'):
4977 if b'bookmarks' not in other.listkeys(b'namespaces'):
4978 ui.warn(_(b"remote doesn't support bookmarks\n"))
4978 ui.warn(_(b"remote doesn't support bookmarks\n"))
4979 return 0
4979 return 0
4980 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4980 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4981 ui.pager(b'outgoing')
4981 ui.pager(b'outgoing')
4982 return bookmarks.outgoing(ui, repo, other)
4982 return bookmarks.outgoing(ui, repo, other)
4983 finally:
4983 finally:
4984 other.close()
4984 other.close()
4985
4985
4986 repo._subtoppath = path.pushloc or path.loc
4986 repo._subtoppath = path.pushloc or path.loc
4987 try:
4987 try:
4988 return hg.outgoing(ui, repo, dest, opts)
4988 return hg.outgoing(ui, repo, dest, opts)
4989 finally:
4989 finally:
4990 del repo._subtoppath
4990 del repo._subtoppath
4991
4991
4992
4992
4993 @command(
4993 @command(
4994 b'parents',
4994 b'parents',
4995 [
4995 [
4996 (
4996 (
4997 b'r',
4997 b'r',
4998 b'rev',
4998 b'rev',
4999 b'',
4999 b'',
5000 _(b'show parents of the specified revision'),
5000 _(b'show parents of the specified revision'),
5001 _(b'REV'),
5001 _(b'REV'),
5002 ),
5002 ),
5003 ]
5003 ]
5004 + templateopts,
5004 + templateopts,
5005 _(b'[-r REV] [FILE]'),
5005 _(b'[-r REV] [FILE]'),
5006 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5006 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
5007 inferrepo=True,
5007 inferrepo=True,
5008 )
5008 )
5009 def parents(ui, repo, file_=None, **opts):
5009 def parents(ui, repo, file_=None, **opts):
5010 """show the parents of the working directory or revision (DEPRECATED)
5010 """show the parents of the working directory or revision (DEPRECATED)
5011
5011
5012 Print the working directory's parent revisions. If a revision is
5012 Print the working directory's parent revisions. If a revision is
5013 given via -r/--rev, the parent of that revision will be printed.
5013 given via -r/--rev, the parent of that revision will be printed.
5014 If a file argument is given, the revision in which the file was
5014 If a file argument is given, the revision in which the file was
5015 last changed (before the working directory revision or the
5015 last changed (before the working directory revision or the
5016 argument to --rev if given) is printed.
5016 argument to --rev if given) is printed.
5017
5017
5018 This command is equivalent to::
5018 This command is equivalent to::
5019
5019
5020 hg log -r "p1()+p2()" or
5020 hg log -r "p1()+p2()" or
5021 hg log -r "p1(REV)+p2(REV)" or
5021 hg log -r "p1(REV)+p2(REV)" or
5022 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5022 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5023 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5023 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5024
5024
5025 See :hg:`summary` and :hg:`help revsets` for related information.
5025 See :hg:`summary` and :hg:`help revsets` for related information.
5026
5026
5027 Returns 0 on success.
5027 Returns 0 on success.
5028 """
5028 """
5029
5029
5030 opts = pycompat.byteskwargs(opts)
5030 opts = pycompat.byteskwargs(opts)
5031 rev = opts.get(b'rev')
5031 rev = opts.get(b'rev')
5032 if rev:
5032 if rev:
5033 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5033 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5034 ctx = scmutil.revsingle(repo, rev, None)
5034 ctx = scmutil.revsingle(repo, rev, None)
5035
5035
5036 if file_:
5036 if file_:
5037 m = scmutil.match(ctx, (file_,), opts)
5037 m = scmutil.match(ctx, (file_,), opts)
5038 if m.anypats() or len(m.files()) != 1:
5038 if m.anypats() or len(m.files()) != 1:
5039 raise error.InputError(_(b'can only specify an explicit filename'))
5039 raise error.InputError(_(b'can only specify an explicit filename'))
5040 file_ = m.files()[0]
5040 file_ = m.files()[0]
5041 filenodes = []
5041 filenodes = []
5042 for cp in ctx.parents():
5042 for cp in ctx.parents():
5043 if not cp:
5043 if not cp:
5044 continue
5044 continue
5045 try:
5045 try:
5046 filenodes.append(cp.filenode(file_))
5046 filenodes.append(cp.filenode(file_))
5047 except error.LookupError:
5047 except error.LookupError:
5048 pass
5048 pass
5049 if not filenodes:
5049 if not filenodes:
5050 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5050 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5051 p = []
5051 p = []
5052 for fn in filenodes:
5052 for fn in filenodes:
5053 fctx = repo.filectx(file_, fileid=fn)
5053 fctx = repo.filectx(file_, fileid=fn)
5054 p.append(fctx.node())
5054 p.append(fctx.node())
5055 else:
5055 else:
5056 p = [cp.node() for cp in ctx.parents()]
5056 p = [cp.node() for cp in ctx.parents()]
5057
5057
5058 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5058 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5059 for n in p:
5059 for n in p:
5060 if n != nullid:
5060 if n != nullid:
5061 displayer.show(repo[n])
5061 displayer.show(repo[n])
5062 displayer.close()
5062 displayer.close()
5063
5063
5064
5064
5065 @command(
5065 @command(
5066 b'paths',
5066 b'paths',
5067 formatteropts,
5067 formatteropts,
5068 _(b'[NAME]'),
5068 _(b'[NAME]'),
5069 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5069 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5070 optionalrepo=True,
5070 optionalrepo=True,
5071 intents={INTENT_READONLY},
5071 intents={INTENT_READONLY},
5072 )
5072 )
5073 def paths(ui, repo, search=None, **opts):
5073 def paths(ui, repo, search=None, **opts):
5074 """show aliases for remote repositories
5074 """show aliases for remote repositories
5075
5075
5076 Show definition of symbolic path name NAME. If no name is given,
5076 Show definition of symbolic path name NAME. If no name is given,
5077 show definition of all available names.
5077 show definition of all available names.
5078
5078
5079 Option -q/--quiet suppresses all output when searching for NAME
5079 Option -q/--quiet suppresses all output when searching for NAME
5080 and shows only the path names when listing all definitions.
5080 and shows only the path names when listing all definitions.
5081
5081
5082 Path names are defined in the [paths] section of your
5082 Path names are defined in the [paths] section of your
5083 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5083 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5084 repository, ``.hg/hgrc`` is used, too.
5084 repository, ``.hg/hgrc`` is used, too.
5085
5085
5086 The path names ``default`` and ``default-push`` have a special
5086 The path names ``default`` and ``default-push`` have a special
5087 meaning. When performing a push or pull operation, they are used
5087 meaning. When performing a push or pull operation, they are used
5088 as fallbacks if no location is specified on the command-line.
5088 as fallbacks if no location is specified on the command-line.
5089 When ``default-push`` is set, it will be used for push and
5089 When ``default-push`` is set, it will be used for push and
5090 ``default`` will be used for pull; otherwise ``default`` is used
5090 ``default`` will be used for pull; otherwise ``default`` is used
5091 as the fallback for both. When cloning a repository, the clone
5091 as the fallback for both. When cloning a repository, the clone
5092 source is written as ``default`` in ``.hg/hgrc``.
5092 source is written as ``default`` in ``.hg/hgrc``.
5093
5093
5094 .. note::
5094 .. note::
5095
5095
5096 ``default`` and ``default-push`` apply to all inbound (e.g.
5096 ``default`` and ``default-push`` apply to all inbound (e.g.
5097 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5097 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5098 and :hg:`bundle`) operations.
5098 and :hg:`bundle`) operations.
5099
5099
5100 See :hg:`help urls` for more information.
5100 See :hg:`help urls` for more information.
5101
5101
5102 .. container:: verbose
5102 .. container:: verbose
5103
5103
5104 Template:
5104 Template:
5105
5105
5106 The following keywords are supported. See also :hg:`help templates`.
5106 The following keywords are supported. See also :hg:`help templates`.
5107
5107
5108 :name: String. Symbolic name of the path alias.
5108 :name: String. Symbolic name of the path alias.
5109 :pushurl: String. URL for push operations.
5109 :pushurl: String. URL for push operations.
5110 :url: String. URL or directory path for the other operations.
5110 :url: String. URL or directory path for the other operations.
5111
5111
5112 Returns 0 on success.
5112 Returns 0 on success.
5113 """
5113 """
5114
5114
5115 opts = pycompat.byteskwargs(opts)
5115 opts = pycompat.byteskwargs(opts)
5116 ui.pager(b'paths')
5116 ui.pager(b'paths')
5117 if search:
5117 if search:
5118 pathitems = [
5118 pathitems = [
5119 (name, path)
5119 (name, path)
5120 for name, path in pycompat.iteritems(ui.paths)
5120 for name, path in pycompat.iteritems(ui.paths)
5121 if name == search
5121 if name == search
5122 ]
5122 ]
5123 else:
5123 else:
5124 pathitems = sorted(pycompat.iteritems(ui.paths))
5124 pathitems = sorted(pycompat.iteritems(ui.paths))
5125
5125
5126 fm = ui.formatter(b'paths', opts)
5126 fm = ui.formatter(b'paths', opts)
5127 if fm.isplain():
5127 if fm.isplain():
5128 hidepassword = util.hidepassword
5128 hidepassword = util.hidepassword
5129 else:
5129 else:
5130 hidepassword = bytes
5130 hidepassword = bytes
5131 if ui.quiet:
5131 if ui.quiet:
5132 namefmt = b'%s\n'
5132 namefmt = b'%s\n'
5133 else:
5133 else:
5134 namefmt = b'%s = '
5134 namefmt = b'%s = '
5135 showsubopts = not search and not ui.quiet
5135 showsubopts = not search and not ui.quiet
5136
5136
5137 for name, path in pathitems:
5137 for name, path in pathitems:
5138 fm.startitem()
5138 fm.startitem()
5139 fm.condwrite(not search, b'name', namefmt, name)
5139 fm.condwrite(not search, b'name', namefmt, name)
5140 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5140 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5141 for subopt, value in sorted(path.suboptions.items()):
5141 for subopt, value in sorted(path.suboptions.items()):
5142 assert subopt not in (b'name', b'url')
5142 assert subopt not in (b'name', b'url')
5143 if showsubopts:
5143 if showsubopts:
5144 fm.plain(b'%s:%s = ' % (name, subopt))
5144 fm.plain(b'%s:%s = ' % (name, subopt))
5145 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5145 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5146
5146
5147 fm.end()
5147 fm.end()
5148
5148
5149 if search and not pathitems:
5149 if search and not pathitems:
5150 if not ui.quiet:
5150 if not ui.quiet:
5151 ui.warn(_(b"not found!\n"))
5151 ui.warn(_(b"not found!\n"))
5152 return 1
5152 return 1
5153 else:
5153 else:
5154 return 0
5154 return 0
5155
5155
5156
5156
5157 @command(
5157 @command(
5158 b'phase',
5158 b'phase',
5159 [
5159 [
5160 (b'p', b'public', False, _(b'set changeset phase to public')),
5160 (b'p', b'public', False, _(b'set changeset phase to public')),
5161 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5161 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5162 (b's', b'secret', False, _(b'set changeset phase to secret')),
5162 (b's', b'secret', False, _(b'set changeset phase to secret')),
5163 (b'f', b'force', False, _(b'allow to move boundary backward')),
5163 (b'f', b'force', False, _(b'allow to move boundary backward')),
5164 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5164 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5165 ],
5165 ],
5166 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5166 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5167 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5167 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5168 )
5168 )
5169 def phase(ui, repo, *revs, **opts):
5169 def phase(ui, repo, *revs, **opts):
5170 """set or show the current phase name
5170 """set or show the current phase name
5171
5171
5172 With no argument, show the phase name of the current revision(s).
5172 With no argument, show the phase name of the current revision(s).
5173
5173
5174 With one of -p/--public, -d/--draft or -s/--secret, change the
5174 With one of -p/--public, -d/--draft or -s/--secret, change the
5175 phase value of the specified revisions.
5175 phase value of the specified revisions.
5176
5176
5177 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5177 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5178 lower phase to a higher phase. Phases are ordered as follows::
5178 lower phase to a higher phase. Phases are ordered as follows::
5179
5179
5180 public < draft < secret
5180 public < draft < secret
5181
5181
5182 Returns 0 on success, 1 if some phases could not be changed.
5182 Returns 0 on success, 1 if some phases could not be changed.
5183
5183
5184 (For more information about the phases concept, see :hg:`help phases`.)
5184 (For more information about the phases concept, see :hg:`help phases`.)
5185 """
5185 """
5186 opts = pycompat.byteskwargs(opts)
5186 opts = pycompat.byteskwargs(opts)
5187 # search for a unique phase argument
5187 # search for a unique phase argument
5188 targetphase = None
5188 targetphase = None
5189 for idx, name in enumerate(phases.cmdphasenames):
5189 for idx, name in enumerate(phases.cmdphasenames):
5190 if opts[name]:
5190 if opts[name]:
5191 if targetphase is not None:
5191 if targetphase is not None:
5192 raise error.InputError(_(b'only one phase can be specified'))
5192 raise error.InputError(_(b'only one phase can be specified'))
5193 targetphase = idx
5193 targetphase = idx
5194
5194
5195 # look for specified revision
5195 # look for specified revision
5196 revs = list(revs)
5196 revs = list(revs)
5197 revs.extend(opts[b'rev'])
5197 revs.extend(opts[b'rev'])
5198 if not revs:
5198 if not revs:
5199 # display both parents as the second parent phase can influence
5199 # display both parents as the second parent phase can influence
5200 # the phase of a merge commit
5200 # the phase of a merge commit
5201 revs = [c.rev() for c in repo[None].parents()]
5201 revs = [c.rev() for c in repo[None].parents()]
5202
5202
5203 revs = scmutil.revrange(repo, revs)
5203 revs = scmutil.revrange(repo, revs)
5204
5204
5205 ret = 0
5205 ret = 0
5206 if targetphase is None:
5206 if targetphase is None:
5207 # display
5207 # display
5208 for r in revs:
5208 for r in revs:
5209 ctx = repo[r]
5209 ctx = repo[r]
5210 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5210 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5211 else:
5211 else:
5212 with repo.lock(), repo.transaction(b"phase") as tr:
5212 with repo.lock(), repo.transaction(b"phase") as tr:
5213 # set phase
5213 # set phase
5214 if not revs:
5214 if not revs:
5215 raise error.InputError(_(b'empty revision set'))
5215 raise error.InputError(_(b'empty revision set'))
5216 nodes = [repo[r].node() for r in revs]
5216 nodes = [repo[r].node() for r in revs]
5217 # moving revision from public to draft may hide them
5217 # moving revision from public to draft may hide them
5218 # We have to check result on an unfiltered repository
5218 # We have to check result on an unfiltered repository
5219 unfi = repo.unfiltered()
5219 unfi = repo.unfiltered()
5220 getphase = unfi._phasecache.phase
5220 getphase = unfi._phasecache.phase
5221 olddata = [getphase(unfi, r) for r in unfi]
5221 olddata = [getphase(unfi, r) for r in unfi]
5222 phases.advanceboundary(repo, tr, targetphase, nodes)
5222 phases.advanceboundary(repo, tr, targetphase, nodes)
5223 if opts[b'force']:
5223 if opts[b'force']:
5224 phases.retractboundary(repo, tr, targetphase, nodes)
5224 phases.retractboundary(repo, tr, targetphase, nodes)
5225 getphase = unfi._phasecache.phase
5225 getphase = unfi._phasecache.phase
5226 newdata = [getphase(unfi, r) for r in unfi]
5226 newdata = [getphase(unfi, r) for r in unfi]
5227 changes = sum(newdata[r] != olddata[r] for r in unfi)
5227 changes = sum(newdata[r] != olddata[r] for r in unfi)
5228 cl = unfi.changelog
5228 cl = unfi.changelog
5229 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5229 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5230 if rejected:
5230 if rejected:
5231 ui.warn(
5231 ui.warn(
5232 _(
5232 _(
5233 b'cannot move %i changesets to a higher '
5233 b'cannot move %i changesets to a higher '
5234 b'phase, use --force\n'
5234 b'phase, use --force\n'
5235 )
5235 )
5236 % len(rejected)
5236 % len(rejected)
5237 )
5237 )
5238 ret = 1
5238 ret = 1
5239 if changes:
5239 if changes:
5240 msg = _(b'phase changed for %i changesets\n') % changes
5240 msg = _(b'phase changed for %i changesets\n') % changes
5241 if ret:
5241 if ret:
5242 ui.status(msg)
5242 ui.status(msg)
5243 else:
5243 else:
5244 ui.note(msg)
5244 ui.note(msg)
5245 else:
5245 else:
5246 ui.warn(_(b'no phases changed\n'))
5246 ui.warn(_(b'no phases changed\n'))
5247 return ret
5247 return ret
5248
5248
5249
5249
5250 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5250 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5251 """Run after a changegroup has been added via pull/unbundle
5251 """Run after a changegroup has been added via pull/unbundle
5252
5252
5253 This takes arguments below:
5253 This takes arguments below:
5254
5254
5255 :modheads: change of heads by pull/unbundle
5255 :modheads: change of heads by pull/unbundle
5256 :optupdate: updating working directory is needed or not
5256 :optupdate: updating working directory is needed or not
5257 :checkout: update destination revision (or None to default destination)
5257 :checkout: update destination revision (or None to default destination)
5258 :brev: a name, which might be a bookmark to be activated after updating
5258 :brev: a name, which might be a bookmark to be activated after updating
5259
5259
5260 return True if update raise any conflict, False otherwise.
5260 return True if update raise any conflict, False otherwise.
5261 """
5261 """
5262 if modheads == 0:
5262 if modheads == 0:
5263 return False
5263 return False
5264 if optupdate:
5264 if optupdate:
5265 try:
5265 try:
5266 return hg.updatetotally(ui, repo, checkout, brev)
5266 return hg.updatetotally(ui, repo, checkout, brev)
5267 except error.UpdateAbort as inst:
5267 except error.UpdateAbort as inst:
5268 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5268 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5269 hint = inst.hint
5269 hint = inst.hint
5270 raise error.UpdateAbort(msg, hint=hint)
5270 raise error.UpdateAbort(msg, hint=hint)
5271 if modheads is not None and modheads > 1:
5271 if modheads is not None and modheads > 1:
5272 currentbranchheads = len(repo.branchheads())
5272 currentbranchheads = len(repo.branchheads())
5273 if currentbranchheads == modheads:
5273 if currentbranchheads == modheads:
5274 ui.status(
5274 ui.status(
5275 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5275 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5276 )
5276 )
5277 elif currentbranchheads > 1:
5277 elif currentbranchheads > 1:
5278 ui.status(
5278 ui.status(
5279 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5279 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5280 )
5280 )
5281 else:
5281 else:
5282 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5282 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5283 elif not ui.configbool(b'commands', b'update.requiredest'):
5283 elif not ui.configbool(b'commands', b'update.requiredest'):
5284 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5284 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5285 return False
5285 return False
5286
5286
5287
5287
5288 @command(
5288 @command(
5289 b'pull',
5289 b'pull',
5290 [
5290 [
5291 (
5291 (
5292 b'u',
5292 b'u',
5293 b'update',
5293 b'update',
5294 None,
5294 None,
5295 _(b'update to new branch head if new descendants were pulled'),
5295 _(b'update to new branch head if new descendants were pulled'),
5296 ),
5296 ),
5297 (
5297 (
5298 b'f',
5298 b'f',
5299 b'force',
5299 b'force',
5300 None,
5300 None,
5301 _(b'run even when remote repository is unrelated'),
5301 _(b'run even when remote repository is unrelated'),
5302 ),
5302 ),
5303 (
5303 (
5304 b'',
5304 b'',
5305 b'confirm',
5305 b'confirm',
5306 None,
5306 None,
5307 _(b'confirm pull before applying changes'),
5307 _(b'confirm pull before applying changes'),
5308 ),
5308 ),
5309 (
5309 (
5310 b'r',
5310 b'r',
5311 b'rev',
5311 b'rev',
5312 [],
5312 [],
5313 _(b'a remote changeset intended to be added'),
5313 _(b'a remote changeset intended to be added'),
5314 _(b'REV'),
5314 _(b'REV'),
5315 ),
5315 ),
5316 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5316 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5317 (
5317 (
5318 b'b',
5318 b'b',
5319 b'branch',
5319 b'branch',
5320 [],
5320 [],
5321 _(b'a specific branch you would like to pull'),
5321 _(b'a specific branch you would like to pull'),
5322 _(b'BRANCH'),
5322 _(b'BRANCH'),
5323 ),
5323 ),
5324 ]
5324 ]
5325 + remoteopts,
5325 + remoteopts,
5326 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5326 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'),
5327 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5327 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5328 helpbasic=True,
5328 helpbasic=True,
5329 )
5329 )
5330 def pull(ui, repo, source=b"default", **opts):
5330 def pull(ui, repo, *sources, **opts):
5331 """pull changes from the specified source
5331 """pull changes from the specified source
5332
5332
5333 Pull changes from a remote repository to a local one.
5333 Pull changes from a remote repository to a local one.
5334
5334
5335 This finds all changes from the repository at the specified path
5335 This finds all changes from the repository at the specified path
5336 or URL and adds them to a local repository (the current one unless
5336 or URL and adds them to a local repository (the current one unless
5337 -R is specified). By default, this does not update the copy of the
5337 -R is specified). By default, this does not update the copy of the
5338 project in the working directory.
5338 project in the working directory.
5339
5339
5340 When cloning from servers that support it, Mercurial may fetch
5340 When cloning from servers that support it, Mercurial may fetch
5341 pre-generated data. When this is done, hooks operating on incoming
5341 pre-generated data. When this is done, hooks operating on incoming
5342 changesets and changegroups may fire more than once, once for each
5342 changesets and changegroups may fire more than once, once for each
5343 pre-generated bundle and as well as for any additional remaining
5343 pre-generated bundle and as well as for any additional remaining
5344 data. See :hg:`help -e clonebundles` for more.
5344 data. See :hg:`help -e clonebundles` for more.
5345
5345
5346 Use :hg:`incoming` if you want to see what would have been added
5346 Use :hg:`incoming` if you want to see what would have been added
5347 by a pull at the time you issued this command. If you then decide
5347 by a pull at the time you issued this command. If you then decide
5348 to add those changes to the repository, you should use :hg:`pull
5348 to add those changes to the repository, you should use :hg:`pull
5349 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5349 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5350
5350
5351 If SOURCE is omitted, the 'default' path will be used.
5351 If SOURCE is omitted, the 'default' path will be used.
5352 See :hg:`help urls` for more information.
5352 See :hg:`help urls` for more information.
5353
5353
5354 If multiple sources are specified, they will be pulled sequentially as if
5355 the command was run multiple time. If --update is specify and the command
5356 will stop at the first failed --update.
5357
5354 Specifying bookmark as ``.`` is equivalent to specifying the active
5358 Specifying bookmark as ``.`` is equivalent to specifying the active
5355 bookmark's name.
5359 bookmark's name.
5356
5360
5357 Returns 0 on success, 1 if an update had unresolved files.
5361 Returns 0 on success, 1 if an update had unresolved files.
5358 """
5362 """
5359
5363
5360 opts = pycompat.byteskwargs(opts)
5364 opts = pycompat.byteskwargs(opts)
5361 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5365 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5362 b'update'
5366 b'update'
5363 ):
5367 ):
5364 msg = _(b'update destination required by configuration')
5368 msg = _(b'update destination required by configuration')
5365 hint = _(b'use hg pull followed by hg update DEST')
5369 hint = _(b'use hg pull followed by hg update DEST')
5366 raise error.InputError(msg, hint=hint)
5370 raise error.InputError(msg, hint=hint)
5367
5371
5368 if True:
5372 if not sources:
5373 sources = [b'default']
5374 for source in sources:
5369 source, branches = hg.parseurl(
5375 source, branches = hg.parseurl(
5370 ui.expandpath(source), opts.get(b'branch')
5376 ui.expandpath(source), opts.get(b'branch')
5371 )
5377 )
5372 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5378 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5373 ui.flush()
5379 ui.flush()
5374 other = hg.peer(repo, opts, source)
5380 other = hg.peer(repo, opts, source)
5375 update_conflict = None
5381 update_conflict = None
5376 try:
5382 try:
5377 revs, checkout = hg.addbranchrevs(
5383 revs, checkout = hg.addbranchrevs(
5378 repo, other, branches, opts.get(b'rev')
5384 repo, other, branches, opts.get(b'rev')
5379 )
5385 )
5380
5386
5381 pullopargs = {}
5387 pullopargs = {}
5382
5388
5383 nodes = None
5389 nodes = None
5384 if opts.get(b'bookmark') or revs:
5390 if opts.get(b'bookmark') or revs:
5385 # The list of bookmark used here is the same used to actually update
5391 # The list of bookmark used here is the same used to actually update
5386 # the bookmark names, to avoid the race from issue 4689 and we do
5392 # the bookmark names, to avoid the race from issue 4689 and we do
5387 # all lookup and bookmark queries in one go so they see the same
5393 # all lookup and bookmark queries in one go so they see the same
5388 # version of the server state (issue 4700).
5394 # version of the server state (issue 4700).
5389 nodes = []
5395 nodes = []
5390 fnodes = []
5396 fnodes = []
5391 revs = revs or []
5397 revs = revs or []
5392 if revs and not other.capable(b'lookup'):
5398 if revs and not other.capable(b'lookup'):
5393 err = _(
5399 err = _(
5394 b"other repository doesn't support revision lookup, "
5400 b"other repository doesn't support revision lookup, "
5395 b"so a rev cannot be specified."
5401 b"so a rev cannot be specified."
5396 )
5402 )
5397 raise error.Abort(err)
5403 raise error.Abort(err)
5398 with other.commandexecutor() as e:
5404 with other.commandexecutor() as e:
5399 fremotebookmarks = e.callcommand(
5405 fremotebookmarks = e.callcommand(
5400 b'listkeys', {b'namespace': b'bookmarks'}
5406 b'listkeys', {b'namespace': b'bookmarks'}
5401 )
5407 )
5402 for r in revs:
5408 for r in revs:
5403 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5409 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5404 remotebookmarks = fremotebookmarks.result()
5410 remotebookmarks = fremotebookmarks.result()
5405 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5411 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5406 pullopargs[b'remotebookmarks'] = remotebookmarks
5412 pullopargs[b'remotebookmarks'] = remotebookmarks
5407 for b in opts.get(b'bookmark', []):
5413 for b in opts.get(b'bookmark', []):
5408 b = repo._bookmarks.expandname(b)
5414 b = repo._bookmarks.expandname(b)
5409 if b not in remotebookmarks:
5415 if b not in remotebookmarks:
5410 raise error.InputError(
5416 raise error.InputError(
5411 _(b'remote bookmark %s not found!') % b
5417 _(b'remote bookmark %s not found!') % b
5412 )
5418 )
5413 nodes.append(remotebookmarks[b])
5419 nodes.append(remotebookmarks[b])
5414 for i, rev in enumerate(revs):
5420 for i, rev in enumerate(revs):
5415 node = fnodes[i].result()
5421 node = fnodes[i].result()
5416 nodes.append(node)
5422 nodes.append(node)
5417 if rev == checkout:
5423 if rev == checkout:
5418 checkout = node
5424 checkout = node
5419
5425
5420 wlock = util.nullcontextmanager()
5426 wlock = util.nullcontextmanager()
5421 if opts.get(b'update'):
5427 if opts.get(b'update'):
5422 wlock = repo.wlock()
5428 wlock = repo.wlock()
5423 with wlock:
5429 with wlock:
5424 pullopargs.update(opts.get(b'opargs', {}))
5430 pullopargs.update(opts.get(b'opargs', {}))
5425 modheads = exchange.pull(
5431 modheads = exchange.pull(
5426 repo,
5432 repo,
5427 other,
5433 other,
5428 heads=nodes,
5434 heads=nodes,
5429 force=opts.get(b'force'),
5435 force=opts.get(b'force'),
5430 bookmarks=opts.get(b'bookmark', ()),
5436 bookmarks=opts.get(b'bookmark', ()),
5431 opargs=pullopargs,
5437 opargs=pullopargs,
5432 confirm=opts.get(b'confirm'),
5438 confirm=opts.get(b'confirm'),
5433 ).cgresult
5439 ).cgresult
5434
5440
5435 # brev is a name, which might be a bookmark to be activated at
5441 # brev is a name, which might be a bookmark to be activated at
5436 # the end of the update. In other words, it is an explicit
5442 # the end of the update. In other words, it is an explicit
5437 # destination of the update
5443 # destination of the update
5438 brev = None
5444 brev = None
5439
5445
5440 if checkout:
5446 if checkout:
5441 checkout = repo.unfiltered().changelog.rev(checkout)
5447 checkout = repo.unfiltered().changelog.rev(checkout)
5442
5448
5443 # order below depends on implementation of
5449 # order below depends on implementation of
5444 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5450 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5445 # because 'checkout' is determined without it.
5451 # because 'checkout' is determined without it.
5446 if opts.get(b'rev'):
5452 if opts.get(b'rev'):
5447 brev = opts[b'rev'][0]
5453 brev = opts[b'rev'][0]
5448 elif opts.get(b'branch'):
5454 elif opts.get(b'branch'):
5449 brev = opts[b'branch'][0]
5455 brev = opts[b'branch'][0]
5450 else:
5456 else:
5451 brev = branches[0]
5457 brev = branches[0]
5452 repo._subtoppath = source
5458 repo._subtoppath = source
5453 try:
5459 try:
5454 update_conflict = postincoming(
5460 update_conflict = postincoming(
5455 ui, repo, modheads, opts.get(b'update'), checkout, brev
5461 ui, repo, modheads, opts.get(b'update'), checkout, brev
5456 )
5462 )
5457 except error.FilteredRepoLookupError as exc:
5463 except error.FilteredRepoLookupError as exc:
5458 msg = _(b'cannot update to target: %s') % exc.args[0]
5464 msg = _(b'cannot update to target: %s') % exc.args[0]
5459 exc.args = (msg,) + exc.args[1:]
5465 exc.args = (msg,) + exc.args[1:]
5460 raise
5466 raise
5461 finally:
5467 finally:
5462 del repo._subtoppath
5468 del repo._subtoppath
5463
5469
5464 finally:
5470 finally:
5465 other.close()
5471 other.close()
5472 # skip the remaining pull source if they are some conflict.
5473 if update_conflict:
5474 break
5466 if update_conflict:
5475 if update_conflict:
5467 return 1
5476 return 1
5468 else:
5477 else:
5469 return 0
5478 return 0
5470
5479
5471
5480
5472 @command(
5481 @command(
5473 b'purge|clean',
5482 b'purge|clean',
5474 [
5483 [
5475 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5484 (b'a', b'abort-on-err', None, _(b'abort if an error occurs')),
5476 (b'', b'all', None, _(b'purge ignored files too')),
5485 (b'', b'all', None, _(b'purge ignored files too')),
5477 (b'i', b'ignored', None, _(b'purge only ignored files')),
5486 (b'i', b'ignored', None, _(b'purge only ignored files')),
5478 (b'', b'dirs', None, _(b'purge empty directories')),
5487 (b'', b'dirs', None, _(b'purge empty directories')),
5479 (b'', b'files', None, _(b'purge files')),
5488 (b'', b'files', None, _(b'purge files')),
5480 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5489 (b'p', b'print', None, _(b'print filenames instead of deleting them')),
5481 (
5490 (
5482 b'0',
5491 b'0',
5483 b'print0',
5492 b'print0',
5484 None,
5493 None,
5485 _(
5494 _(
5486 b'end filenames with NUL, for use with xargs'
5495 b'end filenames with NUL, for use with xargs'
5487 b' (implies -p/--print)'
5496 b' (implies -p/--print)'
5488 ),
5497 ),
5489 ),
5498 ),
5490 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5499 (b'', b'confirm', None, _(b'ask before permanently deleting files')),
5491 ]
5500 ]
5492 + cmdutil.walkopts,
5501 + cmdutil.walkopts,
5493 _(b'hg purge [OPTION]... [DIR]...'),
5502 _(b'hg purge [OPTION]... [DIR]...'),
5494 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5503 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5495 )
5504 )
5496 def purge(ui, repo, *dirs, **opts):
5505 def purge(ui, repo, *dirs, **opts):
5497 """removes files not tracked by Mercurial
5506 """removes files not tracked by Mercurial
5498
5507
5499 Delete files not known to Mercurial. This is useful to test local
5508 Delete files not known to Mercurial. This is useful to test local
5500 and uncommitted changes in an otherwise-clean source tree.
5509 and uncommitted changes in an otherwise-clean source tree.
5501
5510
5502 This means that purge will delete the following by default:
5511 This means that purge will delete the following by default:
5503
5512
5504 - Unknown files: files marked with "?" by :hg:`status`
5513 - Unknown files: files marked with "?" by :hg:`status`
5505 - Empty directories: in fact Mercurial ignores directories unless
5514 - Empty directories: in fact Mercurial ignores directories unless
5506 they contain files under source control management
5515 they contain files under source control management
5507
5516
5508 But it will leave untouched:
5517 But it will leave untouched:
5509
5518
5510 - Modified and unmodified tracked files
5519 - Modified and unmodified tracked files
5511 - Ignored files (unless -i or --all is specified)
5520 - Ignored files (unless -i or --all is specified)
5512 - New files added to the repository (with :hg:`add`)
5521 - New files added to the repository (with :hg:`add`)
5513
5522
5514 The --files and --dirs options can be used to direct purge to delete
5523 The --files and --dirs options can be used to direct purge to delete
5515 only files, only directories, or both. If neither option is given,
5524 only files, only directories, or both. If neither option is given,
5516 both will be deleted.
5525 both will be deleted.
5517
5526
5518 If directories are given on the command line, only files in these
5527 If directories are given on the command line, only files in these
5519 directories are considered.
5528 directories are considered.
5520
5529
5521 Be careful with purge, as you could irreversibly delete some files
5530 Be careful with purge, as you could irreversibly delete some files
5522 you forgot to add to the repository. If you only want to print the
5531 you forgot to add to the repository. If you only want to print the
5523 list of files that this program would delete, use the --print
5532 list of files that this program would delete, use the --print
5524 option.
5533 option.
5525 """
5534 """
5526 opts = pycompat.byteskwargs(opts)
5535 opts = pycompat.byteskwargs(opts)
5527 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5536 cmdutil.check_at_most_one_arg(opts, b'all', b'ignored')
5528
5537
5529 act = not opts.get(b'print')
5538 act = not opts.get(b'print')
5530 eol = b'\n'
5539 eol = b'\n'
5531 if opts.get(b'print0'):
5540 if opts.get(b'print0'):
5532 eol = b'\0'
5541 eol = b'\0'
5533 act = False # --print0 implies --print
5542 act = False # --print0 implies --print
5534 if opts.get(b'all', False):
5543 if opts.get(b'all', False):
5535 ignored = True
5544 ignored = True
5536 unknown = True
5545 unknown = True
5537 else:
5546 else:
5538 ignored = opts.get(b'ignored', False)
5547 ignored = opts.get(b'ignored', False)
5539 unknown = not ignored
5548 unknown = not ignored
5540
5549
5541 removefiles = opts.get(b'files')
5550 removefiles = opts.get(b'files')
5542 removedirs = opts.get(b'dirs')
5551 removedirs = opts.get(b'dirs')
5543 confirm = opts.get(b'confirm')
5552 confirm = opts.get(b'confirm')
5544 if confirm is None:
5553 if confirm is None:
5545 try:
5554 try:
5546 extensions.find(b'purge')
5555 extensions.find(b'purge')
5547 confirm = False
5556 confirm = False
5548 except KeyError:
5557 except KeyError:
5549 confirm = True
5558 confirm = True
5550
5559
5551 if not removefiles and not removedirs:
5560 if not removefiles and not removedirs:
5552 removefiles = True
5561 removefiles = True
5553 removedirs = True
5562 removedirs = True
5554
5563
5555 match = scmutil.match(repo[None], dirs, opts)
5564 match = scmutil.match(repo[None], dirs, opts)
5556
5565
5557 paths = mergemod.purge(
5566 paths = mergemod.purge(
5558 repo,
5567 repo,
5559 match,
5568 match,
5560 unknown=unknown,
5569 unknown=unknown,
5561 ignored=ignored,
5570 ignored=ignored,
5562 removeemptydirs=removedirs,
5571 removeemptydirs=removedirs,
5563 removefiles=removefiles,
5572 removefiles=removefiles,
5564 abortonerror=opts.get(b'abort_on_err'),
5573 abortonerror=opts.get(b'abort_on_err'),
5565 noop=not act,
5574 noop=not act,
5566 confirm=confirm,
5575 confirm=confirm,
5567 )
5576 )
5568
5577
5569 for path in paths:
5578 for path in paths:
5570 if not act:
5579 if not act:
5571 ui.write(b'%s%s' % (path, eol))
5580 ui.write(b'%s%s' % (path, eol))
5572
5581
5573
5582
5574 @command(
5583 @command(
5575 b'push',
5584 b'push',
5576 [
5585 [
5577 (b'f', b'force', None, _(b'force push')),
5586 (b'f', b'force', None, _(b'force push')),
5578 (
5587 (
5579 b'r',
5588 b'r',
5580 b'rev',
5589 b'rev',
5581 [],
5590 [],
5582 _(b'a changeset intended to be included in the destination'),
5591 _(b'a changeset intended to be included in the destination'),
5583 _(b'REV'),
5592 _(b'REV'),
5584 ),
5593 ),
5585 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5594 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5586 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5595 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5587 (
5596 (
5588 b'b',
5597 b'b',
5589 b'branch',
5598 b'branch',
5590 [],
5599 [],
5591 _(b'a specific branch you would like to push'),
5600 _(b'a specific branch you would like to push'),
5592 _(b'BRANCH'),
5601 _(b'BRANCH'),
5593 ),
5602 ),
5594 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5603 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5595 (
5604 (
5596 b'',
5605 b'',
5597 b'pushvars',
5606 b'pushvars',
5598 [],
5607 [],
5599 _(b'variables that can be sent to server (ADVANCED)'),
5608 _(b'variables that can be sent to server (ADVANCED)'),
5600 ),
5609 ),
5601 (
5610 (
5602 b'',
5611 b'',
5603 b'publish',
5612 b'publish',
5604 False,
5613 False,
5605 _(b'push the changeset as public (EXPERIMENTAL)'),
5614 _(b'push the changeset as public (EXPERIMENTAL)'),
5606 ),
5615 ),
5607 ]
5616 ]
5608 + remoteopts,
5617 + remoteopts,
5609 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5618 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5610 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5619 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5611 helpbasic=True,
5620 helpbasic=True,
5612 )
5621 )
5613 def push(ui, repo, dest=None, **opts):
5622 def push(ui, repo, dest=None, **opts):
5614 """push changes to the specified destination
5623 """push changes to the specified destination
5615
5624
5616 Push changesets from the local repository to the specified
5625 Push changesets from the local repository to the specified
5617 destination.
5626 destination.
5618
5627
5619 This operation is symmetrical to pull: it is identical to a pull
5628 This operation is symmetrical to pull: it is identical to a pull
5620 in the destination repository from the current one.
5629 in the destination repository from the current one.
5621
5630
5622 By default, push will not allow creation of new heads at the
5631 By default, push will not allow creation of new heads at the
5623 destination, since multiple heads would make it unclear which head
5632 destination, since multiple heads would make it unclear which head
5624 to use. In this situation, it is recommended to pull and merge
5633 to use. In this situation, it is recommended to pull and merge
5625 before pushing.
5634 before pushing.
5626
5635
5627 Use --new-branch if you want to allow push to create a new named
5636 Use --new-branch if you want to allow push to create a new named
5628 branch that is not present at the destination. This allows you to
5637 branch that is not present at the destination. This allows you to
5629 only create a new branch without forcing other changes.
5638 only create a new branch without forcing other changes.
5630
5639
5631 .. note::
5640 .. note::
5632
5641
5633 Extra care should be taken with the -f/--force option,
5642 Extra care should be taken with the -f/--force option,
5634 which will push all new heads on all branches, an action which will
5643 which will push all new heads on all branches, an action which will
5635 almost always cause confusion for collaborators.
5644 almost always cause confusion for collaborators.
5636
5645
5637 If -r/--rev is used, the specified revision and all its ancestors
5646 If -r/--rev is used, the specified revision and all its ancestors
5638 will be pushed to the remote repository.
5647 will be pushed to the remote repository.
5639
5648
5640 If -B/--bookmark is used, the specified bookmarked revision, its
5649 If -B/--bookmark is used, the specified bookmarked revision, its
5641 ancestors, and the bookmark will be pushed to the remote
5650 ancestors, and the bookmark will be pushed to the remote
5642 repository. Specifying ``.`` is equivalent to specifying the active
5651 repository. Specifying ``.`` is equivalent to specifying the active
5643 bookmark's name. Use the --all-bookmarks option for pushing all
5652 bookmark's name. Use the --all-bookmarks option for pushing all
5644 current bookmarks.
5653 current bookmarks.
5645
5654
5646 Please see :hg:`help urls` for important details about ``ssh://``
5655 Please see :hg:`help urls` for important details about ``ssh://``
5647 URLs. If DESTINATION is omitted, a default path will be used.
5656 URLs. If DESTINATION is omitted, a default path will be used.
5648
5657
5649 .. container:: verbose
5658 .. container:: verbose
5650
5659
5651 The --pushvars option sends strings to the server that become
5660 The --pushvars option sends strings to the server that become
5652 environment variables prepended with ``HG_USERVAR_``. For example,
5661 environment variables prepended with ``HG_USERVAR_``. For example,
5653 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5662 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5654 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5663 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5655
5664
5656 pushvars can provide for user-overridable hooks as well as set debug
5665 pushvars can provide for user-overridable hooks as well as set debug
5657 levels. One example is having a hook that blocks commits containing
5666 levels. One example is having a hook that blocks commits containing
5658 conflict markers, but enables the user to override the hook if the file
5667 conflict markers, but enables the user to override the hook if the file
5659 is using conflict markers for testing purposes or the file format has
5668 is using conflict markers for testing purposes or the file format has
5660 strings that look like conflict markers.
5669 strings that look like conflict markers.
5661
5670
5662 By default, servers will ignore `--pushvars`. To enable it add the
5671 By default, servers will ignore `--pushvars`. To enable it add the
5663 following to your configuration file::
5672 following to your configuration file::
5664
5673
5665 [push]
5674 [push]
5666 pushvars.server = true
5675 pushvars.server = true
5667
5676
5668 Returns 0 if push was successful, 1 if nothing to push.
5677 Returns 0 if push was successful, 1 if nothing to push.
5669 """
5678 """
5670
5679
5671 opts = pycompat.byteskwargs(opts)
5680 opts = pycompat.byteskwargs(opts)
5672
5681
5673 if opts.get(b'all_bookmarks'):
5682 if opts.get(b'all_bookmarks'):
5674 cmdutil.check_incompatible_arguments(
5683 cmdutil.check_incompatible_arguments(
5675 opts,
5684 opts,
5676 b'all_bookmarks',
5685 b'all_bookmarks',
5677 [b'bookmark', b'rev'],
5686 [b'bookmark', b'rev'],
5678 )
5687 )
5679 opts[b'bookmark'] = list(repo._bookmarks)
5688 opts[b'bookmark'] = list(repo._bookmarks)
5680
5689
5681 if opts.get(b'bookmark'):
5690 if opts.get(b'bookmark'):
5682 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5691 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5683 for b in opts[b'bookmark']:
5692 for b in opts[b'bookmark']:
5684 # translate -B options to -r so changesets get pushed
5693 # translate -B options to -r so changesets get pushed
5685 b = repo._bookmarks.expandname(b)
5694 b = repo._bookmarks.expandname(b)
5686 if b in repo._bookmarks:
5695 if b in repo._bookmarks:
5687 opts.setdefault(b'rev', []).append(b)
5696 opts.setdefault(b'rev', []).append(b)
5688 else:
5697 else:
5689 # if we try to push a deleted bookmark, translate it to null
5698 # if we try to push a deleted bookmark, translate it to null
5690 # this lets simultaneous -r, -b options continue working
5699 # this lets simultaneous -r, -b options continue working
5691 opts.setdefault(b'rev', []).append(b"null")
5700 opts.setdefault(b'rev', []).append(b"null")
5692
5701
5693 path = ui.getpath(dest, default=(b'default-push', b'default'))
5702 path = ui.getpath(dest, default=(b'default-push', b'default'))
5694 if not path:
5703 if not path:
5695 raise error.ConfigError(
5704 raise error.ConfigError(
5696 _(b'default repository not configured!'),
5705 _(b'default repository not configured!'),
5697 hint=_(b"see 'hg help config.paths'"),
5706 hint=_(b"see 'hg help config.paths'"),
5698 )
5707 )
5699 dest = path.pushloc or path.loc
5708 dest = path.pushloc or path.loc
5700 branches = (path.branch, opts.get(b'branch') or [])
5709 branches = (path.branch, opts.get(b'branch') or [])
5701 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5710 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5702 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5711 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5703 other = hg.peer(repo, opts, dest)
5712 other = hg.peer(repo, opts, dest)
5704
5713
5705 try:
5714 try:
5706 if revs:
5715 if revs:
5707 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5716 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5708 if not revs:
5717 if not revs:
5709 raise error.InputError(
5718 raise error.InputError(
5710 _(b"specified revisions evaluate to an empty set"),
5719 _(b"specified revisions evaluate to an empty set"),
5711 hint=_(b"use different revision arguments"),
5720 hint=_(b"use different revision arguments"),
5712 )
5721 )
5713 elif path.pushrev:
5722 elif path.pushrev:
5714 # It doesn't make any sense to specify ancestor revisions. So limit
5723 # It doesn't make any sense to specify ancestor revisions. So limit
5715 # to DAG heads to make discovery simpler.
5724 # to DAG heads to make discovery simpler.
5716 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5725 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5717 revs = scmutil.revrange(repo, [expr])
5726 revs = scmutil.revrange(repo, [expr])
5718 revs = [repo[rev].node() for rev in revs]
5727 revs = [repo[rev].node() for rev in revs]
5719 if not revs:
5728 if not revs:
5720 raise error.InputError(
5729 raise error.InputError(
5721 _(b'default push revset for path evaluates to an empty set')
5730 _(b'default push revset for path evaluates to an empty set')
5722 )
5731 )
5723 elif ui.configbool(b'commands', b'push.require-revs'):
5732 elif ui.configbool(b'commands', b'push.require-revs'):
5724 raise error.InputError(
5733 raise error.InputError(
5725 _(b'no revisions specified to push'),
5734 _(b'no revisions specified to push'),
5726 hint=_(b'did you mean "hg push -r ."?'),
5735 hint=_(b'did you mean "hg push -r ."?'),
5727 )
5736 )
5728
5737
5729 repo._subtoppath = dest
5738 repo._subtoppath = dest
5730 try:
5739 try:
5731 # push subrepos depth-first for coherent ordering
5740 # push subrepos depth-first for coherent ordering
5732 c = repo[b'.']
5741 c = repo[b'.']
5733 subs = c.substate # only repos that are committed
5742 subs = c.substate # only repos that are committed
5734 for s in sorted(subs):
5743 for s in sorted(subs):
5735 result = c.sub(s).push(opts)
5744 result = c.sub(s).push(opts)
5736 if result == 0:
5745 if result == 0:
5737 return not result
5746 return not result
5738 finally:
5747 finally:
5739 del repo._subtoppath
5748 del repo._subtoppath
5740
5749
5741 opargs = dict(
5750 opargs = dict(
5742 opts.get(b'opargs', {})
5751 opts.get(b'opargs', {})
5743 ) # copy opargs since we may mutate it
5752 ) # copy opargs since we may mutate it
5744 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5753 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5745
5754
5746 pushop = exchange.push(
5755 pushop = exchange.push(
5747 repo,
5756 repo,
5748 other,
5757 other,
5749 opts.get(b'force'),
5758 opts.get(b'force'),
5750 revs=revs,
5759 revs=revs,
5751 newbranch=opts.get(b'new_branch'),
5760 newbranch=opts.get(b'new_branch'),
5752 bookmarks=opts.get(b'bookmark', ()),
5761 bookmarks=opts.get(b'bookmark', ()),
5753 publish=opts.get(b'publish'),
5762 publish=opts.get(b'publish'),
5754 opargs=opargs,
5763 opargs=opargs,
5755 )
5764 )
5756
5765
5757 result = not pushop.cgresult
5766 result = not pushop.cgresult
5758
5767
5759 if pushop.bkresult is not None:
5768 if pushop.bkresult is not None:
5760 if pushop.bkresult == 2:
5769 if pushop.bkresult == 2:
5761 result = 2
5770 result = 2
5762 elif not result and pushop.bkresult:
5771 elif not result and pushop.bkresult:
5763 result = 2
5772 result = 2
5764 finally:
5773 finally:
5765 other.close()
5774 other.close()
5766 return result
5775 return result
5767
5776
5768
5777
5769 @command(
5778 @command(
5770 b'recover',
5779 b'recover',
5771 [
5780 [
5772 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5781 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5773 ],
5782 ],
5774 helpcategory=command.CATEGORY_MAINTENANCE,
5783 helpcategory=command.CATEGORY_MAINTENANCE,
5775 )
5784 )
5776 def recover(ui, repo, **opts):
5785 def recover(ui, repo, **opts):
5777 """roll back an interrupted transaction
5786 """roll back an interrupted transaction
5778
5787
5779 Recover from an interrupted commit or pull.
5788 Recover from an interrupted commit or pull.
5780
5789
5781 This command tries to fix the repository status after an
5790 This command tries to fix the repository status after an
5782 interrupted operation. It should only be necessary when Mercurial
5791 interrupted operation. It should only be necessary when Mercurial
5783 suggests it.
5792 suggests it.
5784
5793
5785 Returns 0 if successful, 1 if nothing to recover or verify fails.
5794 Returns 0 if successful, 1 if nothing to recover or verify fails.
5786 """
5795 """
5787 ret = repo.recover()
5796 ret = repo.recover()
5788 if ret:
5797 if ret:
5789 if opts['verify']:
5798 if opts['verify']:
5790 return hg.verify(repo)
5799 return hg.verify(repo)
5791 else:
5800 else:
5792 msg = _(
5801 msg = _(
5793 b"(verify step skipped, run `hg verify` to check your "
5802 b"(verify step skipped, run `hg verify` to check your "
5794 b"repository content)\n"
5803 b"repository content)\n"
5795 )
5804 )
5796 ui.warn(msg)
5805 ui.warn(msg)
5797 return 0
5806 return 0
5798 return 1
5807 return 1
5799
5808
5800
5809
5801 @command(
5810 @command(
5802 b'remove|rm',
5811 b'remove|rm',
5803 [
5812 [
5804 (b'A', b'after', None, _(b'record delete for missing files')),
5813 (b'A', b'after', None, _(b'record delete for missing files')),
5805 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5814 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5806 ]
5815 ]
5807 + subrepoopts
5816 + subrepoopts
5808 + walkopts
5817 + walkopts
5809 + dryrunopts,
5818 + dryrunopts,
5810 _(b'[OPTION]... FILE...'),
5819 _(b'[OPTION]... FILE...'),
5811 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5820 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5812 helpbasic=True,
5821 helpbasic=True,
5813 inferrepo=True,
5822 inferrepo=True,
5814 )
5823 )
5815 def remove(ui, repo, *pats, **opts):
5824 def remove(ui, repo, *pats, **opts):
5816 """remove the specified files on the next commit
5825 """remove the specified files on the next commit
5817
5826
5818 Schedule the indicated files for removal from the current branch.
5827 Schedule the indicated files for removal from the current branch.
5819
5828
5820 This command schedules the files to be removed at the next commit.
5829 This command schedules the files to be removed at the next commit.
5821 To undo a remove before that, see :hg:`revert`. To undo added
5830 To undo a remove before that, see :hg:`revert`. To undo added
5822 files, see :hg:`forget`.
5831 files, see :hg:`forget`.
5823
5832
5824 .. container:: verbose
5833 .. container:: verbose
5825
5834
5826 -A/--after can be used to remove only files that have already
5835 -A/--after can be used to remove only files that have already
5827 been deleted, -f/--force can be used to force deletion, and -Af
5836 been deleted, -f/--force can be used to force deletion, and -Af
5828 can be used to remove files from the next revision without
5837 can be used to remove files from the next revision without
5829 deleting them from the working directory.
5838 deleting them from the working directory.
5830
5839
5831 The following table details the behavior of remove for different
5840 The following table details the behavior of remove for different
5832 file states (columns) and option combinations (rows). The file
5841 file states (columns) and option combinations (rows). The file
5833 states are Added [A], Clean [C], Modified [M] and Missing [!]
5842 states are Added [A], Clean [C], Modified [M] and Missing [!]
5834 (as reported by :hg:`status`). The actions are Warn, Remove
5843 (as reported by :hg:`status`). The actions are Warn, Remove
5835 (from branch) and Delete (from disk):
5844 (from branch) and Delete (from disk):
5836
5845
5837 ========= == == == ==
5846 ========= == == == ==
5838 opt/state A C M !
5847 opt/state A C M !
5839 ========= == == == ==
5848 ========= == == == ==
5840 none W RD W R
5849 none W RD W R
5841 -f R RD RD R
5850 -f R RD RD R
5842 -A W W W R
5851 -A W W W R
5843 -Af R R R R
5852 -Af R R R R
5844 ========= == == == ==
5853 ========= == == == ==
5845
5854
5846 .. note::
5855 .. note::
5847
5856
5848 :hg:`remove` never deletes files in Added [A] state from the
5857 :hg:`remove` never deletes files in Added [A] state from the
5849 working directory, not even if ``--force`` is specified.
5858 working directory, not even if ``--force`` is specified.
5850
5859
5851 Returns 0 on success, 1 if any warnings encountered.
5860 Returns 0 on success, 1 if any warnings encountered.
5852 """
5861 """
5853
5862
5854 opts = pycompat.byteskwargs(opts)
5863 opts = pycompat.byteskwargs(opts)
5855 after, force = opts.get(b'after'), opts.get(b'force')
5864 after, force = opts.get(b'after'), opts.get(b'force')
5856 dryrun = opts.get(b'dry_run')
5865 dryrun = opts.get(b'dry_run')
5857 if not pats and not after:
5866 if not pats and not after:
5858 raise error.InputError(_(b'no files specified'))
5867 raise error.InputError(_(b'no files specified'))
5859
5868
5860 m = scmutil.match(repo[None], pats, opts)
5869 m = scmutil.match(repo[None], pats, opts)
5861 subrepos = opts.get(b'subrepos')
5870 subrepos = opts.get(b'subrepos')
5862 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5871 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5863 return cmdutil.remove(
5872 return cmdutil.remove(
5864 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5873 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5865 )
5874 )
5866
5875
5867
5876
5868 @command(
5877 @command(
5869 b'rename|move|mv',
5878 b'rename|move|mv',
5870 [
5879 [
5871 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5880 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5872 (
5881 (
5873 b'',
5882 b'',
5874 b'at-rev',
5883 b'at-rev',
5875 b'',
5884 b'',
5876 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5885 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5877 _(b'REV'),
5886 _(b'REV'),
5878 ),
5887 ),
5879 (
5888 (
5880 b'f',
5889 b'f',
5881 b'force',
5890 b'force',
5882 None,
5891 None,
5883 _(b'forcibly move over an existing managed file'),
5892 _(b'forcibly move over an existing managed file'),
5884 ),
5893 ),
5885 ]
5894 ]
5886 + walkopts
5895 + walkopts
5887 + dryrunopts,
5896 + dryrunopts,
5888 _(b'[OPTION]... SOURCE... DEST'),
5897 _(b'[OPTION]... SOURCE... DEST'),
5889 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5898 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5890 )
5899 )
5891 def rename(ui, repo, *pats, **opts):
5900 def rename(ui, repo, *pats, **opts):
5892 """rename files; equivalent of copy + remove
5901 """rename files; equivalent of copy + remove
5893
5902
5894 Mark dest as copies of sources; mark sources for deletion. If dest
5903 Mark dest as copies of sources; mark sources for deletion. If dest
5895 is a directory, copies are put in that directory. If dest is a
5904 is a directory, copies are put in that directory. If dest is a
5896 file, there can only be one source.
5905 file, there can only be one source.
5897
5906
5898 By default, this command copies the contents of files as they
5907 By default, this command copies the contents of files as they
5899 exist in the working directory. If invoked with -A/--after, the
5908 exist in the working directory. If invoked with -A/--after, the
5900 operation is recorded, but no copying is performed.
5909 operation is recorded, but no copying is performed.
5901
5910
5902 This command takes effect at the next commit. To undo a rename
5911 This command takes effect at the next commit. To undo a rename
5903 before that, see :hg:`revert`.
5912 before that, see :hg:`revert`.
5904
5913
5905 Returns 0 on success, 1 if errors are encountered.
5914 Returns 0 on success, 1 if errors are encountered.
5906 """
5915 """
5907 opts = pycompat.byteskwargs(opts)
5916 opts = pycompat.byteskwargs(opts)
5908 with repo.wlock():
5917 with repo.wlock():
5909 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5918 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5910
5919
5911
5920
5912 @command(
5921 @command(
5913 b'resolve',
5922 b'resolve',
5914 [
5923 [
5915 (b'a', b'all', None, _(b'select all unresolved files')),
5924 (b'a', b'all', None, _(b'select all unresolved files')),
5916 (b'l', b'list', None, _(b'list state of files needing merge')),
5925 (b'l', b'list', None, _(b'list state of files needing merge')),
5917 (b'm', b'mark', None, _(b'mark files as resolved')),
5926 (b'm', b'mark', None, _(b'mark files as resolved')),
5918 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5927 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5919 (b'n', b'no-status', None, _(b'hide status prefix')),
5928 (b'n', b'no-status', None, _(b'hide status prefix')),
5920 (b'', b're-merge', None, _(b're-merge files')),
5929 (b'', b're-merge', None, _(b're-merge files')),
5921 ]
5930 ]
5922 + mergetoolopts
5931 + mergetoolopts
5923 + walkopts
5932 + walkopts
5924 + formatteropts,
5933 + formatteropts,
5925 _(b'[OPTION]... [FILE]...'),
5934 _(b'[OPTION]... [FILE]...'),
5926 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5935 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5927 inferrepo=True,
5936 inferrepo=True,
5928 )
5937 )
5929 def resolve(ui, repo, *pats, **opts):
5938 def resolve(ui, repo, *pats, **opts):
5930 """redo merges or set/view the merge status of files
5939 """redo merges or set/view the merge status of files
5931
5940
5932 Merges with unresolved conflicts are often the result of
5941 Merges with unresolved conflicts are often the result of
5933 non-interactive merging using the ``internal:merge`` configuration
5942 non-interactive merging using the ``internal:merge`` configuration
5934 setting, or a command-line merge tool like ``diff3``. The resolve
5943 setting, or a command-line merge tool like ``diff3``. The resolve
5935 command is used to manage the files involved in a merge, after
5944 command is used to manage the files involved in a merge, after
5936 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5945 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5937 working directory must have two parents). See :hg:`help
5946 working directory must have two parents). See :hg:`help
5938 merge-tools` for information on configuring merge tools.
5947 merge-tools` for information on configuring merge tools.
5939
5948
5940 The resolve command can be used in the following ways:
5949 The resolve command can be used in the following ways:
5941
5950
5942 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5951 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5943 the specified files, discarding any previous merge attempts. Re-merging
5952 the specified files, discarding any previous merge attempts. Re-merging
5944 is not performed for files already marked as resolved. Use ``--all/-a``
5953 is not performed for files already marked as resolved. Use ``--all/-a``
5945 to select all unresolved files. ``--tool`` can be used to specify
5954 to select all unresolved files. ``--tool`` can be used to specify
5946 the merge tool used for the given files. It overrides the HGMERGE
5955 the merge tool used for the given files. It overrides the HGMERGE
5947 environment variable and your configuration files. Previous file
5956 environment variable and your configuration files. Previous file
5948 contents are saved with a ``.orig`` suffix.
5957 contents are saved with a ``.orig`` suffix.
5949
5958
5950 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5959 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5951 (e.g. after having manually fixed-up the files). The default is
5960 (e.g. after having manually fixed-up the files). The default is
5952 to mark all unresolved files.
5961 to mark all unresolved files.
5953
5962
5954 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5963 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5955 default is to mark all resolved files.
5964 default is to mark all resolved files.
5956
5965
5957 - :hg:`resolve -l`: list files which had or still have conflicts.
5966 - :hg:`resolve -l`: list files which had or still have conflicts.
5958 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5967 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5959 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5968 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5960 the list. See :hg:`help filesets` for details.
5969 the list. See :hg:`help filesets` for details.
5961
5970
5962 .. note::
5971 .. note::
5963
5972
5964 Mercurial will not let you commit files with unresolved merge
5973 Mercurial will not let you commit files with unresolved merge
5965 conflicts. You must use :hg:`resolve -m ...` before you can
5974 conflicts. You must use :hg:`resolve -m ...` before you can
5966 commit after a conflicting merge.
5975 commit after a conflicting merge.
5967
5976
5968 .. container:: verbose
5977 .. container:: verbose
5969
5978
5970 Template:
5979 Template:
5971
5980
5972 The following keywords are supported in addition to the common template
5981 The following keywords are supported in addition to the common template
5973 keywords and functions. See also :hg:`help templates`.
5982 keywords and functions. See also :hg:`help templates`.
5974
5983
5975 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5984 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5976 :path: String. Repository-absolute path of the file.
5985 :path: String. Repository-absolute path of the file.
5977
5986
5978 Returns 0 on success, 1 if any files fail a resolve attempt.
5987 Returns 0 on success, 1 if any files fail a resolve attempt.
5979 """
5988 """
5980
5989
5981 opts = pycompat.byteskwargs(opts)
5990 opts = pycompat.byteskwargs(opts)
5982 confirm = ui.configbool(b'commands', b'resolve.confirm')
5991 confirm = ui.configbool(b'commands', b'resolve.confirm')
5983 flaglist = b'all mark unmark list no_status re_merge'.split()
5992 flaglist = b'all mark unmark list no_status re_merge'.split()
5984 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5993 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5985
5994
5986 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5995 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5987 if actioncount > 1:
5996 if actioncount > 1:
5988 raise error.InputError(_(b"too many actions specified"))
5997 raise error.InputError(_(b"too many actions specified"))
5989 elif actioncount == 0 and ui.configbool(
5998 elif actioncount == 0 and ui.configbool(
5990 b'commands', b'resolve.explicit-re-merge'
5999 b'commands', b'resolve.explicit-re-merge'
5991 ):
6000 ):
5992 hint = _(b'use --mark, --unmark, --list or --re-merge')
6001 hint = _(b'use --mark, --unmark, --list or --re-merge')
5993 raise error.InputError(_(b'no action specified'), hint=hint)
6002 raise error.InputError(_(b'no action specified'), hint=hint)
5994 if pats and all:
6003 if pats and all:
5995 raise error.InputError(_(b"can't specify --all and patterns"))
6004 raise error.InputError(_(b"can't specify --all and patterns"))
5996 if not (all or pats or show or mark or unmark):
6005 if not (all or pats or show or mark or unmark):
5997 raise error.InputError(
6006 raise error.InputError(
5998 _(b'no files or directories specified'),
6007 _(b'no files or directories specified'),
5999 hint=b'use --all to re-merge all unresolved files',
6008 hint=b'use --all to re-merge all unresolved files',
6000 )
6009 )
6001
6010
6002 if confirm:
6011 if confirm:
6003 if all:
6012 if all:
6004 if ui.promptchoice(
6013 if ui.promptchoice(
6005 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6014 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
6006 ):
6015 ):
6007 raise error.CanceledError(_(b'user quit'))
6016 raise error.CanceledError(_(b'user quit'))
6008 if mark and not pats:
6017 if mark and not pats:
6009 if ui.promptchoice(
6018 if ui.promptchoice(
6010 _(
6019 _(
6011 b'mark all unresolved files as resolved (yn)?'
6020 b'mark all unresolved files as resolved (yn)?'
6012 b'$$ &Yes $$ &No'
6021 b'$$ &Yes $$ &No'
6013 )
6022 )
6014 ):
6023 ):
6015 raise error.CanceledError(_(b'user quit'))
6024 raise error.CanceledError(_(b'user quit'))
6016 if unmark and not pats:
6025 if unmark and not pats:
6017 if ui.promptchoice(
6026 if ui.promptchoice(
6018 _(
6027 _(
6019 b'mark all resolved files as unresolved (yn)?'
6028 b'mark all resolved files as unresolved (yn)?'
6020 b'$$ &Yes $$ &No'
6029 b'$$ &Yes $$ &No'
6021 )
6030 )
6022 ):
6031 ):
6023 raise error.CanceledError(_(b'user quit'))
6032 raise error.CanceledError(_(b'user quit'))
6024
6033
6025 uipathfn = scmutil.getuipathfn(repo)
6034 uipathfn = scmutil.getuipathfn(repo)
6026
6035
6027 if show:
6036 if show:
6028 ui.pager(b'resolve')
6037 ui.pager(b'resolve')
6029 fm = ui.formatter(b'resolve', opts)
6038 fm = ui.formatter(b'resolve', opts)
6030 ms = mergestatemod.mergestate.read(repo)
6039 ms = mergestatemod.mergestate.read(repo)
6031 wctx = repo[None]
6040 wctx = repo[None]
6032 m = scmutil.match(wctx, pats, opts)
6041 m = scmutil.match(wctx, pats, opts)
6033
6042
6034 # Labels and keys based on merge state. Unresolved path conflicts show
6043 # Labels and keys based on merge state. Unresolved path conflicts show
6035 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6044 # as 'P'. Resolved path conflicts show as 'R', the same as normal
6036 # resolved conflicts.
6045 # resolved conflicts.
6037 mergestateinfo = {
6046 mergestateinfo = {
6038 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6047 mergestatemod.MERGE_RECORD_UNRESOLVED: (
6039 b'resolve.unresolved',
6048 b'resolve.unresolved',
6040 b'U',
6049 b'U',
6041 ),
6050 ),
6042 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6051 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
6043 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6052 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
6044 b'resolve.unresolved',
6053 b'resolve.unresolved',
6045 b'P',
6054 b'P',
6046 ),
6055 ),
6047 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6056 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
6048 b'resolve.resolved',
6057 b'resolve.resolved',
6049 b'R',
6058 b'R',
6050 ),
6059 ),
6051 }
6060 }
6052
6061
6053 for f in ms:
6062 for f in ms:
6054 if not m(f):
6063 if not m(f):
6055 continue
6064 continue
6056
6065
6057 label, key = mergestateinfo[ms[f]]
6066 label, key = mergestateinfo[ms[f]]
6058 fm.startitem()
6067 fm.startitem()
6059 fm.context(ctx=wctx)
6068 fm.context(ctx=wctx)
6060 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6069 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
6061 fm.data(path=f)
6070 fm.data(path=f)
6062 fm.plain(b'%s\n' % uipathfn(f), label=label)
6071 fm.plain(b'%s\n' % uipathfn(f), label=label)
6063 fm.end()
6072 fm.end()
6064 return 0
6073 return 0
6065
6074
6066 with repo.wlock():
6075 with repo.wlock():
6067 ms = mergestatemod.mergestate.read(repo)
6076 ms = mergestatemod.mergestate.read(repo)
6068
6077
6069 if not (ms.active() or repo.dirstate.p2() != nullid):
6078 if not (ms.active() or repo.dirstate.p2() != nullid):
6070 raise error.StateError(
6079 raise error.StateError(
6071 _(b'resolve command not applicable when not merging')
6080 _(b'resolve command not applicable when not merging')
6072 )
6081 )
6073
6082
6074 wctx = repo[None]
6083 wctx = repo[None]
6075 m = scmutil.match(wctx, pats, opts)
6084 m = scmutil.match(wctx, pats, opts)
6076 ret = 0
6085 ret = 0
6077 didwork = False
6086 didwork = False
6078
6087
6079 tocomplete = []
6088 tocomplete = []
6080 hasconflictmarkers = []
6089 hasconflictmarkers = []
6081 if mark:
6090 if mark:
6082 markcheck = ui.config(b'commands', b'resolve.mark-check')
6091 markcheck = ui.config(b'commands', b'resolve.mark-check')
6083 if markcheck not in [b'warn', b'abort']:
6092 if markcheck not in [b'warn', b'abort']:
6084 # Treat all invalid / unrecognized values as 'none'.
6093 # Treat all invalid / unrecognized values as 'none'.
6085 markcheck = False
6094 markcheck = False
6086 for f in ms:
6095 for f in ms:
6087 if not m(f):
6096 if not m(f):
6088 continue
6097 continue
6089
6098
6090 didwork = True
6099 didwork = True
6091
6100
6092 # path conflicts must be resolved manually
6101 # path conflicts must be resolved manually
6093 if ms[f] in (
6102 if ms[f] in (
6094 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6103 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
6095 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6104 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
6096 ):
6105 ):
6097 if mark:
6106 if mark:
6098 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6107 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
6099 elif unmark:
6108 elif unmark:
6100 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6109 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
6101 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6110 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
6102 ui.warn(
6111 ui.warn(
6103 _(b'%s: path conflict must be resolved manually\n')
6112 _(b'%s: path conflict must be resolved manually\n')
6104 % uipathfn(f)
6113 % uipathfn(f)
6105 )
6114 )
6106 continue
6115 continue
6107
6116
6108 if mark:
6117 if mark:
6109 if markcheck:
6118 if markcheck:
6110 fdata = repo.wvfs.tryread(f)
6119 fdata = repo.wvfs.tryread(f)
6111 if (
6120 if (
6112 filemerge.hasconflictmarkers(fdata)
6121 filemerge.hasconflictmarkers(fdata)
6113 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6122 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
6114 ):
6123 ):
6115 hasconflictmarkers.append(f)
6124 hasconflictmarkers.append(f)
6116 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6125 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
6117 elif unmark:
6126 elif unmark:
6118 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6127 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
6119 else:
6128 else:
6120 # backup pre-resolve (merge uses .orig for its own purposes)
6129 # backup pre-resolve (merge uses .orig for its own purposes)
6121 a = repo.wjoin(f)
6130 a = repo.wjoin(f)
6122 try:
6131 try:
6123 util.copyfile(a, a + b".resolve")
6132 util.copyfile(a, a + b".resolve")
6124 except (IOError, OSError) as inst:
6133 except (IOError, OSError) as inst:
6125 if inst.errno != errno.ENOENT:
6134 if inst.errno != errno.ENOENT:
6126 raise
6135 raise
6127
6136
6128 try:
6137 try:
6129 # preresolve file
6138 # preresolve file
6130 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6139 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6131 with ui.configoverride(overrides, b'resolve'):
6140 with ui.configoverride(overrides, b'resolve'):
6132 complete, r = ms.preresolve(f, wctx)
6141 complete, r = ms.preresolve(f, wctx)
6133 if not complete:
6142 if not complete:
6134 tocomplete.append(f)
6143 tocomplete.append(f)
6135 elif r:
6144 elif r:
6136 ret = 1
6145 ret = 1
6137 finally:
6146 finally:
6138 ms.commit()
6147 ms.commit()
6139
6148
6140 # replace filemerge's .orig file with our resolve file, but only
6149 # replace filemerge's .orig file with our resolve file, but only
6141 # for merges that are complete
6150 # for merges that are complete
6142 if complete:
6151 if complete:
6143 try:
6152 try:
6144 util.rename(
6153 util.rename(
6145 a + b".resolve", scmutil.backuppath(ui, repo, f)
6154 a + b".resolve", scmutil.backuppath(ui, repo, f)
6146 )
6155 )
6147 except OSError as inst:
6156 except OSError as inst:
6148 if inst.errno != errno.ENOENT:
6157 if inst.errno != errno.ENOENT:
6149 raise
6158 raise
6150
6159
6151 if hasconflictmarkers:
6160 if hasconflictmarkers:
6152 ui.warn(
6161 ui.warn(
6153 _(
6162 _(
6154 b'warning: the following files still have conflict '
6163 b'warning: the following files still have conflict '
6155 b'markers:\n'
6164 b'markers:\n'
6156 )
6165 )
6157 + b''.join(
6166 + b''.join(
6158 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6167 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6159 )
6168 )
6160 )
6169 )
6161 if markcheck == b'abort' and not all and not pats:
6170 if markcheck == b'abort' and not all and not pats:
6162 raise error.StateError(
6171 raise error.StateError(
6163 _(b'conflict markers detected'),
6172 _(b'conflict markers detected'),
6164 hint=_(b'use --all to mark anyway'),
6173 hint=_(b'use --all to mark anyway'),
6165 )
6174 )
6166
6175
6167 for f in tocomplete:
6176 for f in tocomplete:
6168 try:
6177 try:
6169 # resolve file
6178 # resolve file
6170 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6179 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6171 with ui.configoverride(overrides, b'resolve'):
6180 with ui.configoverride(overrides, b'resolve'):
6172 r = ms.resolve(f, wctx)
6181 r = ms.resolve(f, wctx)
6173 if r:
6182 if r:
6174 ret = 1
6183 ret = 1
6175 finally:
6184 finally:
6176 ms.commit()
6185 ms.commit()
6177
6186
6178 # replace filemerge's .orig file with our resolve file
6187 # replace filemerge's .orig file with our resolve file
6179 a = repo.wjoin(f)
6188 a = repo.wjoin(f)
6180 try:
6189 try:
6181 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6190 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6182 except OSError as inst:
6191 except OSError as inst:
6183 if inst.errno != errno.ENOENT:
6192 if inst.errno != errno.ENOENT:
6184 raise
6193 raise
6185
6194
6186 ms.commit()
6195 ms.commit()
6187 branchmerge = repo.dirstate.p2() != nullid
6196 branchmerge = repo.dirstate.p2() != nullid
6188 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6197 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6189
6198
6190 if not didwork and pats:
6199 if not didwork and pats:
6191 hint = None
6200 hint = None
6192 if not any([p for p in pats if p.find(b':') >= 0]):
6201 if not any([p for p in pats if p.find(b':') >= 0]):
6193 pats = [b'path:%s' % p for p in pats]
6202 pats = [b'path:%s' % p for p in pats]
6194 m = scmutil.match(wctx, pats, opts)
6203 m = scmutil.match(wctx, pats, opts)
6195 for f in ms:
6204 for f in ms:
6196 if not m(f):
6205 if not m(f):
6197 continue
6206 continue
6198
6207
6199 def flag(o):
6208 def flag(o):
6200 if o == b're_merge':
6209 if o == b're_merge':
6201 return b'--re-merge '
6210 return b'--re-merge '
6202 return b'-%s ' % o[0:1]
6211 return b'-%s ' % o[0:1]
6203
6212
6204 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6213 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6205 hint = _(b"(try: hg resolve %s%s)\n") % (
6214 hint = _(b"(try: hg resolve %s%s)\n") % (
6206 flags,
6215 flags,
6207 b' '.join(pats),
6216 b' '.join(pats),
6208 )
6217 )
6209 break
6218 break
6210 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6219 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6211 if hint:
6220 if hint:
6212 ui.warn(hint)
6221 ui.warn(hint)
6213
6222
6214 unresolvedf = ms.unresolvedcount()
6223 unresolvedf = ms.unresolvedcount()
6215 if not unresolvedf:
6224 if not unresolvedf:
6216 ui.status(_(b'(no more unresolved files)\n'))
6225 ui.status(_(b'(no more unresolved files)\n'))
6217 cmdutil.checkafterresolved(repo)
6226 cmdutil.checkafterresolved(repo)
6218
6227
6219 return ret
6228 return ret
6220
6229
6221
6230
6222 @command(
6231 @command(
6223 b'revert',
6232 b'revert',
6224 [
6233 [
6225 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6234 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6226 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6235 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6227 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6236 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6228 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6237 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6229 (b'i', b'interactive', None, _(b'interactively select the changes')),
6238 (b'i', b'interactive', None, _(b'interactively select the changes')),
6230 ]
6239 ]
6231 + walkopts
6240 + walkopts
6232 + dryrunopts,
6241 + dryrunopts,
6233 _(b'[OPTION]... [-r REV] [NAME]...'),
6242 _(b'[OPTION]... [-r REV] [NAME]...'),
6234 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6243 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6235 )
6244 )
6236 def revert(ui, repo, *pats, **opts):
6245 def revert(ui, repo, *pats, **opts):
6237 """restore files to their checkout state
6246 """restore files to their checkout state
6238
6247
6239 .. note::
6248 .. note::
6240
6249
6241 To check out earlier revisions, you should use :hg:`update REV`.
6250 To check out earlier revisions, you should use :hg:`update REV`.
6242 To cancel an uncommitted merge (and lose your changes),
6251 To cancel an uncommitted merge (and lose your changes),
6243 use :hg:`merge --abort`.
6252 use :hg:`merge --abort`.
6244
6253
6245 With no revision specified, revert the specified files or directories
6254 With no revision specified, revert the specified files or directories
6246 to the contents they had in the parent of the working directory.
6255 to the contents they had in the parent of the working directory.
6247 This restores the contents of files to an unmodified
6256 This restores the contents of files to an unmodified
6248 state and unschedules adds, removes, copies, and renames. If the
6257 state and unschedules adds, removes, copies, and renames. If the
6249 working directory has two parents, you must explicitly specify a
6258 working directory has two parents, you must explicitly specify a
6250 revision.
6259 revision.
6251
6260
6252 Using the -r/--rev or -d/--date options, revert the given files or
6261 Using the -r/--rev or -d/--date options, revert the given files or
6253 directories to their states as of a specific revision. Because
6262 directories to their states as of a specific revision. Because
6254 revert does not change the working directory parents, this will
6263 revert does not change the working directory parents, this will
6255 cause these files to appear modified. This can be helpful to "back
6264 cause these files to appear modified. This can be helpful to "back
6256 out" some or all of an earlier change. See :hg:`backout` for a
6265 out" some or all of an earlier change. See :hg:`backout` for a
6257 related method.
6266 related method.
6258
6267
6259 Modified files are saved with a .orig suffix before reverting.
6268 Modified files are saved with a .orig suffix before reverting.
6260 To disable these backups, use --no-backup. It is possible to store
6269 To disable these backups, use --no-backup. It is possible to store
6261 the backup files in a custom directory relative to the root of the
6270 the backup files in a custom directory relative to the root of the
6262 repository by setting the ``ui.origbackuppath`` configuration
6271 repository by setting the ``ui.origbackuppath`` configuration
6263 option.
6272 option.
6264
6273
6265 See :hg:`help dates` for a list of formats valid for -d/--date.
6274 See :hg:`help dates` for a list of formats valid for -d/--date.
6266
6275
6267 See :hg:`help backout` for a way to reverse the effect of an
6276 See :hg:`help backout` for a way to reverse the effect of an
6268 earlier changeset.
6277 earlier changeset.
6269
6278
6270 Returns 0 on success.
6279 Returns 0 on success.
6271 """
6280 """
6272
6281
6273 opts = pycompat.byteskwargs(opts)
6282 opts = pycompat.byteskwargs(opts)
6274 if opts.get(b"date"):
6283 if opts.get(b"date"):
6275 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6284 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6276 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6285 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6277
6286
6278 parent, p2 = repo.dirstate.parents()
6287 parent, p2 = repo.dirstate.parents()
6279 if not opts.get(b'rev') and p2 != nullid:
6288 if not opts.get(b'rev') and p2 != nullid:
6280 # revert after merge is a trap for new users (issue2915)
6289 # revert after merge is a trap for new users (issue2915)
6281 raise error.InputError(
6290 raise error.InputError(
6282 _(b'uncommitted merge with no revision specified'),
6291 _(b'uncommitted merge with no revision specified'),
6283 hint=_(b"use 'hg update' or see 'hg help revert'"),
6292 hint=_(b"use 'hg update' or see 'hg help revert'"),
6284 )
6293 )
6285
6294
6286 rev = opts.get(b'rev')
6295 rev = opts.get(b'rev')
6287 if rev:
6296 if rev:
6288 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6297 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6289 ctx = scmutil.revsingle(repo, rev)
6298 ctx = scmutil.revsingle(repo, rev)
6290
6299
6291 if not (
6300 if not (
6292 pats
6301 pats
6293 or opts.get(b'include')
6302 or opts.get(b'include')
6294 or opts.get(b'exclude')
6303 or opts.get(b'exclude')
6295 or opts.get(b'all')
6304 or opts.get(b'all')
6296 or opts.get(b'interactive')
6305 or opts.get(b'interactive')
6297 ):
6306 ):
6298 msg = _(b"no files or directories specified")
6307 msg = _(b"no files or directories specified")
6299 if p2 != nullid:
6308 if p2 != nullid:
6300 hint = _(
6309 hint = _(
6301 b"uncommitted merge, use --all to discard all changes,"
6310 b"uncommitted merge, use --all to discard all changes,"
6302 b" or 'hg update -C .' to abort the merge"
6311 b" or 'hg update -C .' to abort the merge"
6303 )
6312 )
6304 raise error.InputError(msg, hint=hint)
6313 raise error.InputError(msg, hint=hint)
6305 dirty = any(repo.status())
6314 dirty = any(repo.status())
6306 node = ctx.node()
6315 node = ctx.node()
6307 if node != parent:
6316 if node != parent:
6308 if dirty:
6317 if dirty:
6309 hint = (
6318 hint = (
6310 _(
6319 _(
6311 b"uncommitted changes, use --all to discard all"
6320 b"uncommitted changes, use --all to discard all"
6312 b" changes, or 'hg update %d' to update"
6321 b" changes, or 'hg update %d' to update"
6313 )
6322 )
6314 % ctx.rev()
6323 % ctx.rev()
6315 )
6324 )
6316 else:
6325 else:
6317 hint = (
6326 hint = (
6318 _(
6327 _(
6319 b"use --all to revert all files,"
6328 b"use --all to revert all files,"
6320 b" or 'hg update %d' to update"
6329 b" or 'hg update %d' to update"
6321 )
6330 )
6322 % ctx.rev()
6331 % ctx.rev()
6323 )
6332 )
6324 elif dirty:
6333 elif dirty:
6325 hint = _(b"uncommitted changes, use --all to discard all changes")
6334 hint = _(b"uncommitted changes, use --all to discard all changes")
6326 else:
6335 else:
6327 hint = _(b"use --all to revert all files")
6336 hint = _(b"use --all to revert all files")
6328 raise error.InputError(msg, hint=hint)
6337 raise error.InputError(msg, hint=hint)
6329
6338
6330 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6339 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6331
6340
6332
6341
6333 @command(
6342 @command(
6334 b'rollback',
6343 b'rollback',
6335 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6344 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6336 helpcategory=command.CATEGORY_MAINTENANCE,
6345 helpcategory=command.CATEGORY_MAINTENANCE,
6337 )
6346 )
6338 def rollback(ui, repo, **opts):
6347 def rollback(ui, repo, **opts):
6339 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6348 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6340
6349
6341 Please use :hg:`commit --amend` instead of rollback to correct
6350 Please use :hg:`commit --amend` instead of rollback to correct
6342 mistakes in the last commit.
6351 mistakes in the last commit.
6343
6352
6344 This command should be used with care. There is only one level of
6353 This command should be used with care. There is only one level of
6345 rollback, and there is no way to undo a rollback. It will also
6354 rollback, and there is no way to undo a rollback. It will also
6346 restore the dirstate at the time of the last transaction, losing
6355 restore the dirstate at the time of the last transaction, losing
6347 any dirstate changes since that time. This command does not alter
6356 any dirstate changes since that time. This command does not alter
6348 the working directory.
6357 the working directory.
6349
6358
6350 Transactions are used to encapsulate the effects of all commands
6359 Transactions are used to encapsulate the effects of all commands
6351 that create new changesets or propagate existing changesets into a
6360 that create new changesets or propagate existing changesets into a
6352 repository.
6361 repository.
6353
6362
6354 .. container:: verbose
6363 .. container:: verbose
6355
6364
6356 For example, the following commands are transactional, and their
6365 For example, the following commands are transactional, and their
6357 effects can be rolled back:
6366 effects can be rolled back:
6358
6367
6359 - commit
6368 - commit
6360 - import
6369 - import
6361 - pull
6370 - pull
6362 - push (with this repository as the destination)
6371 - push (with this repository as the destination)
6363 - unbundle
6372 - unbundle
6364
6373
6365 To avoid permanent data loss, rollback will refuse to rollback a
6374 To avoid permanent data loss, rollback will refuse to rollback a
6366 commit transaction if it isn't checked out. Use --force to
6375 commit transaction if it isn't checked out. Use --force to
6367 override this protection.
6376 override this protection.
6368
6377
6369 The rollback command can be entirely disabled by setting the
6378 The rollback command can be entirely disabled by setting the
6370 ``ui.rollback`` configuration setting to false. If you're here
6379 ``ui.rollback`` configuration setting to false. If you're here
6371 because you want to use rollback and it's disabled, you can
6380 because you want to use rollback and it's disabled, you can
6372 re-enable the command by setting ``ui.rollback`` to true.
6381 re-enable the command by setting ``ui.rollback`` to true.
6373
6382
6374 This command is not intended for use on public repositories. Once
6383 This command is not intended for use on public repositories. Once
6375 changes are visible for pull by other users, rolling a transaction
6384 changes are visible for pull by other users, rolling a transaction
6376 back locally is ineffective (someone else may already have pulled
6385 back locally is ineffective (someone else may already have pulled
6377 the changes). Furthermore, a race is possible with readers of the
6386 the changes). Furthermore, a race is possible with readers of the
6378 repository; for example an in-progress pull from the repository
6387 repository; for example an in-progress pull from the repository
6379 may fail if a rollback is performed.
6388 may fail if a rollback is performed.
6380
6389
6381 Returns 0 on success, 1 if no rollback data is available.
6390 Returns 0 on success, 1 if no rollback data is available.
6382 """
6391 """
6383 if not ui.configbool(b'ui', b'rollback'):
6392 if not ui.configbool(b'ui', b'rollback'):
6384 raise error.Abort(
6393 raise error.Abort(
6385 _(b'rollback is disabled because it is unsafe'),
6394 _(b'rollback is disabled because it is unsafe'),
6386 hint=b'see `hg help -v rollback` for information',
6395 hint=b'see `hg help -v rollback` for information',
6387 )
6396 )
6388 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6397 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6389
6398
6390
6399
6391 @command(
6400 @command(
6392 b'root',
6401 b'root',
6393 [] + formatteropts,
6402 [] + formatteropts,
6394 intents={INTENT_READONLY},
6403 intents={INTENT_READONLY},
6395 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6404 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6396 )
6405 )
6397 def root(ui, repo, **opts):
6406 def root(ui, repo, **opts):
6398 """print the root (top) of the current working directory
6407 """print the root (top) of the current working directory
6399
6408
6400 Print the root directory of the current repository.
6409 Print the root directory of the current repository.
6401
6410
6402 .. container:: verbose
6411 .. container:: verbose
6403
6412
6404 Template:
6413 Template:
6405
6414
6406 The following keywords are supported in addition to the common template
6415 The following keywords are supported in addition to the common template
6407 keywords and functions. See also :hg:`help templates`.
6416 keywords and functions. See also :hg:`help templates`.
6408
6417
6409 :hgpath: String. Path to the .hg directory.
6418 :hgpath: String. Path to the .hg directory.
6410 :storepath: String. Path to the directory holding versioned data.
6419 :storepath: String. Path to the directory holding versioned data.
6411
6420
6412 Returns 0 on success.
6421 Returns 0 on success.
6413 """
6422 """
6414 opts = pycompat.byteskwargs(opts)
6423 opts = pycompat.byteskwargs(opts)
6415 with ui.formatter(b'root', opts) as fm:
6424 with ui.formatter(b'root', opts) as fm:
6416 fm.startitem()
6425 fm.startitem()
6417 fm.write(b'reporoot', b'%s\n', repo.root)
6426 fm.write(b'reporoot', b'%s\n', repo.root)
6418 fm.data(hgpath=repo.path, storepath=repo.spath)
6427 fm.data(hgpath=repo.path, storepath=repo.spath)
6419
6428
6420
6429
6421 @command(
6430 @command(
6422 b'serve',
6431 b'serve',
6423 [
6432 [
6424 (
6433 (
6425 b'A',
6434 b'A',
6426 b'accesslog',
6435 b'accesslog',
6427 b'',
6436 b'',
6428 _(b'name of access log file to write to'),
6437 _(b'name of access log file to write to'),
6429 _(b'FILE'),
6438 _(b'FILE'),
6430 ),
6439 ),
6431 (b'd', b'daemon', None, _(b'run server in background')),
6440 (b'd', b'daemon', None, _(b'run server in background')),
6432 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6441 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6433 (
6442 (
6434 b'E',
6443 b'E',
6435 b'errorlog',
6444 b'errorlog',
6436 b'',
6445 b'',
6437 _(b'name of error log file to write to'),
6446 _(b'name of error log file to write to'),
6438 _(b'FILE'),
6447 _(b'FILE'),
6439 ),
6448 ),
6440 # use string type, then we can check if something was passed
6449 # use string type, then we can check if something was passed
6441 (
6450 (
6442 b'p',
6451 b'p',
6443 b'port',
6452 b'port',
6444 b'',
6453 b'',
6445 _(b'port to listen on (default: 8000)'),
6454 _(b'port to listen on (default: 8000)'),
6446 _(b'PORT'),
6455 _(b'PORT'),
6447 ),
6456 ),
6448 (
6457 (
6449 b'a',
6458 b'a',
6450 b'address',
6459 b'address',
6451 b'',
6460 b'',
6452 _(b'address to listen on (default: all interfaces)'),
6461 _(b'address to listen on (default: all interfaces)'),
6453 _(b'ADDR'),
6462 _(b'ADDR'),
6454 ),
6463 ),
6455 (
6464 (
6456 b'',
6465 b'',
6457 b'prefix',
6466 b'prefix',
6458 b'',
6467 b'',
6459 _(b'prefix path to serve from (default: server root)'),
6468 _(b'prefix path to serve from (default: server root)'),
6460 _(b'PREFIX'),
6469 _(b'PREFIX'),
6461 ),
6470 ),
6462 (
6471 (
6463 b'n',
6472 b'n',
6464 b'name',
6473 b'name',
6465 b'',
6474 b'',
6466 _(b'name to show in web pages (default: working directory)'),
6475 _(b'name to show in web pages (default: working directory)'),
6467 _(b'NAME'),
6476 _(b'NAME'),
6468 ),
6477 ),
6469 (
6478 (
6470 b'',
6479 b'',
6471 b'web-conf',
6480 b'web-conf',
6472 b'',
6481 b'',
6473 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6482 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6474 _(b'FILE'),
6483 _(b'FILE'),
6475 ),
6484 ),
6476 (
6485 (
6477 b'',
6486 b'',
6478 b'webdir-conf',
6487 b'webdir-conf',
6479 b'',
6488 b'',
6480 _(b'name of the hgweb config file (DEPRECATED)'),
6489 _(b'name of the hgweb config file (DEPRECATED)'),
6481 _(b'FILE'),
6490 _(b'FILE'),
6482 ),
6491 ),
6483 (
6492 (
6484 b'',
6493 b'',
6485 b'pid-file',
6494 b'pid-file',
6486 b'',
6495 b'',
6487 _(b'name of file to write process ID to'),
6496 _(b'name of file to write process ID to'),
6488 _(b'FILE'),
6497 _(b'FILE'),
6489 ),
6498 ),
6490 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6499 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6491 (
6500 (
6492 b'',
6501 b'',
6493 b'cmdserver',
6502 b'cmdserver',
6494 b'',
6503 b'',
6495 _(b'for remote clients (ADVANCED)'),
6504 _(b'for remote clients (ADVANCED)'),
6496 _(b'MODE'),
6505 _(b'MODE'),
6497 ),
6506 ),
6498 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6507 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6499 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6508 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6500 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6509 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6501 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6510 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6502 (b'', b'print-url', None, _(b'start and print only the URL')),
6511 (b'', b'print-url', None, _(b'start and print only the URL')),
6503 ]
6512 ]
6504 + subrepoopts,
6513 + subrepoopts,
6505 _(b'[OPTION]...'),
6514 _(b'[OPTION]...'),
6506 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6515 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6507 helpbasic=True,
6516 helpbasic=True,
6508 optionalrepo=True,
6517 optionalrepo=True,
6509 )
6518 )
6510 def serve(ui, repo, **opts):
6519 def serve(ui, repo, **opts):
6511 """start stand-alone webserver
6520 """start stand-alone webserver
6512
6521
6513 Start a local HTTP repository browser and pull server. You can use
6522 Start a local HTTP repository browser and pull server. You can use
6514 this for ad-hoc sharing and browsing of repositories. It is
6523 this for ad-hoc sharing and browsing of repositories. It is
6515 recommended to use a real web server to serve a repository for
6524 recommended to use a real web server to serve a repository for
6516 longer periods of time.
6525 longer periods of time.
6517
6526
6518 Please note that the server does not implement access control.
6527 Please note that the server does not implement access control.
6519 This means that, by default, anybody can read from the server and
6528 This means that, by default, anybody can read from the server and
6520 nobody can write to it by default. Set the ``web.allow-push``
6529 nobody can write to it by default. Set the ``web.allow-push``
6521 option to ``*`` to allow everybody to push to the server. You
6530 option to ``*`` to allow everybody to push to the server. You
6522 should use a real web server if you need to authenticate users.
6531 should use a real web server if you need to authenticate users.
6523
6532
6524 By default, the server logs accesses to stdout and errors to
6533 By default, the server logs accesses to stdout and errors to
6525 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6534 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6526 files.
6535 files.
6527
6536
6528 To have the server choose a free port number to listen on, specify
6537 To have the server choose a free port number to listen on, specify
6529 a port number of 0; in this case, the server will print the port
6538 a port number of 0; in this case, the server will print the port
6530 number it uses.
6539 number it uses.
6531
6540
6532 Returns 0 on success.
6541 Returns 0 on success.
6533 """
6542 """
6534
6543
6535 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6544 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6536 opts = pycompat.byteskwargs(opts)
6545 opts = pycompat.byteskwargs(opts)
6537 if opts[b"print_url"] and ui.verbose:
6546 if opts[b"print_url"] and ui.verbose:
6538 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6547 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6539
6548
6540 if opts[b"stdio"]:
6549 if opts[b"stdio"]:
6541 if repo is None:
6550 if repo is None:
6542 raise error.RepoError(
6551 raise error.RepoError(
6543 _(b"there is no Mercurial repository here (.hg not found)")
6552 _(b"there is no Mercurial repository here (.hg not found)")
6544 )
6553 )
6545 s = wireprotoserver.sshserver(ui, repo)
6554 s = wireprotoserver.sshserver(ui, repo)
6546 s.serve_forever()
6555 s.serve_forever()
6547 return
6556 return
6548
6557
6549 service = server.createservice(ui, repo, opts)
6558 service = server.createservice(ui, repo, opts)
6550 return server.runservice(opts, initfn=service.init, runfn=service.run)
6559 return server.runservice(opts, initfn=service.init, runfn=service.run)
6551
6560
6552
6561
6553 @command(
6562 @command(
6554 b'shelve',
6563 b'shelve',
6555 [
6564 [
6556 (
6565 (
6557 b'A',
6566 b'A',
6558 b'addremove',
6567 b'addremove',
6559 None,
6568 None,
6560 _(b'mark new/missing files as added/removed before shelving'),
6569 _(b'mark new/missing files as added/removed before shelving'),
6561 ),
6570 ),
6562 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6571 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6563 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6572 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6564 (
6573 (
6565 b'',
6574 b'',
6566 b'date',
6575 b'date',
6567 b'',
6576 b'',
6568 _(b'shelve with the specified commit date'),
6577 _(b'shelve with the specified commit date'),
6569 _(b'DATE'),
6578 _(b'DATE'),
6570 ),
6579 ),
6571 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6580 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6572 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6581 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6573 (
6582 (
6574 b'k',
6583 b'k',
6575 b'keep',
6584 b'keep',
6576 False,
6585 False,
6577 _(b'shelve, but keep changes in the working directory'),
6586 _(b'shelve, but keep changes in the working directory'),
6578 ),
6587 ),
6579 (b'l', b'list', None, _(b'list current shelves')),
6588 (b'l', b'list', None, _(b'list current shelves')),
6580 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6589 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6581 (
6590 (
6582 b'n',
6591 b'n',
6583 b'name',
6592 b'name',
6584 b'',
6593 b'',
6585 _(b'use the given name for the shelved commit'),
6594 _(b'use the given name for the shelved commit'),
6586 _(b'NAME'),
6595 _(b'NAME'),
6587 ),
6596 ),
6588 (
6597 (
6589 b'p',
6598 b'p',
6590 b'patch',
6599 b'patch',
6591 None,
6600 None,
6592 _(
6601 _(
6593 b'output patches for changes (provide the names of the shelved '
6602 b'output patches for changes (provide the names of the shelved '
6594 b'changes as positional arguments)'
6603 b'changes as positional arguments)'
6595 ),
6604 ),
6596 ),
6605 ),
6597 (b'i', b'interactive', None, _(b'interactive mode')),
6606 (b'i', b'interactive', None, _(b'interactive mode')),
6598 (
6607 (
6599 b'',
6608 b'',
6600 b'stat',
6609 b'stat',
6601 None,
6610 None,
6602 _(
6611 _(
6603 b'output diffstat-style summary of changes (provide the names of '
6612 b'output diffstat-style summary of changes (provide the names of '
6604 b'the shelved changes as positional arguments)'
6613 b'the shelved changes as positional arguments)'
6605 ),
6614 ),
6606 ),
6615 ),
6607 ]
6616 ]
6608 + cmdutil.walkopts,
6617 + cmdutil.walkopts,
6609 _(b'hg shelve [OPTION]... [FILE]...'),
6618 _(b'hg shelve [OPTION]... [FILE]...'),
6610 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6619 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6611 )
6620 )
6612 def shelve(ui, repo, *pats, **opts):
6621 def shelve(ui, repo, *pats, **opts):
6613 """save and set aside changes from the working directory
6622 """save and set aside changes from the working directory
6614
6623
6615 Shelving takes files that "hg status" reports as not clean, saves
6624 Shelving takes files that "hg status" reports as not clean, saves
6616 the modifications to a bundle (a shelved change), and reverts the
6625 the modifications to a bundle (a shelved change), and reverts the
6617 files so that their state in the working directory becomes clean.
6626 files so that their state in the working directory becomes clean.
6618
6627
6619 To restore these changes to the working directory, using "hg
6628 To restore these changes to the working directory, using "hg
6620 unshelve"; this will work even if you switch to a different
6629 unshelve"; this will work even if you switch to a different
6621 commit.
6630 commit.
6622
6631
6623 When no files are specified, "hg shelve" saves all not-clean
6632 When no files are specified, "hg shelve" saves all not-clean
6624 files. If specific files or directories are named, only changes to
6633 files. If specific files or directories are named, only changes to
6625 those files are shelved.
6634 those files are shelved.
6626
6635
6627 In bare shelve (when no files are specified, without interactive,
6636 In bare shelve (when no files are specified, without interactive,
6628 include and exclude option), shelving remembers information if the
6637 include and exclude option), shelving remembers information if the
6629 working directory was on newly created branch, in other words working
6638 working directory was on newly created branch, in other words working
6630 directory was on different branch than its first parent. In this
6639 directory was on different branch than its first parent. In this
6631 situation unshelving restores branch information to the working directory.
6640 situation unshelving restores branch information to the working directory.
6632
6641
6633 Each shelved change has a name that makes it easier to find later.
6642 Each shelved change has a name that makes it easier to find later.
6634 The name of a shelved change defaults to being based on the active
6643 The name of a shelved change defaults to being based on the active
6635 bookmark, or if there is no active bookmark, the current named
6644 bookmark, or if there is no active bookmark, the current named
6636 branch. To specify a different name, use ``--name``.
6645 branch. To specify a different name, use ``--name``.
6637
6646
6638 To see a list of existing shelved changes, use the ``--list``
6647 To see a list of existing shelved changes, use the ``--list``
6639 option. For each shelved change, this will print its name, age,
6648 option. For each shelved change, this will print its name, age,
6640 and description; use ``--patch`` or ``--stat`` for more details.
6649 and description; use ``--patch`` or ``--stat`` for more details.
6641
6650
6642 To delete specific shelved changes, use ``--delete``. To delete
6651 To delete specific shelved changes, use ``--delete``. To delete
6643 all shelved changes, use ``--cleanup``.
6652 all shelved changes, use ``--cleanup``.
6644 """
6653 """
6645 opts = pycompat.byteskwargs(opts)
6654 opts = pycompat.byteskwargs(opts)
6646 allowables = [
6655 allowables = [
6647 (b'addremove', {b'create'}), # 'create' is pseudo action
6656 (b'addremove', {b'create'}), # 'create' is pseudo action
6648 (b'unknown', {b'create'}),
6657 (b'unknown', {b'create'}),
6649 (b'cleanup', {b'cleanup'}),
6658 (b'cleanup', {b'cleanup'}),
6650 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6659 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6651 (b'delete', {b'delete'}),
6660 (b'delete', {b'delete'}),
6652 (b'edit', {b'create'}),
6661 (b'edit', {b'create'}),
6653 (b'keep', {b'create'}),
6662 (b'keep', {b'create'}),
6654 (b'list', {b'list'}),
6663 (b'list', {b'list'}),
6655 (b'message', {b'create'}),
6664 (b'message', {b'create'}),
6656 (b'name', {b'create'}),
6665 (b'name', {b'create'}),
6657 (b'patch', {b'patch', b'list'}),
6666 (b'patch', {b'patch', b'list'}),
6658 (b'stat', {b'stat', b'list'}),
6667 (b'stat', {b'stat', b'list'}),
6659 ]
6668 ]
6660
6669
6661 def checkopt(opt):
6670 def checkopt(opt):
6662 if opts.get(opt):
6671 if opts.get(opt):
6663 for i, allowable in allowables:
6672 for i, allowable in allowables:
6664 if opts[i] and opt not in allowable:
6673 if opts[i] and opt not in allowable:
6665 raise error.InputError(
6674 raise error.InputError(
6666 _(
6675 _(
6667 b"options '--%s' and '--%s' may not be "
6676 b"options '--%s' and '--%s' may not be "
6668 b"used together"
6677 b"used together"
6669 )
6678 )
6670 % (opt, i)
6679 % (opt, i)
6671 )
6680 )
6672 return True
6681 return True
6673
6682
6674 if checkopt(b'cleanup'):
6683 if checkopt(b'cleanup'):
6675 if pats:
6684 if pats:
6676 raise error.InputError(
6685 raise error.InputError(
6677 _(b"cannot specify names when using '--cleanup'")
6686 _(b"cannot specify names when using '--cleanup'")
6678 )
6687 )
6679 return shelvemod.cleanupcmd(ui, repo)
6688 return shelvemod.cleanupcmd(ui, repo)
6680 elif checkopt(b'delete'):
6689 elif checkopt(b'delete'):
6681 return shelvemod.deletecmd(ui, repo, pats)
6690 return shelvemod.deletecmd(ui, repo, pats)
6682 elif checkopt(b'list'):
6691 elif checkopt(b'list'):
6683 return shelvemod.listcmd(ui, repo, pats, opts)
6692 return shelvemod.listcmd(ui, repo, pats, opts)
6684 elif checkopt(b'patch') or checkopt(b'stat'):
6693 elif checkopt(b'patch') or checkopt(b'stat'):
6685 return shelvemod.patchcmds(ui, repo, pats, opts)
6694 return shelvemod.patchcmds(ui, repo, pats, opts)
6686 else:
6695 else:
6687 return shelvemod.createcmd(ui, repo, pats, opts)
6696 return shelvemod.createcmd(ui, repo, pats, opts)
6688
6697
6689
6698
6690 _NOTTERSE = b'nothing'
6699 _NOTTERSE = b'nothing'
6691
6700
6692
6701
6693 @command(
6702 @command(
6694 b'status|st',
6703 b'status|st',
6695 [
6704 [
6696 (b'A', b'all', None, _(b'show status of all files')),
6705 (b'A', b'all', None, _(b'show status of all files')),
6697 (b'm', b'modified', None, _(b'show only modified files')),
6706 (b'm', b'modified', None, _(b'show only modified files')),
6698 (b'a', b'added', None, _(b'show only added files')),
6707 (b'a', b'added', None, _(b'show only added files')),
6699 (b'r', b'removed', None, _(b'show only removed files')),
6708 (b'r', b'removed', None, _(b'show only removed files')),
6700 (b'd', b'deleted', None, _(b'show only missing files')),
6709 (b'd', b'deleted', None, _(b'show only missing files')),
6701 (b'c', b'clean', None, _(b'show only files without changes')),
6710 (b'c', b'clean', None, _(b'show only files without changes')),
6702 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6711 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6703 (b'i', b'ignored', None, _(b'show only ignored files')),
6712 (b'i', b'ignored', None, _(b'show only ignored files')),
6704 (b'n', b'no-status', None, _(b'hide status prefix')),
6713 (b'n', b'no-status', None, _(b'hide status prefix')),
6705 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6714 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6706 (
6715 (
6707 b'C',
6716 b'C',
6708 b'copies',
6717 b'copies',
6709 None,
6718 None,
6710 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6719 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6711 ),
6720 ),
6712 (
6721 (
6713 b'0',
6722 b'0',
6714 b'print0',
6723 b'print0',
6715 None,
6724 None,
6716 _(b'end filenames with NUL, for use with xargs'),
6725 _(b'end filenames with NUL, for use with xargs'),
6717 ),
6726 ),
6718 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6727 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6719 (
6728 (
6720 b'',
6729 b'',
6721 b'change',
6730 b'change',
6722 b'',
6731 b'',
6723 _(b'list the changed files of a revision'),
6732 _(b'list the changed files of a revision'),
6724 _(b'REV'),
6733 _(b'REV'),
6725 ),
6734 ),
6726 ]
6735 ]
6727 + walkopts
6736 + walkopts
6728 + subrepoopts
6737 + subrepoopts
6729 + formatteropts,
6738 + formatteropts,
6730 _(b'[OPTION]... [FILE]...'),
6739 _(b'[OPTION]... [FILE]...'),
6731 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6740 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6732 helpbasic=True,
6741 helpbasic=True,
6733 inferrepo=True,
6742 inferrepo=True,
6734 intents={INTENT_READONLY},
6743 intents={INTENT_READONLY},
6735 )
6744 )
6736 def status(ui, repo, *pats, **opts):
6745 def status(ui, repo, *pats, **opts):
6737 """show changed files in the working directory
6746 """show changed files in the working directory
6738
6747
6739 Show status of files in the repository. If names are given, only
6748 Show status of files in the repository. If names are given, only
6740 files that match are shown. Files that are clean or ignored or
6749 files that match are shown. Files that are clean or ignored or
6741 the source of a copy/move operation, are not listed unless
6750 the source of a copy/move operation, are not listed unless
6742 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6751 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6743 Unless options described with "show only ..." are given, the
6752 Unless options described with "show only ..." are given, the
6744 options -mardu are used.
6753 options -mardu are used.
6745
6754
6746 Option -q/--quiet hides untracked (unknown and ignored) files
6755 Option -q/--quiet hides untracked (unknown and ignored) files
6747 unless explicitly requested with -u/--unknown or -i/--ignored.
6756 unless explicitly requested with -u/--unknown or -i/--ignored.
6748
6757
6749 .. note::
6758 .. note::
6750
6759
6751 :hg:`status` may appear to disagree with diff if permissions have
6760 :hg:`status` may appear to disagree with diff if permissions have
6752 changed or a merge has occurred. The standard diff format does
6761 changed or a merge has occurred. The standard diff format does
6753 not report permission changes and diff only reports changes
6762 not report permission changes and diff only reports changes
6754 relative to one merge parent.
6763 relative to one merge parent.
6755
6764
6756 If one revision is given, it is used as the base revision.
6765 If one revision is given, it is used as the base revision.
6757 If two revisions are given, the differences between them are
6766 If two revisions are given, the differences between them are
6758 shown. The --change option can also be used as a shortcut to list
6767 shown. The --change option can also be used as a shortcut to list
6759 the changed files of a revision from its first parent.
6768 the changed files of a revision from its first parent.
6760
6769
6761 The codes used to show the status of files are::
6770 The codes used to show the status of files are::
6762
6771
6763 M = modified
6772 M = modified
6764 A = added
6773 A = added
6765 R = removed
6774 R = removed
6766 C = clean
6775 C = clean
6767 ! = missing (deleted by non-hg command, but still tracked)
6776 ! = missing (deleted by non-hg command, but still tracked)
6768 ? = not tracked
6777 ? = not tracked
6769 I = ignored
6778 I = ignored
6770 = origin of the previous file (with --copies)
6779 = origin of the previous file (with --copies)
6771
6780
6772 .. container:: verbose
6781 .. container:: verbose
6773
6782
6774 The -t/--terse option abbreviates the output by showing only the directory
6783 The -t/--terse option abbreviates the output by showing only the directory
6775 name if all the files in it share the same status. The option takes an
6784 name if all the files in it share the same status. The option takes an
6776 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6785 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6777 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6786 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6778 for 'ignored' and 'c' for clean.
6787 for 'ignored' and 'c' for clean.
6779
6788
6780 It abbreviates only those statuses which are passed. Note that clean and
6789 It abbreviates only those statuses which are passed. Note that clean and
6781 ignored files are not displayed with '--terse ic' unless the -c/--clean
6790 ignored files are not displayed with '--terse ic' unless the -c/--clean
6782 and -i/--ignored options are also used.
6791 and -i/--ignored options are also used.
6783
6792
6784 The -v/--verbose option shows information when the repository is in an
6793 The -v/--verbose option shows information when the repository is in an
6785 unfinished merge, shelve, rebase state etc. You can have this behavior
6794 unfinished merge, shelve, rebase state etc. You can have this behavior
6786 turned on by default by enabling the ``commands.status.verbose`` option.
6795 turned on by default by enabling the ``commands.status.verbose`` option.
6787
6796
6788 You can skip displaying some of these states by setting
6797 You can skip displaying some of these states by setting
6789 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6798 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6790 'histedit', 'merge', 'rebase', or 'unshelve'.
6799 'histedit', 'merge', 'rebase', or 'unshelve'.
6791
6800
6792 Template:
6801 Template:
6793
6802
6794 The following keywords are supported in addition to the common template
6803 The following keywords are supported in addition to the common template
6795 keywords and functions. See also :hg:`help templates`.
6804 keywords and functions. See also :hg:`help templates`.
6796
6805
6797 :path: String. Repository-absolute path of the file.
6806 :path: String. Repository-absolute path of the file.
6798 :source: String. Repository-absolute path of the file originated from.
6807 :source: String. Repository-absolute path of the file originated from.
6799 Available if ``--copies`` is specified.
6808 Available if ``--copies`` is specified.
6800 :status: String. Character denoting file's status.
6809 :status: String. Character denoting file's status.
6801
6810
6802 Examples:
6811 Examples:
6803
6812
6804 - show changes in the working directory relative to a
6813 - show changes in the working directory relative to a
6805 changeset::
6814 changeset::
6806
6815
6807 hg status --rev 9353
6816 hg status --rev 9353
6808
6817
6809 - show changes in the working directory relative to the
6818 - show changes in the working directory relative to the
6810 current directory (see :hg:`help patterns` for more information)::
6819 current directory (see :hg:`help patterns` for more information)::
6811
6820
6812 hg status re:
6821 hg status re:
6813
6822
6814 - show all changes including copies in an existing changeset::
6823 - show all changes including copies in an existing changeset::
6815
6824
6816 hg status --copies --change 9353
6825 hg status --copies --change 9353
6817
6826
6818 - get a NUL separated list of added files, suitable for xargs::
6827 - get a NUL separated list of added files, suitable for xargs::
6819
6828
6820 hg status -an0
6829 hg status -an0
6821
6830
6822 - show more information about the repository status, abbreviating
6831 - show more information about the repository status, abbreviating
6823 added, removed, modified, deleted, and untracked paths::
6832 added, removed, modified, deleted, and untracked paths::
6824
6833
6825 hg status -v -t mardu
6834 hg status -v -t mardu
6826
6835
6827 Returns 0 on success.
6836 Returns 0 on success.
6828
6837
6829 """
6838 """
6830
6839
6831 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6840 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6832 opts = pycompat.byteskwargs(opts)
6841 opts = pycompat.byteskwargs(opts)
6833 revs = opts.get(b'rev')
6842 revs = opts.get(b'rev')
6834 change = opts.get(b'change')
6843 change = opts.get(b'change')
6835 terse = opts.get(b'terse')
6844 terse = opts.get(b'terse')
6836 if terse is _NOTTERSE:
6845 if terse is _NOTTERSE:
6837 if revs:
6846 if revs:
6838 terse = b''
6847 terse = b''
6839 else:
6848 else:
6840 terse = ui.config(b'commands', b'status.terse')
6849 terse = ui.config(b'commands', b'status.terse')
6841
6850
6842 if revs and terse:
6851 if revs and terse:
6843 msg = _(b'cannot use --terse with --rev')
6852 msg = _(b'cannot use --terse with --rev')
6844 raise error.InputError(msg)
6853 raise error.InputError(msg)
6845 elif change:
6854 elif change:
6846 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6855 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6847 ctx2 = scmutil.revsingle(repo, change, None)
6856 ctx2 = scmutil.revsingle(repo, change, None)
6848 ctx1 = ctx2.p1()
6857 ctx1 = ctx2.p1()
6849 else:
6858 else:
6850 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6859 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6851 ctx1, ctx2 = scmutil.revpair(repo, revs)
6860 ctx1, ctx2 = scmutil.revpair(repo, revs)
6852
6861
6853 forcerelativevalue = None
6862 forcerelativevalue = None
6854 if ui.hasconfig(b'commands', b'status.relative'):
6863 if ui.hasconfig(b'commands', b'status.relative'):
6855 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6864 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6856 uipathfn = scmutil.getuipathfn(
6865 uipathfn = scmutil.getuipathfn(
6857 repo,
6866 repo,
6858 legacyrelativevalue=bool(pats),
6867 legacyrelativevalue=bool(pats),
6859 forcerelativevalue=forcerelativevalue,
6868 forcerelativevalue=forcerelativevalue,
6860 )
6869 )
6861
6870
6862 if opts.get(b'print0'):
6871 if opts.get(b'print0'):
6863 end = b'\0'
6872 end = b'\0'
6864 else:
6873 else:
6865 end = b'\n'
6874 end = b'\n'
6866 states = b'modified added removed deleted unknown ignored clean'.split()
6875 states = b'modified added removed deleted unknown ignored clean'.split()
6867 show = [k for k in states if opts.get(k)]
6876 show = [k for k in states if opts.get(k)]
6868 if opts.get(b'all'):
6877 if opts.get(b'all'):
6869 show += ui.quiet and (states[:4] + [b'clean']) or states
6878 show += ui.quiet and (states[:4] + [b'clean']) or states
6870
6879
6871 if not show:
6880 if not show:
6872 if ui.quiet:
6881 if ui.quiet:
6873 show = states[:4]
6882 show = states[:4]
6874 else:
6883 else:
6875 show = states[:5]
6884 show = states[:5]
6876
6885
6877 m = scmutil.match(ctx2, pats, opts)
6886 m = scmutil.match(ctx2, pats, opts)
6878 if terse:
6887 if terse:
6879 # we need to compute clean and unknown to terse
6888 # we need to compute clean and unknown to terse
6880 stat = repo.status(
6889 stat = repo.status(
6881 ctx1.node(),
6890 ctx1.node(),
6882 ctx2.node(),
6891 ctx2.node(),
6883 m,
6892 m,
6884 b'ignored' in show or b'i' in terse,
6893 b'ignored' in show or b'i' in terse,
6885 clean=True,
6894 clean=True,
6886 unknown=True,
6895 unknown=True,
6887 listsubrepos=opts.get(b'subrepos'),
6896 listsubrepos=opts.get(b'subrepos'),
6888 )
6897 )
6889
6898
6890 stat = cmdutil.tersedir(stat, terse)
6899 stat = cmdutil.tersedir(stat, terse)
6891 else:
6900 else:
6892 stat = repo.status(
6901 stat = repo.status(
6893 ctx1.node(),
6902 ctx1.node(),
6894 ctx2.node(),
6903 ctx2.node(),
6895 m,
6904 m,
6896 b'ignored' in show,
6905 b'ignored' in show,
6897 b'clean' in show,
6906 b'clean' in show,
6898 b'unknown' in show,
6907 b'unknown' in show,
6899 opts.get(b'subrepos'),
6908 opts.get(b'subrepos'),
6900 )
6909 )
6901
6910
6902 changestates = zip(
6911 changestates = zip(
6903 states,
6912 states,
6904 pycompat.iterbytestr(b'MAR!?IC'),
6913 pycompat.iterbytestr(b'MAR!?IC'),
6905 [getattr(stat, s.decode('utf8')) for s in states],
6914 [getattr(stat, s.decode('utf8')) for s in states],
6906 )
6915 )
6907
6916
6908 copy = {}
6917 copy = {}
6909 if (
6918 if (
6910 opts.get(b'all')
6919 opts.get(b'all')
6911 or opts.get(b'copies')
6920 or opts.get(b'copies')
6912 or ui.configbool(b'ui', b'statuscopies')
6921 or ui.configbool(b'ui', b'statuscopies')
6913 ) and not opts.get(b'no_status'):
6922 ) and not opts.get(b'no_status'):
6914 copy = copies.pathcopies(ctx1, ctx2, m)
6923 copy = copies.pathcopies(ctx1, ctx2, m)
6915
6924
6916 morestatus = None
6925 morestatus = None
6917 if (
6926 if (
6918 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6927 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6919 and not ui.plain()
6928 and not ui.plain()
6920 and not opts.get(b'print0')
6929 and not opts.get(b'print0')
6921 ):
6930 ):
6922 morestatus = cmdutil.readmorestatus(repo)
6931 morestatus = cmdutil.readmorestatus(repo)
6923
6932
6924 ui.pager(b'status')
6933 ui.pager(b'status')
6925 fm = ui.formatter(b'status', opts)
6934 fm = ui.formatter(b'status', opts)
6926 fmt = b'%s' + end
6935 fmt = b'%s' + end
6927 showchar = not opts.get(b'no_status')
6936 showchar = not opts.get(b'no_status')
6928
6937
6929 for state, char, files in changestates:
6938 for state, char, files in changestates:
6930 if state in show:
6939 if state in show:
6931 label = b'status.' + state
6940 label = b'status.' + state
6932 for f in files:
6941 for f in files:
6933 fm.startitem()
6942 fm.startitem()
6934 fm.context(ctx=ctx2)
6943 fm.context(ctx=ctx2)
6935 fm.data(itemtype=b'file', path=f)
6944 fm.data(itemtype=b'file', path=f)
6936 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6945 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6937 fm.plain(fmt % uipathfn(f), label=label)
6946 fm.plain(fmt % uipathfn(f), label=label)
6938 if f in copy:
6947 if f in copy:
6939 fm.data(source=copy[f])
6948 fm.data(source=copy[f])
6940 fm.plain(
6949 fm.plain(
6941 (b' %s' + end) % uipathfn(copy[f]),
6950 (b' %s' + end) % uipathfn(copy[f]),
6942 label=b'status.copied',
6951 label=b'status.copied',
6943 )
6952 )
6944 if morestatus:
6953 if morestatus:
6945 morestatus.formatfile(f, fm)
6954 morestatus.formatfile(f, fm)
6946
6955
6947 if morestatus:
6956 if morestatus:
6948 morestatus.formatfooter(fm)
6957 morestatus.formatfooter(fm)
6949 fm.end()
6958 fm.end()
6950
6959
6951
6960
6952 @command(
6961 @command(
6953 b'summary|sum',
6962 b'summary|sum',
6954 [(b'', b'remote', None, _(b'check for push and pull'))],
6963 [(b'', b'remote', None, _(b'check for push and pull'))],
6955 b'[--remote]',
6964 b'[--remote]',
6956 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6965 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6957 helpbasic=True,
6966 helpbasic=True,
6958 intents={INTENT_READONLY},
6967 intents={INTENT_READONLY},
6959 )
6968 )
6960 def summary(ui, repo, **opts):
6969 def summary(ui, repo, **opts):
6961 """summarize working directory state
6970 """summarize working directory state
6962
6971
6963 This generates a brief summary of the working directory state,
6972 This generates a brief summary of the working directory state,
6964 including parents, branch, commit status, phase and available updates.
6973 including parents, branch, commit status, phase and available updates.
6965
6974
6966 With the --remote option, this will check the default paths for
6975 With the --remote option, this will check the default paths for
6967 incoming and outgoing changes. This can be time-consuming.
6976 incoming and outgoing changes. This can be time-consuming.
6968
6977
6969 Returns 0 on success.
6978 Returns 0 on success.
6970 """
6979 """
6971
6980
6972 opts = pycompat.byteskwargs(opts)
6981 opts = pycompat.byteskwargs(opts)
6973 ui.pager(b'summary')
6982 ui.pager(b'summary')
6974 ctx = repo[None]
6983 ctx = repo[None]
6975 parents = ctx.parents()
6984 parents = ctx.parents()
6976 pnode = parents[0].node()
6985 pnode = parents[0].node()
6977 marks = []
6986 marks = []
6978
6987
6979 try:
6988 try:
6980 ms = mergestatemod.mergestate.read(repo)
6989 ms = mergestatemod.mergestate.read(repo)
6981 except error.UnsupportedMergeRecords as e:
6990 except error.UnsupportedMergeRecords as e:
6982 s = b' '.join(e.recordtypes)
6991 s = b' '.join(e.recordtypes)
6983 ui.warn(
6992 ui.warn(
6984 _(b'warning: merge state has unsupported record types: %s\n') % s
6993 _(b'warning: merge state has unsupported record types: %s\n') % s
6985 )
6994 )
6986 unresolved = []
6995 unresolved = []
6987 else:
6996 else:
6988 unresolved = list(ms.unresolved())
6997 unresolved = list(ms.unresolved())
6989
6998
6990 for p in parents:
6999 for p in parents:
6991 # label with log.changeset (instead of log.parent) since this
7000 # label with log.changeset (instead of log.parent) since this
6992 # shows a working directory parent *changeset*:
7001 # shows a working directory parent *changeset*:
6993 # i18n: column positioning for "hg summary"
7002 # i18n: column positioning for "hg summary"
6994 ui.write(
7003 ui.write(
6995 _(b'parent: %d:%s ') % (p.rev(), p),
7004 _(b'parent: %d:%s ') % (p.rev(), p),
6996 label=logcmdutil.changesetlabels(p),
7005 label=logcmdutil.changesetlabels(p),
6997 )
7006 )
6998 ui.write(b' '.join(p.tags()), label=b'log.tag')
7007 ui.write(b' '.join(p.tags()), label=b'log.tag')
6999 if p.bookmarks():
7008 if p.bookmarks():
7000 marks.extend(p.bookmarks())
7009 marks.extend(p.bookmarks())
7001 if p.rev() == -1:
7010 if p.rev() == -1:
7002 if not len(repo):
7011 if not len(repo):
7003 ui.write(_(b' (empty repository)'))
7012 ui.write(_(b' (empty repository)'))
7004 else:
7013 else:
7005 ui.write(_(b' (no revision checked out)'))
7014 ui.write(_(b' (no revision checked out)'))
7006 if p.obsolete():
7015 if p.obsolete():
7007 ui.write(_(b' (obsolete)'))
7016 ui.write(_(b' (obsolete)'))
7008 if p.isunstable():
7017 if p.isunstable():
7009 instabilities = (
7018 instabilities = (
7010 ui.label(instability, b'trouble.%s' % instability)
7019 ui.label(instability, b'trouble.%s' % instability)
7011 for instability in p.instabilities()
7020 for instability in p.instabilities()
7012 )
7021 )
7013 ui.write(b' (' + b', '.join(instabilities) + b')')
7022 ui.write(b' (' + b', '.join(instabilities) + b')')
7014 ui.write(b'\n')
7023 ui.write(b'\n')
7015 if p.description():
7024 if p.description():
7016 ui.status(
7025 ui.status(
7017 b' ' + p.description().splitlines()[0].strip() + b'\n',
7026 b' ' + p.description().splitlines()[0].strip() + b'\n',
7018 label=b'log.summary',
7027 label=b'log.summary',
7019 )
7028 )
7020
7029
7021 branch = ctx.branch()
7030 branch = ctx.branch()
7022 bheads = repo.branchheads(branch)
7031 bheads = repo.branchheads(branch)
7023 # i18n: column positioning for "hg summary"
7032 # i18n: column positioning for "hg summary"
7024 m = _(b'branch: %s\n') % branch
7033 m = _(b'branch: %s\n') % branch
7025 if branch != b'default':
7034 if branch != b'default':
7026 ui.write(m, label=b'log.branch')
7035 ui.write(m, label=b'log.branch')
7027 else:
7036 else:
7028 ui.status(m, label=b'log.branch')
7037 ui.status(m, label=b'log.branch')
7029
7038
7030 if marks:
7039 if marks:
7031 active = repo._activebookmark
7040 active = repo._activebookmark
7032 # i18n: column positioning for "hg summary"
7041 # i18n: column positioning for "hg summary"
7033 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7042 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
7034 if active is not None:
7043 if active is not None:
7035 if active in marks:
7044 if active in marks:
7036 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7045 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
7037 marks.remove(active)
7046 marks.remove(active)
7038 else:
7047 else:
7039 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7048 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
7040 for m in marks:
7049 for m in marks:
7041 ui.write(b' ' + m, label=b'log.bookmark')
7050 ui.write(b' ' + m, label=b'log.bookmark')
7042 ui.write(b'\n', label=b'log.bookmark')
7051 ui.write(b'\n', label=b'log.bookmark')
7043
7052
7044 status = repo.status(unknown=True)
7053 status = repo.status(unknown=True)
7045
7054
7046 c = repo.dirstate.copies()
7055 c = repo.dirstate.copies()
7047 copied, renamed = [], []
7056 copied, renamed = [], []
7048 for d, s in pycompat.iteritems(c):
7057 for d, s in pycompat.iteritems(c):
7049 if s in status.removed:
7058 if s in status.removed:
7050 status.removed.remove(s)
7059 status.removed.remove(s)
7051 renamed.append(d)
7060 renamed.append(d)
7052 else:
7061 else:
7053 copied.append(d)
7062 copied.append(d)
7054 if d in status.added:
7063 if d in status.added:
7055 status.added.remove(d)
7064 status.added.remove(d)
7056
7065
7057 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7066 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
7058
7067
7059 labels = [
7068 labels = [
7060 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7069 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
7061 (ui.label(_(b'%d added'), b'status.added'), status.added),
7070 (ui.label(_(b'%d added'), b'status.added'), status.added),
7062 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7071 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
7063 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7072 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
7064 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7073 (ui.label(_(b'%d copied'), b'status.copied'), copied),
7065 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7074 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
7066 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7075 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
7067 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7076 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
7068 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7077 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
7069 ]
7078 ]
7070 t = []
7079 t = []
7071 for l, s in labels:
7080 for l, s in labels:
7072 if s:
7081 if s:
7073 t.append(l % len(s))
7082 t.append(l % len(s))
7074
7083
7075 t = b', '.join(t)
7084 t = b', '.join(t)
7076 cleanworkdir = False
7085 cleanworkdir = False
7077
7086
7078 if repo.vfs.exists(b'graftstate'):
7087 if repo.vfs.exists(b'graftstate'):
7079 t += _(b' (graft in progress)')
7088 t += _(b' (graft in progress)')
7080 if repo.vfs.exists(b'updatestate'):
7089 if repo.vfs.exists(b'updatestate'):
7081 t += _(b' (interrupted update)')
7090 t += _(b' (interrupted update)')
7082 elif len(parents) > 1:
7091 elif len(parents) > 1:
7083 t += _(b' (merge)')
7092 t += _(b' (merge)')
7084 elif branch != parents[0].branch():
7093 elif branch != parents[0].branch():
7085 t += _(b' (new branch)')
7094 t += _(b' (new branch)')
7086 elif parents[0].closesbranch() and pnode in repo.branchheads(
7095 elif parents[0].closesbranch() and pnode in repo.branchheads(
7087 branch, closed=True
7096 branch, closed=True
7088 ):
7097 ):
7089 t += _(b' (head closed)')
7098 t += _(b' (head closed)')
7090 elif not (
7099 elif not (
7091 status.modified
7100 status.modified
7092 or status.added
7101 or status.added
7093 or status.removed
7102 or status.removed
7094 or renamed
7103 or renamed
7095 or copied
7104 or copied
7096 or subs
7105 or subs
7097 ):
7106 ):
7098 t += _(b' (clean)')
7107 t += _(b' (clean)')
7099 cleanworkdir = True
7108 cleanworkdir = True
7100 elif pnode not in bheads:
7109 elif pnode not in bheads:
7101 t += _(b' (new branch head)')
7110 t += _(b' (new branch head)')
7102
7111
7103 if parents:
7112 if parents:
7104 pendingphase = max(p.phase() for p in parents)
7113 pendingphase = max(p.phase() for p in parents)
7105 else:
7114 else:
7106 pendingphase = phases.public
7115 pendingphase = phases.public
7107
7116
7108 if pendingphase > phases.newcommitphase(ui):
7117 if pendingphase > phases.newcommitphase(ui):
7109 t += b' (%s)' % phases.phasenames[pendingphase]
7118 t += b' (%s)' % phases.phasenames[pendingphase]
7110
7119
7111 if cleanworkdir:
7120 if cleanworkdir:
7112 # i18n: column positioning for "hg summary"
7121 # i18n: column positioning for "hg summary"
7113 ui.status(_(b'commit: %s\n') % t.strip())
7122 ui.status(_(b'commit: %s\n') % t.strip())
7114 else:
7123 else:
7115 # i18n: column positioning for "hg summary"
7124 # i18n: column positioning for "hg summary"
7116 ui.write(_(b'commit: %s\n') % t.strip())
7125 ui.write(_(b'commit: %s\n') % t.strip())
7117
7126
7118 # all ancestors of branch heads - all ancestors of parent = new csets
7127 # all ancestors of branch heads - all ancestors of parent = new csets
7119 new = len(
7128 new = len(
7120 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7129 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
7121 )
7130 )
7122
7131
7123 if new == 0:
7132 if new == 0:
7124 # i18n: column positioning for "hg summary"
7133 # i18n: column positioning for "hg summary"
7125 ui.status(_(b'update: (current)\n'))
7134 ui.status(_(b'update: (current)\n'))
7126 elif pnode not in bheads:
7135 elif pnode not in bheads:
7127 # i18n: column positioning for "hg summary"
7136 # i18n: column positioning for "hg summary"
7128 ui.write(_(b'update: %d new changesets (update)\n') % new)
7137 ui.write(_(b'update: %d new changesets (update)\n') % new)
7129 else:
7138 else:
7130 # i18n: column positioning for "hg summary"
7139 # i18n: column positioning for "hg summary"
7131 ui.write(
7140 ui.write(
7132 _(b'update: %d new changesets, %d branch heads (merge)\n')
7141 _(b'update: %d new changesets, %d branch heads (merge)\n')
7133 % (new, len(bheads))
7142 % (new, len(bheads))
7134 )
7143 )
7135
7144
7136 t = []
7145 t = []
7137 draft = len(repo.revs(b'draft()'))
7146 draft = len(repo.revs(b'draft()'))
7138 if draft:
7147 if draft:
7139 t.append(_(b'%d draft') % draft)
7148 t.append(_(b'%d draft') % draft)
7140 secret = len(repo.revs(b'secret()'))
7149 secret = len(repo.revs(b'secret()'))
7141 if secret:
7150 if secret:
7142 t.append(_(b'%d secret') % secret)
7151 t.append(_(b'%d secret') % secret)
7143
7152
7144 if draft or secret:
7153 if draft or secret:
7145 ui.status(_(b'phases: %s\n') % b', '.join(t))
7154 ui.status(_(b'phases: %s\n') % b', '.join(t))
7146
7155
7147 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7156 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7148 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7157 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7149 numtrouble = len(repo.revs(trouble + b"()"))
7158 numtrouble = len(repo.revs(trouble + b"()"))
7150 # We write all the possibilities to ease translation
7159 # We write all the possibilities to ease translation
7151 troublemsg = {
7160 troublemsg = {
7152 b"orphan": _(b"orphan: %d changesets"),
7161 b"orphan": _(b"orphan: %d changesets"),
7153 b"contentdivergent": _(b"content-divergent: %d changesets"),
7162 b"contentdivergent": _(b"content-divergent: %d changesets"),
7154 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7163 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7155 }
7164 }
7156 if numtrouble > 0:
7165 if numtrouble > 0:
7157 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7166 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7158
7167
7159 cmdutil.summaryhooks(ui, repo)
7168 cmdutil.summaryhooks(ui, repo)
7160
7169
7161 if opts.get(b'remote'):
7170 if opts.get(b'remote'):
7162 needsincoming, needsoutgoing = True, True
7171 needsincoming, needsoutgoing = True, True
7163 else:
7172 else:
7164 needsincoming, needsoutgoing = False, False
7173 needsincoming, needsoutgoing = False, False
7165 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7174 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7166 if i:
7175 if i:
7167 needsincoming = True
7176 needsincoming = True
7168 if o:
7177 if o:
7169 needsoutgoing = True
7178 needsoutgoing = True
7170 if not needsincoming and not needsoutgoing:
7179 if not needsincoming and not needsoutgoing:
7171 return
7180 return
7172
7181
7173 def getincoming():
7182 def getincoming():
7174 source, branches = hg.parseurl(ui.expandpath(b'default'))
7183 source, branches = hg.parseurl(ui.expandpath(b'default'))
7175 sbranch = branches[0]
7184 sbranch = branches[0]
7176 try:
7185 try:
7177 other = hg.peer(repo, {}, source)
7186 other = hg.peer(repo, {}, source)
7178 except error.RepoError:
7187 except error.RepoError:
7179 if opts.get(b'remote'):
7188 if opts.get(b'remote'):
7180 raise
7189 raise
7181 return source, sbranch, None, None, None
7190 return source, sbranch, None, None, None
7182 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7191 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7183 if revs:
7192 if revs:
7184 revs = [other.lookup(rev) for rev in revs]
7193 revs = [other.lookup(rev) for rev in revs]
7185 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7194 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7186 repo.ui.pushbuffer()
7195 repo.ui.pushbuffer()
7187 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7196 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7188 repo.ui.popbuffer()
7197 repo.ui.popbuffer()
7189 return source, sbranch, other, commoninc, commoninc[1]
7198 return source, sbranch, other, commoninc, commoninc[1]
7190
7199
7191 if needsincoming:
7200 if needsincoming:
7192 source, sbranch, sother, commoninc, incoming = getincoming()
7201 source, sbranch, sother, commoninc, incoming = getincoming()
7193 else:
7202 else:
7194 source = sbranch = sother = commoninc = incoming = None
7203 source = sbranch = sother = commoninc = incoming = None
7195
7204
7196 def getoutgoing():
7205 def getoutgoing():
7197 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7206 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7198 dbranch = branches[0]
7207 dbranch = branches[0]
7199 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7208 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7200 if source != dest:
7209 if source != dest:
7201 try:
7210 try:
7202 dother = hg.peer(repo, {}, dest)
7211 dother = hg.peer(repo, {}, dest)
7203 except error.RepoError:
7212 except error.RepoError:
7204 if opts.get(b'remote'):
7213 if opts.get(b'remote'):
7205 raise
7214 raise
7206 return dest, dbranch, None, None
7215 return dest, dbranch, None, None
7207 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7216 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7208 elif sother is None:
7217 elif sother is None:
7209 # there is no explicit destination peer, but source one is invalid
7218 # there is no explicit destination peer, but source one is invalid
7210 return dest, dbranch, None, None
7219 return dest, dbranch, None, None
7211 else:
7220 else:
7212 dother = sother
7221 dother = sother
7213 if source != dest or (sbranch is not None and sbranch != dbranch):
7222 if source != dest or (sbranch is not None and sbranch != dbranch):
7214 common = None
7223 common = None
7215 else:
7224 else:
7216 common = commoninc
7225 common = commoninc
7217 if revs:
7226 if revs:
7218 revs = [repo.lookup(rev) for rev in revs]
7227 revs = [repo.lookup(rev) for rev in revs]
7219 repo.ui.pushbuffer()
7228 repo.ui.pushbuffer()
7220 outgoing = discovery.findcommonoutgoing(
7229 outgoing = discovery.findcommonoutgoing(
7221 repo, dother, onlyheads=revs, commoninc=common
7230 repo, dother, onlyheads=revs, commoninc=common
7222 )
7231 )
7223 repo.ui.popbuffer()
7232 repo.ui.popbuffer()
7224 return dest, dbranch, dother, outgoing
7233 return dest, dbranch, dother, outgoing
7225
7234
7226 if needsoutgoing:
7235 if needsoutgoing:
7227 dest, dbranch, dother, outgoing = getoutgoing()
7236 dest, dbranch, dother, outgoing = getoutgoing()
7228 else:
7237 else:
7229 dest = dbranch = dother = outgoing = None
7238 dest = dbranch = dother = outgoing = None
7230
7239
7231 if opts.get(b'remote'):
7240 if opts.get(b'remote'):
7232 t = []
7241 t = []
7233 if incoming:
7242 if incoming:
7234 t.append(_(b'1 or more incoming'))
7243 t.append(_(b'1 or more incoming'))
7235 o = outgoing.missing
7244 o = outgoing.missing
7236 if o:
7245 if o:
7237 t.append(_(b'%d outgoing') % len(o))
7246 t.append(_(b'%d outgoing') % len(o))
7238 other = dother or sother
7247 other = dother or sother
7239 if b'bookmarks' in other.listkeys(b'namespaces'):
7248 if b'bookmarks' in other.listkeys(b'namespaces'):
7240 counts = bookmarks.summary(repo, other)
7249 counts = bookmarks.summary(repo, other)
7241 if counts[0] > 0:
7250 if counts[0] > 0:
7242 t.append(_(b'%d incoming bookmarks') % counts[0])
7251 t.append(_(b'%d incoming bookmarks') % counts[0])
7243 if counts[1] > 0:
7252 if counts[1] > 0:
7244 t.append(_(b'%d outgoing bookmarks') % counts[1])
7253 t.append(_(b'%d outgoing bookmarks') % counts[1])
7245
7254
7246 if t:
7255 if t:
7247 # i18n: column positioning for "hg summary"
7256 # i18n: column positioning for "hg summary"
7248 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7257 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7249 else:
7258 else:
7250 # i18n: column positioning for "hg summary"
7259 # i18n: column positioning for "hg summary"
7251 ui.status(_(b'remote: (synced)\n'))
7260 ui.status(_(b'remote: (synced)\n'))
7252
7261
7253 cmdutil.summaryremotehooks(
7262 cmdutil.summaryremotehooks(
7254 ui,
7263 ui,
7255 repo,
7264 repo,
7256 opts,
7265 opts,
7257 (
7266 (
7258 (source, sbranch, sother, commoninc),
7267 (source, sbranch, sother, commoninc),
7259 (dest, dbranch, dother, outgoing),
7268 (dest, dbranch, dother, outgoing),
7260 ),
7269 ),
7261 )
7270 )
7262
7271
7263
7272
7264 @command(
7273 @command(
7265 b'tag',
7274 b'tag',
7266 [
7275 [
7267 (b'f', b'force', None, _(b'force tag')),
7276 (b'f', b'force', None, _(b'force tag')),
7268 (b'l', b'local', None, _(b'make the tag local')),
7277 (b'l', b'local', None, _(b'make the tag local')),
7269 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7278 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7270 (b'', b'remove', None, _(b'remove a tag')),
7279 (b'', b'remove', None, _(b'remove a tag')),
7271 # -l/--local is already there, commitopts cannot be used
7280 # -l/--local is already there, commitopts cannot be used
7272 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7281 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7273 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7282 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7274 ]
7283 ]
7275 + commitopts2,
7284 + commitopts2,
7276 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7285 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7277 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7286 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7278 )
7287 )
7279 def tag(ui, repo, name1, *names, **opts):
7288 def tag(ui, repo, name1, *names, **opts):
7280 """add one or more tags for the current or given revision
7289 """add one or more tags for the current or given revision
7281
7290
7282 Name a particular revision using <name>.
7291 Name a particular revision using <name>.
7283
7292
7284 Tags are used to name particular revisions of the repository and are
7293 Tags are used to name particular revisions of the repository and are
7285 very useful to compare different revisions, to go back to significant
7294 very useful to compare different revisions, to go back to significant
7286 earlier versions or to mark branch points as releases, etc. Changing
7295 earlier versions or to mark branch points as releases, etc. Changing
7287 an existing tag is normally disallowed; use -f/--force to override.
7296 an existing tag is normally disallowed; use -f/--force to override.
7288
7297
7289 If no revision is given, the parent of the working directory is
7298 If no revision is given, the parent of the working directory is
7290 used.
7299 used.
7291
7300
7292 To facilitate version control, distribution, and merging of tags,
7301 To facilitate version control, distribution, and merging of tags,
7293 they are stored as a file named ".hgtags" which is managed similarly
7302 they are stored as a file named ".hgtags" which is managed similarly
7294 to other project files and can be hand-edited if necessary. This
7303 to other project files and can be hand-edited if necessary. This
7295 also means that tagging creates a new commit. The file
7304 also means that tagging creates a new commit. The file
7296 ".hg/localtags" is used for local tags (not shared among
7305 ".hg/localtags" is used for local tags (not shared among
7297 repositories).
7306 repositories).
7298
7307
7299 Tag commits are usually made at the head of a branch. If the parent
7308 Tag commits are usually made at the head of a branch. If the parent
7300 of the working directory is not a branch head, :hg:`tag` aborts; use
7309 of the working directory is not a branch head, :hg:`tag` aborts; use
7301 -f/--force to force the tag commit to be based on a non-head
7310 -f/--force to force the tag commit to be based on a non-head
7302 changeset.
7311 changeset.
7303
7312
7304 See :hg:`help dates` for a list of formats valid for -d/--date.
7313 See :hg:`help dates` for a list of formats valid for -d/--date.
7305
7314
7306 Since tag names have priority over branch names during revision
7315 Since tag names have priority over branch names during revision
7307 lookup, using an existing branch name as a tag name is discouraged.
7316 lookup, using an existing branch name as a tag name is discouraged.
7308
7317
7309 Returns 0 on success.
7318 Returns 0 on success.
7310 """
7319 """
7311 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7320 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7312 opts = pycompat.byteskwargs(opts)
7321 opts = pycompat.byteskwargs(opts)
7313 with repo.wlock(), repo.lock():
7322 with repo.wlock(), repo.lock():
7314 rev_ = b"."
7323 rev_ = b"."
7315 names = [t.strip() for t in (name1,) + names]
7324 names = [t.strip() for t in (name1,) + names]
7316 if len(names) != len(set(names)):
7325 if len(names) != len(set(names)):
7317 raise error.InputError(_(b'tag names must be unique'))
7326 raise error.InputError(_(b'tag names must be unique'))
7318 for n in names:
7327 for n in names:
7319 scmutil.checknewlabel(repo, n, b'tag')
7328 scmutil.checknewlabel(repo, n, b'tag')
7320 if not n:
7329 if not n:
7321 raise error.InputError(
7330 raise error.InputError(
7322 _(b'tag names cannot consist entirely of whitespace')
7331 _(b'tag names cannot consist entirely of whitespace')
7323 )
7332 )
7324 if opts.get(b'rev'):
7333 if opts.get(b'rev'):
7325 rev_ = opts[b'rev']
7334 rev_ = opts[b'rev']
7326 message = opts.get(b'message')
7335 message = opts.get(b'message')
7327 if opts.get(b'remove'):
7336 if opts.get(b'remove'):
7328 if opts.get(b'local'):
7337 if opts.get(b'local'):
7329 expectedtype = b'local'
7338 expectedtype = b'local'
7330 else:
7339 else:
7331 expectedtype = b'global'
7340 expectedtype = b'global'
7332
7341
7333 for n in names:
7342 for n in names:
7334 if repo.tagtype(n) == b'global':
7343 if repo.tagtype(n) == b'global':
7335 alltags = tagsmod.findglobaltags(ui, repo)
7344 alltags = tagsmod.findglobaltags(ui, repo)
7336 if alltags[n][0] == nullid:
7345 if alltags[n][0] == nullid:
7337 raise error.InputError(
7346 raise error.InputError(
7338 _(b"tag '%s' is already removed") % n
7347 _(b"tag '%s' is already removed") % n
7339 )
7348 )
7340 if not repo.tagtype(n):
7349 if not repo.tagtype(n):
7341 raise error.InputError(_(b"tag '%s' does not exist") % n)
7350 raise error.InputError(_(b"tag '%s' does not exist") % n)
7342 if repo.tagtype(n) != expectedtype:
7351 if repo.tagtype(n) != expectedtype:
7343 if expectedtype == b'global':
7352 if expectedtype == b'global':
7344 raise error.InputError(
7353 raise error.InputError(
7345 _(b"tag '%s' is not a global tag") % n
7354 _(b"tag '%s' is not a global tag") % n
7346 )
7355 )
7347 else:
7356 else:
7348 raise error.InputError(
7357 raise error.InputError(
7349 _(b"tag '%s' is not a local tag") % n
7358 _(b"tag '%s' is not a local tag") % n
7350 )
7359 )
7351 rev_ = b'null'
7360 rev_ = b'null'
7352 if not message:
7361 if not message:
7353 # we don't translate commit messages
7362 # we don't translate commit messages
7354 message = b'Removed tag %s' % b', '.join(names)
7363 message = b'Removed tag %s' % b', '.join(names)
7355 elif not opts.get(b'force'):
7364 elif not opts.get(b'force'):
7356 for n in names:
7365 for n in names:
7357 if n in repo.tags():
7366 if n in repo.tags():
7358 raise error.InputError(
7367 raise error.InputError(
7359 _(b"tag '%s' already exists (use -f to force)") % n
7368 _(b"tag '%s' already exists (use -f to force)") % n
7360 )
7369 )
7361 if not opts.get(b'local'):
7370 if not opts.get(b'local'):
7362 p1, p2 = repo.dirstate.parents()
7371 p1, p2 = repo.dirstate.parents()
7363 if p2 != nullid:
7372 if p2 != nullid:
7364 raise error.StateError(_(b'uncommitted merge'))
7373 raise error.StateError(_(b'uncommitted merge'))
7365 bheads = repo.branchheads()
7374 bheads = repo.branchheads()
7366 if not opts.get(b'force') and bheads and p1 not in bheads:
7375 if not opts.get(b'force') and bheads and p1 not in bheads:
7367 raise error.InputError(
7376 raise error.InputError(
7368 _(
7377 _(
7369 b'working directory is not at a branch head '
7378 b'working directory is not at a branch head '
7370 b'(use -f to force)'
7379 b'(use -f to force)'
7371 )
7380 )
7372 )
7381 )
7373 node = scmutil.revsingle(repo, rev_).node()
7382 node = scmutil.revsingle(repo, rev_).node()
7374
7383
7375 if not message:
7384 if not message:
7376 # we don't translate commit messages
7385 # we don't translate commit messages
7377 message = b'Added tag %s for changeset %s' % (
7386 message = b'Added tag %s for changeset %s' % (
7378 b', '.join(names),
7387 b', '.join(names),
7379 short(node),
7388 short(node),
7380 )
7389 )
7381
7390
7382 date = opts.get(b'date')
7391 date = opts.get(b'date')
7383 if date:
7392 if date:
7384 date = dateutil.parsedate(date)
7393 date = dateutil.parsedate(date)
7385
7394
7386 if opts.get(b'remove'):
7395 if opts.get(b'remove'):
7387 editform = b'tag.remove'
7396 editform = b'tag.remove'
7388 else:
7397 else:
7389 editform = b'tag.add'
7398 editform = b'tag.add'
7390 editor = cmdutil.getcommiteditor(
7399 editor = cmdutil.getcommiteditor(
7391 editform=editform, **pycompat.strkwargs(opts)
7400 editform=editform, **pycompat.strkwargs(opts)
7392 )
7401 )
7393
7402
7394 # don't allow tagging the null rev
7403 # don't allow tagging the null rev
7395 if (
7404 if (
7396 not opts.get(b'remove')
7405 not opts.get(b'remove')
7397 and scmutil.revsingle(repo, rev_).rev() == nullrev
7406 and scmutil.revsingle(repo, rev_).rev() == nullrev
7398 ):
7407 ):
7399 raise error.InputError(_(b"cannot tag null revision"))
7408 raise error.InputError(_(b"cannot tag null revision"))
7400
7409
7401 tagsmod.tag(
7410 tagsmod.tag(
7402 repo,
7411 repo,
7403 names,
7412 names,
7404 node,
7413 node,
7405 message,
7414 message,
7406 opts.get(b'local'),
7415 opts.get(b'local'),
7407 opts.get(b'user'),
7416 opts.get(b'user'),
7408 date,
7417 date,
7409 editor=editor,
7418 editor=editor,
7410 )
7419 )
7411
7420
7412
7421
7413 @command(
7422 @command(
7414 b'tags',
7423 b'tags',
7415 formatteropts,
7424 formatteropts,
7416 b'',
7425 b'',
7417 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7426 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7418 intents={INTENT_READONLY},
7427 intents={INTENT_READONLY},
7419 )
7428 )
7420 def tags(ui, repo, **opts):
7429 def tags(ui, repo, **opts):
7421 """list repository tags
7430 """list repository tags
7422
7431
7423 This lists both regular and local tags. When the -v/--verbose
7432 This lists both regular and local tags. When the -v/--verbose
7424 switch is used, a third column "local" is printed for local tags.
7433 switch is used, a third column "local" is printed for local tags.
7425 When the -q/--quiet switch is used, only the tag name is printed.
7434 When the -q/--quiet switch is used, only the tag name is printed.
7426
7435
7427 .. container:: verbose
7436 .. container:: verbose
7428
7437
7429 Template:
7438 Template:
7430
7439
7431 The following keywords are supported in addition to the common template
7440 The following keywords are supported in addition to the common template
7432 keywords and functions such as ``{tag}``. See also
7441 keywords and functions such as ``{tag}``. See also
7433 :hg:`help templates`.
7442 :hg:`help templates`.
7434
7443
7435 :type: String. ``local`` for local tags.
7444 :type: String. ``local`` for local tags.
7436
7445
7437 Returns 0 on success.
7446 Returns 0 on success.
7438 """
7447 """
7439
7448
7440 opts = pycompat.byteskwargs(opts)
7449 opts = pycompat.byteskwargs(opts)
7441 ui.pager(b'tags')
7450 ui.pager(b'tags')
7442 fm = ui.formatter(b'tags', opts)
7451 fm = ui.formatter(b'tags', opts)
7443 hexfunc = fm.hexfunc
7452 hexfunc = fm.hexfunc
7444
7453
7445 for t, n in reversed(repo.tagslist()):
7454 for t, n in reversed(repo.tagslist()):
7446 hn = hexfunc(n)
7455 hn = hexfunc(n)
7447 label = b'tags.normal'
7456 label = b'tags.normal'
7448 tagtype = repo.tagtype(t)
7457 tagtype = repo.tagtype(t)
7449 if not tagtype or tagtype == b'global':
7458 if not tagtype or tagtype == b'global':
7450 tagtype = b''
7459 tagtype = b''
7451 else:
7460 else:
7452 label = b'tags.' + tagtype
7461 label = b'tags.' + tagtype
7453
7462
7454 fm.startitem()
7463 fm.startitem()
7455 fm.context(repo=repo)
7464 fm.context(repo=repo)
7456 fm.write(b'tag', b'%s', t, label=label)
7465 fm.write(b'tag', b'%s', t, label=label)
7457 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7466 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7458 fm.condwrite(
7467 fm.condwrite(
7459 not ui.quiet,
7468 not ui.quiet,
7460 b'rev node',
7469 b'rev node',
7461 fmt,
7470 fmt,
7462 repo.changelog.rev(n),
7471 repo.changelog.rev(n),
7463 hn,
7472 hn,
7464 label=label,
7473 label=label,
7465 )
7474 )
7466 fm.condwrite(
7475 fm.condwrite(
7467 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7476 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7468 )
7477 )
7469 fm.plain(b'\n')
7478 fm.plain(b'\n')
7470 fm.end()
7479 fm.end()
7471
7480
7472
7481
7473 @command(
7482 @command(
7474 b'tip',
7483 b'tip',
7475 [
7484 [
7476 (b'p', b'patch', None, _(b'show patch')),
7485 (b'p', b'patch', None, _(b'show patch')),
7477 (b'g', b'git', None, _(b'use git extended diff format')),
7486 (b'g', b'git', None, _(b'use git extended diff format')),
7478 ]
7487 ]
7479 + templateopts,
7488 + templateopts,
7480 _(b'[-p] [-g]'),
7489 _(b'[-p] [-g]'),
7481 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7490 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7482 )
7491 )
7483 def tip(ui, repo, **opts):
7492 def tip(ui, repo, **opts):
7484 """show the tip revision (DEPRECATED)
7493 """show the tip revision (DEPRECATED)
7485
7494
7486 The tip revision (usually just called the tip) is the changeset
7495 The tip revision (usually just called the tip) is the changeset
7487 most recently added to the repository (and therefore the most
7496 most recently added to the repository (and therefore the most
7488 recently changed head).
7497 recently changed head).
7489
7498
7490 If you have just made a commit, that commit will be the tip. If
7499 If you have just made a commit, that commit will be the tip. If
7491 you have just pulled changes from another repository, the tip of
7500 you have just pulled changes from another repository, the tip of
7492 that repository becomes the current tip. The "tip" tag is special
7501 that repository becomes the current tip. The "tip" tag is special
7493 and cannot be renamed or assigned to a different changeset.
7502 and cannot be renamed or assigned to a different changeset.
7494
7503
7495 This command is deprecated, please use :hg:`heads` instead.
7504 This command is deprecated, please use :hg:`heads` instead.
7496
7505
7497 Returns 0 on success.
7506 Returns 0 on success.
7498 """
7507 """
7499 opts = pycompat.byteskwargs(opts)
7508 opts = pycompat.byteskwargs(opts)
7500 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7509 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7501 displayer.show(repo[b'tip'])
7510 displayer.show(repo[b'tip'])
7502 displayer.close()
7511 displayer.close()
7503
7512
7504
7513
7505 @command(
7514 @command(
7506 b'unbundle',
7515 b'unbundle',
7507 [
7516 [
7508 (
7517 (
7509 b'u',
7518 b'u',
7510 b'update',
7519 b'update',
7511 None,
7520 None,
7512 _(b'update to new branch head if changesets were unbundled'),
7521 _(b'update to new branch head if changesets were unbundled'),
7513 )
7522 )
7514 ],
7523 ],
7515 _(b'[-u] FILE...'),
7524 _(b'[-u] FILE...'),
7516 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7525 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7517 )
7526 )
7518 def unbundle(ui, repo, fname1, *fnames, **opts):
7527 def unbundle(ui, repo, fname1, *fnames, **opts):
7519 """apply one or more bundle files
7528 """apply one or more bundle files
7520
7529
7521 Apply one or more bundle files generated by :hg:`bundle`.
7530 Apply one or more bundle files generated by :hg:`bundle`.
7522
7531
7523 Returns 0 on success, 1 if an update has unresolved files.
7532 Returns 0 on success, 1 if an update has unresolved files.
7524 """
7533 """
7525 fnames = (fname1,) + fnames
7534 fnames = (fname1,) + fnames
7526
7535
7527 with repo.lock():
7536 with repo.lock():
7528 for fname in fnames:
7537 for fname in fnames:
7529 f = hg.openpath(ui, fname)
7538 f = hg.openpath(ui, fname)
7530 gen = exchange.readbundle(ui, f, fname)
7539 gen = exchange.readbundle(ui, f, fname)
7531 if isinstance(gen, streamclone.streamcloneapplier):
7540 if isinstance(gen, streamclone.streamcloneapplier):
7532 raise error.InputError(
7541 raise error.InputError(
7533 _(
7542 _(
7534 b'packed bundles cannot be applied with '
7543 b'packed bundles cannot be applied with '
7535 b'"hg unbundle"'
7544 b'"hg unbundle"'
7536 ),
7545 ),
7537 hint=_(b'use "hg debugapplystreamclonebundle"'),
7546 hint=_(b'use "hg debugapplystreamclonebundle"'),
7538 )
7547 )
7539 url = b'bundle:' + fname
7548 url = b'bundle:' + fname
7540 try:
7549 try:
7541 txnname = b'unbundle'
7550 txnname = b'unbundle'
7542 if not isinstance(gen, bundle2.unbundle20):
7551 if not isinstance(gen, bundle2.unbundle20):
7543 txnname = b'unbundle\n%s' % util.hidepassword(url)
7552 txnname = b'unbundle\n%s' % util.hidepassword(url)
7544 with repo.transaction(txnname) as tr:
7553 with repo.transaction(txnname) as tr:
7545 op = bundle2.applybundle(
7554 op = bundle2.applybundle(
7546 repo, gen, tr, source=b'unbundle', url=url
7555 repo, gen, tr, source=b'unbundle', url=url
7547 )
7556 )
7548 except error.BundleUnknownFeatureError as exc:
7557 except error.BundleUnknownFeatureError as exc:
7549 raise error.Abort(
7558 raise error.Abort(
7550 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7559 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7551 hint=_(
7560 hint=_(
7552 b"see https://mercurial-scm.org/"
7561 b"see https://mercurial-scm.org/"
7553 b"wiki/BundleFeature for more "
7562 b"wiki/BundleFeature for more "
7554 b"information"
7563 b"information"
7555 ),
7564 ),
7556 )
7565 )
7557 modheads = bundle2.combinechangegroupresults(op)
7566 modheads = bundle2.combinechangegroupresults(op)
7558
7567
7559 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7568 if postincoming(ui, repo, modheads, opts.get('update'), None, None):
7560 return 1
7569 return 1
7561 else:
7570 else:
7562 return 0
7571 return 0
7563
7572
7564
7573
7565 @command(
7574 @command(
7566 b'unshelve',
7575 b'unshelve',
7567 [
7576 [
7568 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7577 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7569 (
7578 (
7570 b'c',
7579 b'c',
7571 b'continue',
7580 b'continue',
7572 None,
7581 None,
7573 _(b'continue an incomplete unshelve operation'),
7582 _(b'continue an incomplete unshelve operation'),
7574 ),
7583 ),
7575 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7584 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7576 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7585 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7577 (
7586 (
7578 b'n',
7587 b'n',
7579 b'name',
7588 b'name',
7580 b'',
7589 b'',
7581 _(b'restore shelved change with given name'),
7590 _(b'restore shelved change with given name'),
7582 _(b'NAME'),
7591 _(b'NAME'),
7583 ),
7592 ),
7584 (b't', b'tool', b'', _(b'specify merge tool')),
7593 (b't', b'tool', b'', _(b'specify merge tool')),
7585 (
7594 (
7586 b'',
7595 b'',
7587 b'date',
7596 b'date',
7588 b'',
7597 b'',
7589 _(b'set date for temporary commits (DEPRECATED)'),
7598 _(b'set date for temporary commits (DEPRECATED)'),
7590 _(b'DATE'),
7599 _(b'DATE'),
7591 ),
7600 ),
7592 ],
7601 ],
7593 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7602 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7594 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7603 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7595 )
7604 )
7596 def unshelve(ui, repo, *shelved, **opts):
7605 def unshelve(ui, repo, *shelved, **opts):
7597 """restore a shelved change to the working directory
7606 """restore a shelved change to the working directory
7598
7607
7599 This command accepts an optional name of a shelved change to
7608 This command accepts an optional name of a shelved change to
7600 restore. If none is given, the most recent shelved change is used.
7609 restore. If none is given, the most recent shelved change is used.
7601
7610
7602 If a shelved change is applied successfully, the bundle that
7611 If a shelved change is applied successfully, the bundle that
7603 contains the shelved changes is moved to a backup location
7612 contains the shelved changes is moved to a backup location
7604 (.hg/shelve-backup).
7613 (.hg/shelve-backup).
7605
7614
7606 Since you can restore a shelved change on top of an arbitrary
7615 Since you can restore a shelved change on top of an arbitrary
7607 commit, it is possible that unshelving will result in a conflict
7616 commit, it is possible that unshelving will result in a conflict
7608 between your changes and the commits you are unshelving onto. If
7617 between your changes and the commits you are unshelving onto. If
7609 this occurs, you must resolve the conflict, then use
7618 this occurs, you must resolve the conflict, then use
7610 ``--continue`` to complete the unshelve operation. (The bundle
7619 ``--continue`` to complete the unshelve operation. (The bundle
7611 will not be moved until you successfully complete the unshelve.)
7620 will not be moved until you successfully complete the unshelve.)
7612
7621
7613 (Alternatively, you can use ``--abort`` to abandon an unshelve
7622 (Alternatively, you can use ``--abort`` to abandon an unshelve
7614 that causes a conflict. This reverts the unshelved changes, and
7623 that causes a conflict. This reverts the unshelved changes, and
7615 leaves the bundle in place.)
7624 leaves the bundle in place.)
7616
7625
7617 If bare shelved change (without interactive, include and exclude
7626 If bare shelved change (without interactive, include and exclude
7618 option) was done on newly created branch it would restore branch
7627 option) was done on newly created branch it would restore branch
7619 information to the working directory.
7628 information to the working directory.
7620
7629
7621 After a successful unshelve, the shelved changes are stored in a
7630 After a successful unshelve, the shelved changes are stored in a
7622 backup directory. Only the N most recent backups are kept. N
7631 backup directory. Only the N most recent backups are kept. N
7623 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7632 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7624 configuration option.
7633 configuration option.
7625
7634
7626 .. container:: verbose
7635 .. container:: verbose
7627
7636
7628 Timestamp in seconds is used to decide order of backups. More
7637 Timestamp in seconds is used to decide order of backups. More
7629 than ``maxbackups`` backups are kept, if same timestamp
7638 than ``maxbackups`` backups are kept, if same timestamp
7630 prevents from deciding exact order of them, for safety.
7639 prevents from deciding exact order of them, for safety.
7631
7640
7632 Selected changes can be unshelved with ``--interactive`` flag.
7641 Selected changes can be unshelved with ``--interactive`` flag.
7633 The working directory is updated with the selected changes, and
7642 The working directory is updated with the selected changes, and
7634 only the unselected changes remain shelved.
7643 only the unselected changes remain shelved.
7635 Note: The whole shelve is applied to working directory first before
7644 Note: The whole shelve is applied to working directory first before
7636 running interactively. So, this will bring up all the conflicts between
7645 running interactively. So, this will bring up all the conflicts between
7637 working directory and the shelve, irrespective of which changes will be
7646 working directory and the shelve, irrespective of which changes will be
7638 unshelved.
7647 unshelved.
7639 """
7648 """
7640 with repo.wlock():
7649 with repo.wlock():
7641 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7650 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7642
7651
7643
7652
7644 statemod.addunfinished(
7653 statemod.addunfinished(
7645 b'unshelve',
7654 b'unshelve',
7646 fname=b'shelvedstate',
7655 fname=b'shelvedstate',
7647 continueflag=True,
7656 continueflag=True,
7648 abortfunc=shelvemod.hgabortunshelve,
7657 abortfunc=shelvemod.hgabortunshelve,
7649 continuefunc=shelvemod.hgcontinueunshelve,
7658 continuefunc=shelvemod.hgcontinueunshelve,
7650 cmdmsg=_(b'unshelve already in progress'),
7659 cmdmsg=_(b'unshelve already in progress'),
7651 )
7660 )
7652
7661
7653
7662
7654 @command(
7663 @command(
7655 b'update|up|checkout|co',
7664 b'update|up|checkout|co',
7656 [
7665 [
7657 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7666 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7658 (b'c', b'check', None, _(b'require clean working directory')),
7667 (b'c', b'check', None, _(b'require clean working directory')),
7659 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7668 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7660 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7669 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7661 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7670 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7662 ]
7671 ]
7663 + mergetoolopts,
7672 + mergetoolopts,
7664 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7673 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7665 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7674 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7666 helpbasic=True,
7675 helpbasic=True,
7667 )
7676 )
7668 def update(ui, repo, node=None, **opts):
7677 def update(ui, repo, node=None, **opts):
7669 """update working directory (or switch revisions)
7678 """update working directory (or switch revisions)
7670
7679
7671 Update the repository's working directory to the specified
7680 Update the repository's working directory to the specified
7672 changeset. If no changeset is specified, update to the tip of the
7681 changeset. If no changeset is specified, update to the tip of the
7673 current named branch and move the active bookmark (see :hg:`help
7682 current named branch and move the active bookmark (see :hg:`help
7674 bookmarks`).
7683 bookmarks`).
7675
7684
7676 Update sets the working directory's parent revision to the specified
7685 Update sets the working directory's parent revision to the specified
7677 changeset (see :hg:`help parents`).
7686 changeset (see :hg:`help parents`).
7678
7687
7679 If the changeset is not a descendant or ancestor of the working
7688 If the changeset is not a descendant or ancestor of the working
7680 directory's parent and there are uncommitted changes, the update is
7689 directory's parent and there are uncommitted changes, the update is
7681 aborted. With the -c/--check option, the working directory is checked
7690 aborted. With the -c/--check option, the working directory is checked
7682 for uncommitted changes; if none are found, the working directory is
7691 for uncommitted changes; if none are found, the working directory is
7683 updated to the specified changeset.
7692 updated to the specified changeset.
7684
7693
7685 .. container:: verbose
7694 .. container:: verbose
7686
7695
7687 The -C/--clean, -c/--check, and -m/--merge options control what
7696 The -C/--clean, -c/--check, and -m/--merge options control what
7688 happens if the working directory contains uncommitted changes.
7697 happens if the working directory contains uncommitted changes.
7689 At most of one of them can be specified.
7698 At most of one of them can be specified.
7690
7699
7691 1. If no option is specified, and if
7700 1. If no option is specified, and if
7692 the requested changeset is an ancestor or descendant of
7701 the requested changeset is an ancestor or descendant of
7693 the working directory's parent, the uncommitted changes
7702 the working directory's parent, the uncommitted changes
7694 are merged into the requested changeset and the merged
7703 are merged into the requested changeset and the merged
7695 result is left uncommitted. If the requested changeset is
7704 result is left uncommitted. If the requested changeset is
7696 not an ancestor or descendant (that is, it is on another
7705 not an ancestor or descendant (that is, it is on another
7697 branch), the update is aborted and the uncommitted changes
7706 branch), the update is aborted and the uncommitted changes
7698 are preserved.
7707 are preserved.
7699
7708
7700 2. With the -m/--merge option, the update is allowed even if the
7709 2. With the -m/--merge option, the update is allowed even if the
7701 requested changeset is not an ancestor or descendant of
7710 requested changeset is not an ancestor or descendant of
7702 the working directory's parent.
7711 the working directory's parent.
7703
7712
7704 3. With the -c/--check option, the update is aborted and the
7713 3. With the -c/--check option, the update is aborted and the
7705 uncommitted changes are preserved.
7714 uncommitted changes are preserved.
7706
7715
7707 4. With the -C/--clean option, uncommitted changes are discarded and
7716 4. With the -C/--clean option, uncommitted changes are discarded and
7708 the working directory is updated to the requested changeset.
7717 the working directory is updated to the requested changeset.
7709
7718
7710 To cancel an uncommitted merge (and lose your changes), use
7719 To cancel an uncommitted merge (and lose your changes), use
7711 :hg:`merge --abort`.
7720 :hg:`merge --abort`.
7712
7721
7713 Use null as the changeset to remove the working directory (like
7722 Use null as the changeset to remove the working directory (like
7714 :hg:`clone -U`).
7723 :hg:`clone -U`).
7715
7724
7716 If you want to revert just one file to an older revision, use
7725 If you want to revert just one file to an older revision, use
7717 :hg:`revert [-r REV] NAME`.
7726 :hg:`revert [-r REV] NAME`.
7718
7727
7719 See :hg:`help dates` for a list of formats valid for -d/--date.
7728 See :hg:`help dates` for a list of formats valid for -d/--date.
7720
7729
7721 Returns 0 on success, 1 if there are unresolved files.
7730 Returns 0 on success, 1 if there are unresolved files.
7722 """
7731 """
7723 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7732 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7724 rev = opts.get('rev')
7733 rev = opts.get('rev')
7725 date = opts.get('date')
7734 date = opts.get('date')
7726 clean = opts.get('clean')
7735 clean = opts.get('clean')
7727 check = opts.get('check')
7736 check = opts.get('check')
7728 merge = opts.get('merge')
7737 merge = opts.get('merge')
7729 if rev and node:
7738 if rev and node:
7730 raise error.InputError(_(b"please specify just one revision"))
7739 raise error.InputError(_(b"please specify just one revision"))
7731
7740
7732 if ui.configbool(b'commands', b'update.requiredest'):
7741 if ui.configbool(b'commands', b'update.requiredest'):
7733 if not node and not rev and not date:
7742 if not node and not rev and not date:
7734 raise error.InputError(
7743 raise error.InputError(
7735 _(b'you must specify a destination'),
7744 _(b'you must specify a destination'),
7736 hint=_(b'for example: hg update ".::"'),
7745 hint=_(b'for example: hg update ".::"'),
7737 )
7746 )
7738
7747
7739 if rev is None or rev == b'':
7748 if rev is None or rev == b'':
7740 rev = node
7749 rev = node
7741
7750
7742 if date and rev is not None:
7751 if date and rev is not None:
7743 raise error.InputError(_(b"you can't specify a revision and a date"))
7752 raise error.InputError(_(b"you can't specify a revision and a date"))
7744
7753
7745 updatecheck = None
7754 updatecheck = None
7746 if check:
7755 if check:
7747 updatecheck = b'abort'
7756 updatecheck = b'abort'
7748 elif merge:
7757 elif merge:
7749 updatecheck = b'none'
7758 updatecheck = b'none'
7750
7759
7751 with repo.wlock():
7760 with repo.wlock():
7752 cmdutil.clearunfinished(repo)
7761 cmdutil.clearunfinished(repo)
7753 if date:
7762 if date:
7754 rev = cmdutil.finddate(ui, repo, date)
7763 rev = cmdutil.finddate(ui, repo, date)
7755
7764
7756 # if we defined a bookmark, we have to remember the original name
7765 # if we defined a bookmark, we have to remember the original name
7757 brev = rev
7766 brev = rev
7758 if rev:
7767 if rev:
7759 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7768 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7760 ctx = scmutil.revsingle(repo, rev, default=None)
7769 ctx = scmutil.revsingle(repo, rev, default=None)
7761 rev = ctx.rev()
7770 rev = ctx.rev()
7762 hidden = ctx.hidden()
7771 hidden = ctx.hidden()
7763 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7772 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7764 with ui.configoverride(overrides, b'update'):
7773 with ui.configoverride(overrides, b'update'):
7765 ret = hg.updatetotally(
7774 ret = hg.updatetotally(
7766 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7775 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7767 )
7776 )
7768 if hidden:
7777 if hidden:
7769 ctxstr = ctx.hex()[:12]
7778 ctxstr = ctx.hex()[:12]
7770 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7779 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7771
7780
7772 if ctx.obsolete():
7781 if ctx.obsolete():
7773 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7782 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7774 ui.warn(b"(%s)\n" % obsfatemsg)
7783 ui.warn(b"(%s)\n" % obsfatemsg)
7775 return ret
7784 return ret
7776
7785
7777
7786
7778 @command(
7787 @command(
7779 b'verify',
7788 b'verify',
7780 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7789 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7781 helpcategory=command.CATEGORY_MAINTENANCE,
7790 helpcategory=command.CATEGORY_MAINTENANCE,
7782 )
7791 )
7783 def verify(ui, repo, **opts):
7792 def verify(ui, repo, **opts):
7784 """verify the integrity of the repository
7793 """verify the integrity of the repository
7785
7794
7786 Verify the integrity of the current repository.
7795 Verify the integrity of the current repository.
7787
7796
7788 This will perform an extensive check of the repository's
7797 This will perform an extensive check of the repository's
7789 integrity, validating the hashes and checksums of each entry in
7798 integrity, validating the hashes and checksums of each entry in
7790 the changelog, manifest, and tracked files, as well as the
7799 the changelog, manifest, and tracked files, as well as the
7791 integrity of their crosslinks and indices.
7800 integrity of their crosslinks and indices.
7792
7801
7793 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7802 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7794 for more information about recovery from corruption of the
7803 for more information about recovery from corruption of the
7795 repository.
7804 repository.
7796
7805
7797 Returns 0 on success, 1 if errors are encountered.
7806 Returns 0 on success, 1 if errors are encountered.
7798 """
7807 """
7799 opts = pycompat.byteskwargs(opts)
7808 opts = pycompat.byteskwargs(opts)
7800
7809
7801 level = None
7810 level = None
7802 if opts[b'full']:
7811 if opts[b'full']:
7803 level = verifymod.VERIFY_FULL
7812 level = verifymod.VERIFY_FULL
7804 return hg.verify(repo, level)
7813 return hg.verify(repo, level)
7805
7814
7806
7815
7807 @command(
7816 @command(
7808 b'version',
7817 b'version',
7809 [] + formatteropts,
7818 [] + formatteropts,
7810 helpcategory=command.CATEGORY_HELP,
7819 helpcategory=command.CATEGORY_HELP,
7811 norepo=True,
7820 norepo=True,
7812 intents={INTENT_READONLY},
7821 intents={INTENT_READONLY},
7813 )
7822 )
7814 def version_(ui, **opts):
7823 def version_(ui, **opts):
7815 """output version and copyright information
7824 """output version and copyright information
7816
7825
7817 .. container:: verbose
7826 .. container:: verbose
7818
7827
7819 Template:
7828 Template:
7820
7829
7821 The following keywords are supported. See also :hg:`help templates`.
7830 The following keywords are supported. See also :hg:`help templates`.
7822
7831
7823 :extensions: List of extensions.
7832 :extensions: List of extensions.
7824 :ver: String. Version number.
7833 :ver: String. Version number.
7825
7834
7826 And each entry of ``{extensions}`` provides the following sub-keywords
7835 And each entry of ``{extensions}`` provides the following sub-keywords
7827 in addition to ``{ver}``.
7836 in addition to ``{ver}``.
7828
7837
7829 :bundled: Boolean. True if included in the release.
7838 :bundled: Boolean. True if included in the release.
7830 :name: String. Extension name.
7839 :name: String. Extension name.
7831 """
7840 """
7832 opts = pycompat.byteskwargs(opts)
7841 opts = pycompat.byteskwargs(opts)
7833 if ui.verbose:
7842 if ui.verbose:
7834 ui.pager(b'version')
7843 ui.pager(b'version')
7835 fm = ui.formatter(b"version", opts)
7844 fm = ui.formatter(b"version", opts)
7836 fm.startitem()
7845 fm.startitem()
7837 fm.write(
7846 fm.write(
7838 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7847 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7839 )
7848 )
7840 license = _(
7849 license = _(
7841 b"(see https://mercurial-scm.org for more information)\n"
7850 b"(see https://mercurial-scm.org for more information)\n"
7842 b"\nCopyright (C) 2005-2021 Matt Mackall and others\n"
7851 b"\nCopyright (C) 2005-2021 Matt Mackall and others\n"
7843 b"This is free software; see the source for copying conditions. "
7852 b"This is free software; see the source for copying conditions. "
7844 b"There is NO\nwarranty; "
7853 b"There is NO\nwarranty; "
7845 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7854 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7846 )
7855 )
7847 if not ui.quiet:
7856 if not ui.quiet:
7848 fm.plain(license)
7857 fm.plain(license)
7849
7858
7850 if ui.verbose:
7859 if ui.verbose:
7851 fm.plain(_(b"\nEnabled extensions:\n\n"))
7860 fm.plain(_(b"\nEnabled extensions:\n\n"))
7852 # format names and versions into columns
7861 # format names and versions into columns
7853 names = []
7862 names = []
7854 vers = []
7863 vers = []
7855 isinternals = []
7864 isinternals = []
7856 for name, module in sorted(extensions.extensions()):
7865 for name, module in sorted(extensions.extensions()):
7857 names.append(name)
7866 names.append(name)
7858 vers.append(extensions.moduleversion(module) or None)
7867 vers.append(extensions.moduleversion(module) or None)
7859 isinternals.append(extensions.ismoduleinternal(module))
7868 isinternals.append(extensions.ismoduleinternal(module))
7860 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7869 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7861 if names:
7870 if names:
7862 namefmt = b" %%-%ds " % max(len(n) for n in names)
7871 namefmt = b" %%-%ds " % max(len(n) for n in names)
7863 places = [_(b"external"), _(b"internal")]
7872 places = [_(b"external"), _(b"internal")]
7864 for n, v, p in zip(names, vers, isinternals):
7873 for n, v, p in zip(names, vers, isinternals):
7865 fn.startitem()
7874 fn.startitem()
7866 fn.condwrite(ui.verbose, b"name", namefmt, n)
7875 fn.condwrite(ui.verbose, b"name", namefmt, n)
7867 if ui.verbose:
7876 if ui.verbose:
7868 fn.plain(b"%s " % places[p])
7877 fn.plain(b"%s " % places[p])
7869 fn.data(bundled=p)
7878 fn.data(bundled=p)
7870 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7879 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7871 if ui.verbose:
7880 if ui.verbose:
7872 fn.plain(b"\n")
7881 fn.plain(b"\n")
7873 fn.end()
7882 fn.end()
7874 fm.end()
7883 fm.end()
7875
7884
7876
7885
7877 def loadcmdtable(ui, name, cmdtable):
7886 def loadcmdtable(ui, name, cmdtable):
7878 """Load command functions from specified cmdtable"""
7887 """Load command functions from specified cmdtable"""
7879 overrides = [cmd for cmd in cmdtable if cmd in table]
7888 overrides = [cmd for cmd in cmdtable if cmd in table]
7880 if overrides:
7889 if overrides:
7881 ui.warn(
7890 ui.warn(
7882 _(b"extension '%s' overrides commands: %s\n")
7891 _(b"extension '%s' overrides commands: %s\n")
7883 % (name, b" ".join(overrides))
7892 % (name, b" ".join(overrides))
7884 )
7893 )
7885 table.update(cmdtable)
7894 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now