Show More
@@ -155,3 +155,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6' | |||||
155 | 1e2454b60e5936f5e77498cab2648db469504487 0 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 |
@@ -168,3 +168,4 b' 2f427b57bf9019c6dc3750baa539dc22c1be50f6' | |||||
168 | 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc |
|
168 | 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc | |
169 | 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4 |
|
169 | 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4 | |
170 | cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1 |
|
170 | cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1 | |
|
171 | a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2 |
@@ -455,6 +455,7 b' def updatelfiles(ui, repo, filelist=None' | |||||
455 | lfiles = [f for f in lfiles if f in filelist] |
|
455 | lfiles = [f for f in lfiles if f in filelist] | |
456 |
|
456 | |||
457 | update = {} |
|
457 | update = {} | |
|
458 | dropped = set() | |||
458 | updated, removed = 0, 0 |
|
459 | updated, removed = 0, 0 | |
459 | wvfs = repo.wvfs |
|
460 | wvfs = repo.wvfs | |
460 | wctx = repo[None] |
|
461 | wctx = repo[None] | |
@@ -476,7 +477,11 b' def updatelfiles(ui, repo, filelist=None' | |||||
476 | expecthash = lfutil.readasstandin(wctx[relstandin]) |
|
477 | expecthash = lfutil.readasstandin(wctx[relstandin]) | |
477 | if expecthash != '': |
|
478 | if expecthash != '': | |
478 | if lfile not in wctx: # not switched to normal file |
|
479 | if lfile not in wctx: # not switched to normal file | |
479 | wvfs.unlinkpath(rellfile, ignoremissing=True) |
|
480 | if repo.dirstate[relstandin] != '?': | |
|
481 | wvfs.unlinkpath(rellfile, ignoremissing=True) | |||
|
482 | else: | |||
|
483 | dropped.add(rellfile) | |||
|
484 | ||||
480 | # use normallookup() to allocate an entry in largefiles |
|
485 | # use normallookup() to allocate an entry in largefiles | |
481 | # dirstate to prevent lfilesrepo.status() from reporting |
|
486 | # dirstate to prevent lfilesrepo.status() from reporting | |
482 | # missing files as removed. |
|
487 | # missing files as removed. | |
@@ -496,6 +501,15 b' def updatelfiles(ui, repo, filelist=None' | |||||
496 | lfdirstate.write() |
|
501 | lfdirstate.write() | |
497 |
|
502 | |||
498 | if lfiles: |
|
503 | if lfiles: | |
|
504 | lfiles = [f for f in lfiles if f not in dropped] | |||
|
505 | ||||
|
506 | for f in dropped: | |||
|
507 | repo.wvfs.unlinkpath(lfutil.standin(f)) | |||
|
508 | ||||
|
509 | # This needs to happen for dropped files, otherwise they stay in | |||
|
510 | # the M state. | |||
|
511 | lfutil.synclfdirstate(repo, lfdirstate, f, normallookup) | |||
|
512 | ||||
499 | statuswriter(_('getting changed largefiles\n')) |
|
513 | statuswriter(_('getting changed largefiles\n')) | |
500 | cachelfiles(ui, repo, None, lfiles) |
|
514 | cachelfiles(ui, repo, None, lfiles) | |
501 |
|
515 |
@@ -220,8 +220,17 b' def _loadnewui(srcui, args):' | |||||
220 | newui._csystem = srcui._csystem |
|
220 | newui._csystem = srcui._csystem | |
221 |
|
221 | |||
222 | # command line args |
|
222 | # command line args | |
223 | args = args[:] |
|
223 | options = {} | |
224 | dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args)) |
|
224 | if srcui.plain('strictflags'): | |
|
225 | options.update(dispatch._earlyparseopts(args)) | |||
|
226 | else: | |||
|
227 | args = args[:] | |||
|
228 | options['config'] = dispatch._earlygetopt(['--config'], args) | |||
|
229 | cwds = dispatch._earlygetopt(['--cwd'], args) | |||
|
230 | options['cwd'] = cwds and cwds[-1] or '' | |||
|
231 | rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) | |||
|
232 | options['repository'] = rpath and rpath[-1] or '' | |||
|
233 | dispatch._parseconfig(newui, options['config']) | |||
225 |
|
234 | |||
226 | # stolen from tortoisehg.util.copydynamicconfig() |
|
235 | # stolen from tortoisehg.util.copydynamicconfig() | |
227 | for section, name, value in srcui.walkconfig(): |
|
236 | for section, name, value in srcui.walkconfig(): | |
@@ -232,10 +241,9 b' def _loadnewui(srcui, args):' | |||||
232 | newui.setconfig(section, name, value, source) |
|
241 | newui.setconfig(section, name, value, source) | |
233 |
|
242 | |||
234 | # load wd and repo config, copied from dispatch.py |
|
243 | # load wd and repo config, copied from dispatch.py | |
235 | cwds = dispatch._earlygetopt(['--cwd'], args) |
|
244 | cwd = options['cwd'] | |
236 |
cwd = cwd |
|
245 | cwd = cwd and os.path.realpath(cwd) or None | |
237 | rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args) |
|
246 | rpath = options['repository'] | |
238 | rpath = rpath and rpath[-1] or '' |
|
|||
239 | path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) |
|
247 | path, newlui = dispatch._getlocal(newui, rpath, wd=cwd) | |
240 |
|
248 | |||
241 | return (newui, newlui) |
|
249 | return (newui, newlui) |
@@ -150,6 +150,8 b' def dispatch(req):' | |||||
150 | try: |
|
150 | try: | |
151 | if not req.ui: |
|
151 | if not req.ui: | |
152 | req.ui = uimod.ui.load() |
|
152 | req.ui = uimod.ui.load() | |
|
153 | if req.ui.plain('strictflags'): | |||
|
154 | req.earlyoptions.update(_earlyparseopts(req.args)) | |||
153 | if _earlyreqoptbool(req, 'traceback', ['--traceback']): |
|
155 | if _earlyreqoptbool(req, 'traceback', ['--traceback']): | |
154 | req.ui.setconfig('ui', 'traceback', 'on', '--traceback') |
|
156 | req.ui.setconfig('ui', 'traceback', 'on', '--traceback') | |
155 |
|
157 | |||
@@ -644,6 +646,12 b' def _parseconfig(ui, config):' | |||||
644 |
|
646 | |||
645 | return configs |
|
647 | return configs | |
646 |
|
648 | |||
|
649 | def _earlyparseopts(args): | |||
|
650 | options = {} | |||
|
651 | fancyopts.fancyopts(args, commands.globalopts, options, | |||
|
652 | gnu=False, early=True) | |||
|
653 | return options | |||
|
654 | ||||
647 | def _earlygetopt(aliases, args, strip=True): |
|
655 | def _earlygetopt(aliases, args, strip=True): | |
648 | """Return list of values for an option (or aliases). |
|
656 | """Return list of values for an option (or aliases). | |
649 |
|
657 | |||
@@ -732,12 +740,16 b' def _earlygetopt(aliases, args, strip=Tr' | |||||
732 |
|
740 | |||
733 | def _earlyreqopt(req, name, aliases): |
|
741 | def _earlyreqopt(req, name, aliases): | |
734 | """Peek a list option without using a full options table""" |
|
742 | """Peek a list option without using a full options table""" | |
|
743 | if req.ui.plain('strictflags'): | |||
|
744 | return req.earlyoptions[name] | |||
735 | values = _earlygetopt(aliases, req.args, strip=False) |
|
745 | values = _earlygetopt(aliases, req.args, strip=False) | |
736 | req.earlyoptions[name] = values |
|
746 | req.earlyoptions[name] = values | |
737 | return values |
|
747 | return values | |
738 |
|
748 | |||
739 | def _earlyreqoptstr(req, name, aliases): |
|
749 | def _earlyreqoptstr(req, name, aliases): | |
740 | """Peek a string option without using a full options table""" |
|
750 | """Peek a string option without using a full options table""" | |
|
751 | if req.ui.plain('strictflags'): | |||
|
752 | return req.earlyoptions[name] | |||
741 | value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] |
|
753 | value = (_earlygetopt(aliases, req.args, strip=False) or [''])[-1] | |
742 | req.earlyoptions[name] = value |
|
754 | req.earlyoptions[name] = value | |
743 | return value |
|
755 | return value | |
@@ -745,13 +757,15 b' def _earlyreqoptstr(req, name, aliases):' | |||||
745 | def _earlyreqoptbool(req, name, aliases): |
|
757 | def _earlyreqoptbool(req, name, aliases): | |
746 | """Peek a boolean option without using a full options table |
|
758 | """Peek a boolean option without using a full options table | |
747 |
|
759 | |||
748 | >>> req = request([b'x', b'--debugger']) |
|
760 | >>> req = request([b'x', b'--debugger'], uimod.ui()) | |
749 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
761 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) | |
750 | True |
|
762 | True | |
751 |
|
763 | |||
752 | >>> req = request([b'x', b'--', b'--debugger']) |
|
764 | >>> req = request([b'x', b'--', b'--debugger'], uimod.ui()) | |
753 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) |
|
765 | >>> _earlyreqoptbool(req, b'debugger', [b'--debugger']) | |
754 | """ |
|
766 | """ | |
|
767 | if req.ui.plain('strictflags'): | |||
|
768 | return req.earlyoptions[name] | |||
755 | try: |
|
769 | try: | |
756 | argcount = req.args.index("--") |
|
770 | argcount = req.args.index("--") | |
757 | except ValueError: |
|
771 | except ValueError: |
@@ -7,6 +7,8 b'' | |||||
7 |
|
7 | |||
8 | from __future__ import absolute_import |
|
8 | from __future__ import absolute_import | |
9 |
|
9 | |||
|
10 | import functools | |||
|
11 | ||||
10 | from .i18n import _ |
|
12 | from .i18n import _ | |
11 | from . import ( |
|
13 | from . import ( | |
12 | error, |
|
14 | error, | |
@@ -24,6 +26,179 b' nevernegate = {' | |||||
24 | 'version', |
|
26 | 'version', | |
25 | } |
|
27 | } | |
26 |
|
28 | |||
|
29 | def _earlyoptarg(arg, shortlist, namelist): | |||
|
30 | """Check if the given arg is a valid unabbreviated option | |||
|
31 | ||||
|
32 | Returns (flag_str, has_embedded_value?, embedded_value, takes_value?) | |||
|
33 | ||||
|
34 | >>> def opt(arg): | |||
|
35 | ... return _earlyoptarg(arg, b'R:q', [b'cwd=', b'debugger']) | |||
|
36 | ||||
|
37 | long form: | |||
|
38 | ||||
|
39 | >>> opt(b'--cwd') | |||
|
40 | ('--cwd', False, '', True) | |||
|
41 | >>> opt(b'--cwd=') | |||
|
42 | ('--cwd', True, '', True) | |||
|
43 | >>> opt(b'--cwd=foo') | |||
|
44 | ('--cwd', True, 'foo', True) | |||
|
45 | >>> opt(b'--debugger') | |||
|
46 | ('--debugger', False, '', False) | |||
|
47 | >>> opt(b'--debugger=') # invalid but parsable | |||
|
48 | ('--debugger', True, '', False) | |||
|
49 | ||||
|
50 | short form: | |||
|
51 | ||||
|
52 | >>> opt(b'-R') | |||
|
53 | ('-R', False, '', True) | |||
|
54 | >>> opt(b'-Rfoo') | |||
|
55 | ('-R', True, 'foo', True) | |||
|
56 | >>> opt(b'-q') | |||
|
57 | ('-q', False, '', False) | |||
|
58 | >>> opt(b'-qfoo') # invalid but parsable | |||
|
59 | ('-q', True, 'foo', False) | |||
|
60 | ||||
|
61 | unknown or invalid: | |||
|
62 | ||||
|
63 | >>> opt(b'--unknown') | |||
|
64 | ('', False, '', False) | |||
|
65 | >>> opt(b'-u') | |||
|
66 | ('', False, '', False) | |||
|
67 | >>> opt(b'-ufoo') | |||
|
68 | ('', False, '', False) | |||
|
69 | >>> opt(b'--') | |||
|
70 | ('', False, '', False) | |||
|
71 | >>> opt(b'-') | |||
|
72 | ('', False, '', False) | |||
|
73 | >>> opt(b'-:') | |||
|
74 | ('', False, '', False) | |||
|
75 | >>> opt(b'-:foo') | |||
|
76 | ('', False, '', False) | |||
|
77 | """ | |||
|
78 | if arg.startswith('--'): | |||
|
79 | flag, eq, val = arg.partition('=') | |||
|
80 | if flag[2:] in namelist: | |||
|
81 | return flag, bool(eq), val, False | |||
|
82 | if flag[2:] + '=' in namelist: | |||
|
83 | return flag, bool(eq), val, True | |||
|
84 | elif arg.startswith('-') and arg != '-' and not arg.startswith('-:'): | |||
|
85 | flag, val = arg[:2], arg[2:] | |||
|
86 | i = shortlist.find(flag[1:]) | |||
|
87 | if i >= 0: | |||
|
88 | return flag, bool(val), val, shortlist.startswith(':', i + 1) | |||
|
89 | return '', False, '', False | |||
|
90 | ||||
|
91 | def earlygetopt(args, shortlist, namelist, gnu=False, keepsep=False): | |||
|
92 | """Parse options like getopt, but ignores unknown options and abbreviated | |||
|
93 | forms | |||
|
94 | ||||
|
95 | If gnu=False, this stops processing options as soon as a non/unknown-option | |||
|
96 | argument is encountered. Otherwise, option and non-option arguments may be | |||
|
97 | intermixed, and unknown-option arguments are taken as non-option. | |||
|
98 | ||||
|
99 | If keepsep=True, '--' won't be removed from the list of arguments left. | |||
|
100 | This is useful for stripping early options from a full command arguments. | |||
|
101 | ||||
|
102 | >>> def get(args, gnu=False, keepsep=False): | |||
|
103 | ... return earlygetopt(args, b'R:q', [b'cwd=', b'debugger'], | |||
|
104 | ... gnu=gnu, keepsep=keepsep) | |||
|
105 | ||||
|
106 | default parsing rules for early options: | |||
|
107 | ||||
|
108 | >>> get([b'x', b'--cwd', b'foo', b'-Rbar', b'-q', b'y'], gnu=True) | |||
|
109 | ([('--cwd', 'foo'), ('-R', 'bar'), ('-q', '')], ['x', 'y']) | |||
|
110 | >>> get([b'x', b'--cwd=foo', b'y', b'-R', b'bar', b'--debugger'], gnu=True) | |||
|
111 | ([('--cwd', 'foo'), ('-R', 'bar'), ('--debugger', '')], ['x', 'y']) | |||
|
112 | >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=True) | |||
|
113 | ([('--cwd', 'foo')], ['--unknown', '--debugger']) | |||
|
114 | ||||
|
115 | restricted parsing rules (early options must come first): | |||
|
116 | ||||
|
117 | >>> get([b'--cwd', b'foo', b'-Rbar', b'x', b'-q', b'y'], gnu=False) | |||
|
118 | ([('--cwd', 'foo'), ('-R', 'bar')], ['x', '-q', 'y']) | |||
|
119 | >>> get([b'--cwd=foo', b'x', b'y', b'-R', b'bar', b'--debugger'], gnu=False) | |||
|
120 | ([('--cwd', 'foo')], ['x', 'y', '-R', 'bar', '--debugger']) | |||
|
121 | >>> get([b'--unknown', b'--cwd=foo', b'--', '--debugger'], gnu=False) | |||
|
122 | ([], ['--unknown', '--cwd=foo', '--debugger']) | |||
|
123 | ||||
|
124 | stripping early options (without loosing '--'): | |||
|
125 | ||||
|
126 | >>> get([b'x', b'-Rbar', b'--', '--debugger'], gnu=True, keepsep=True)[1] | |||
|
127 | ['x', '--', '--debugger'] | |||
|
128 | ||||
|
129 | last argument: | |||
|
130 | ||||
|
131 | >>> get([b'--cwd']) | |||
|
132 | ([], ['--cwd']) | |||
|
133 | >>> get([b'--cwd=foo']) | |||
|
134 | ([('--cwd', 'foo')], []) | |||
|
135 | >>> get([b'-R']) | |||
|
136 | ([], ['-R']) | |||
|
137 | >>> get([b'-Rbar']) | |||
|
138 | ([('-R', 'bar')], []) | |||
|
139 | >>> get([b'-q']) | |||
|
140 | ([('-q', '')], []) | |||
|
141 | >>> get([b'-q', b'--']) | |||
|
142 | ([('-q', '')], []) | |||
|
143 | ||||
|
144 | value passed to bool options: | |||
|
145 | ||||
|
146 | >>> get([b'--debugger=foo', b'x']) | |||
|
147 | ([], ['--debugger=foo', 'x']) | |||
|
148 | >>> get([b'-qfoo', b'x']) | |||
|
149 | ([], ['-qfoo', 'x']) | |||
|
150 | ||||
|
151 | short option isn't separated with '=': | |||
|
152 | ||||
|
153 | >>> get([b'-R=bar']) | |||
|
154 | ([('-R', '=bar')], []) | |||
|
155 | ||||
|
156 | ':' may be in shortlist, but shouldn't be taken as an option letter: | |||
|
157 | ||||
|
158 | >>> get([b'-:', b'y']) | |||
|
159 | ([], ['-:', 'y']) | |||
|
160 | ||||
|
161 | '-' is a valid non-option argument: | |||
|
162 | ||||
|
163 | >>> get([b'-', b'y']) | |||
|
164 | ([], ['-', 'y']) | |||
|
165 | """ | |||
|
166 | # ignoring everything just after '--' isn't correct as '--' may be an | |||
|
167 | # option value (e.g. ['-R', '--']), but we do that consistently. | |||
|
168 | try: | |||
|
169 | argcount = args.index('--') | |||
|
170 | except ValueError: | |||
|
171 | argcount = len(args) | |||
|
172 | ||||
|
173 | parsedopts = [] | |||
|
174 | parsedargs = [] | |||
|
175 | pos = 0 | |||
|
176 | while pos < argcount: | |||
|
177 | arg = args[pos] | |||
|
178 | flag, hasval, val, takeval = _earlyoptarg(arg, shortlist, namelist) | |||
|
179 | if not hasval and takeval and pos + 1 >= argcount: | |||
|
180 | # missing last argument | |||
|
181 | break | |||
|
182 | if not flag or hasval and not takeval: | |||
|
183 | # non-option argument or -b/--bool=INVALID_VALUE | |||
|
184 | if gnu: | |||
|
185 | parsedargs.append(arg) | |||
|
186 | pos += 1 | |||
|
187 | else: | |||
|
188 | break | |||
|
189 | elif hasval == takeval: | |||
|
190 | # -b/--bool or -s/--str=VALUE | |||
|
191 | parsedopts.append((flag, val)) | |||
|
192 | pos += 1 | |||
|
193 | else: | |||
|
194 | # -s/--str VALUE | |||
|
195 | parsedopts.append((flag, args[pos + 1])) | |||
|
196 | pos += 2 | |||
|
197 | ||||
|
198 | parsedargs.extend(args[pos:argcount]) | |||
|
199 | parsedargs.extend(args[argcount + (not keepsep):]) | |||
|
200 | return parsedopts, parsedargs | |||
|
201 | ||||
27 | def gnugetopt(args, options, longoptions): |
|
202 | def gnugetopt(args, options, longoptions): | |
28 | """Parse options mostly like getopt.gnu_getopt. |
|
203 | """Parse options mostly like getopt.gnu_getopt. | |
29 |
|
204 | |||
@@ -51,7 +226,7 b' def gnugetopt(args, options, longoptions' | |||||
51 | return opts, args |
|
226 | return opts, args | |
52 |
|
227 | |||
53 |
|
228 | |||
54 | def fancyopts(args, options, state, gnu=False): |
|
229 | def fancyopts(args, options, state, gnu=False, early=False): | |
55 | """ |
|
230 | """ | |
56 | read args, parse options, and store options in state |
|
231 | read args, parse options, and store options in state | |
57 |
|
232 | |||
@@ -124,7 +299,9 b' def fancyopts(args, options, state, gnu=' | |||||
124 | namelist.append(oname) |
|
299 | namelist.append(oname) | |
125 |
|
300 | |||
126 | # parse arguments |
|
301 | # parse arguments | |
127 |
if |
|
302 | if early: | |
|
303 | parse = functools.partial(earlygetopt, gnu=gnu) | |||
|
304 | elif gnu: | |||
128 | parse = gnugetopt |
|
305 | parse = gnugetopt | |
129 | else: |
|
306 | else: | |
130 | parse = pycompat.getoptb |
|
307 | parse = pycompat.getoptb |
@@ -56,9 +56,17 b' HGPLAIN' | |||||
56 | localization. This can be useful when scripting against Mercurial |
|
56 | localization. This can be useful when scripting against Mercurial | |
57 | in the face of existing user configuration. |
|
57 | in the face of existing user configuration. | |
58 |
|
58 | |||
|
59 | In addition to the features disabled by ``HGPLAIN=``, the following | |||
|
60 | values can be specified to adjust behavior: | |||
|
61 | ||||
|
62 | ``+strictflags`` | |||
|
63 | Restrict parsing of command line flags. | |||
|
64 | ||||
59 | Equivalent options set via command line flags or environment |
|
65 | Equivalent options set via command line flags or environment | |
60 | variables are not overridden. |
|
66 | variables are not overridden. | |
61 |
|
67 | |||
|
68 | See :hg:`help scripting` for details. | |||
|
69 | ||||
62 | HGPLAINEXCEPT |
|
70 | HGPLAINEXCEPT | |
63 | This is a comma-separated list of features to preserve when |
|
71 | This is a comma-separated list of features to preserve when | |
64 | HGPLAIN is enabled. Currently the following values are supported: |
|
72 | HGPLAIN is enabled. Currently the following values are supported: |
@@ -74,6 +74,32 b' HGRCPATH' | |||||
74 | like the username and extensions that may be required to interface |
|
74 | like the username and extensions that may be required to interface | |
75 | with a repository. |
|
75 | with a repository. | |
76 |
|
76 | |||
|
77 | Command-line Flags | |||
|
78 | ================== | |||
|
79 | ||||
|
80 | Mercurial's default command-line parser is designed for humans, and is not | |||
|
81 | robust against malicious input. For instance, you can start a debugger by | |||
|
82 | passing ``--debugger`` as an option value:: | |||
|
83 | ||||
|
84 | $ REV=--debugger sh -c 'hg log -r "$REV"' | |||
|
85 | ||||
|
86 | This happens because several command-line flags need to be scanned without | |||
|
87 | using a concrete command table, which may be modified while loading repository | |||
|
88 | settings and extensions. | |||
|
89 | ||||
|
90 | Since Mercurial 4.4.2, the parsing of such flags may be restricted by setting | |||
|
91 | ``HGPLAIN=+strictflags``. When this feature is enabled, all early options | |||
|
92 | (e.g. ``-R/--repository``, ``--cwd``, ``--config``) must be specified first | |||
|
93 | amongst the other global options, and cannot be injected to an arbitrary | |||
|
94 | location:: | |||
|
95 | ||||
|
96 | $ HGPLAIN=+strictflags hg -R "$REPO" log -r "$REV" | |||
|
97 | ||||
|
98 | In earlier Mercurial versions where ``+strictflags`` isn't available, you | |||
|
99 | can mitigate the issue by concatenating an option value with its flag:: | |||
|
100 | ||||
|
101 | $ hg log -r"$REV" --keyword="$KEYWORD" | |||
|
102 | ||||
77 | Consuming Command Output |
|
103 | Consuming Command Output | |
78 | ======================== |
|
104 | ======================== | |
79 |
|
105 |
@@ -90,7 +90,7 b' Interaction with Mercurial Commands' | |||||
90 | :archive: archive does not recurse in subrepositories unless |
|
90 | :archive: archive does not recurse in subrepositories unless | |
91 | -S/--subrepos is specified. |
|
91 | -S/--subrepos is specified. | |
92 |
|
92 | |||
93 |
:cat: |
|
93 | :cat: Git subrepositories only support exact file matches. | |
94 | Subversion subrepositories are currently ignored. |
|
94 | Subversion subrepositories are currently ignored. | |
95 |
|
95 | |||
96 | :commit: commit creates a consistent snapshot of the state of the |
|
96 | :commit: commit creates a consistent snapshot of the state of the |
@@ -653,7 +653,7 b' def _checkunknownfile(repo, wctx, mctx, ' | |||||
653 | and repo.dirstate.normalize(f) not in repo.dirstate |
|
653 | and repo.dirstate.normalize(f) not in repo.dirstate | |
654 | and mctx[f2].cmp(wctx[f])) |
|
654 | and mctx[f2].cmp(wctx[f])) | |
655 |
|
655 | |||
656 | def _checkunknowndirs(repo, f): |
|
656 | class _unknowndirschecker(object): | |
657 | """ |
|
657 | """ | |
658 | Look for any unknown files or directories that may have a path conflict |
|
658 | Look for any unknown files or directories that may have a path conflict | |
659 | with a file. If any path prefix of the file exists as a file or link, |
|
659 | with a file. If any path prefix of the file exists as a file or link, | |
@@ -663,23 +663,42 b' def _checkunknowndirs(repo, f):' | |||||
663 | Returns the shortest path at which a conflict occurs, or None if there is |
|
663 | Returns the shortest path at which a conflict occurs, or None if there is | |
664 | no conflict. |
|
664 | no conflict. | |
665 | """ |
|
665 | """ | |
|
666 | def __init__(self): | |||
|
667 | # A set of paths known to be good. This prevents repeated checking of | |||
|
668 | # dirs. It will be updated with any new dirs that are checked and found | |||
|
669 | # to be safe. | |||
|
670 | self._unknowndircache = set() | |||
666 |
|
671 | |||
667 | # Check for path prefixes that exist as unknown files. |
|
672 | # A set of paths that are known to be absent. This prevents repeated | |
668 | for p in reversed(list(util.finddirs(f))): |
|
673 | # checking of subdirectories that are known not to exist. It will be | |
669 | if (repo.wvfs.audit.check(p) |
|
674 | # updated with any new dirs that are checked and found to be absent. | |
670 | and repo.wvfs.isfileorlink(p) |
|
675 | self._missingdircache = set() | |
671 | and repo.dirstate.normalize(p) not in repo.dirstate): |
|
|||
672 | return p |
|
|||
673 |
|
676 | |||
674 | # Check if the file conflicts with a directory containing unknown files. |
|
677 | def __call__(self, repo, f): | |
675 | if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f): |
|
678 | # Check for path prefixes that exist as unknown files. | |
676 | # Does the directory contain any files that are not in the dirstate? |
|
679 | for p in reversed(list(util.finddirs(f))): | |
677 | for p, dirs, files in repo.wvfs.walk(f): |
|
680 | if p in self._missingdircache: | |
678 | for fn in files: |
|
681 | return | |
679 | relf = repo.dirstate.normalize(repo.wvfs.reljoin(p, fn)) |
|
682 | if p in self._unknowndircache: | |
680 |
|
|
683 | continue | |
681 | return f |
|
684 | if repo.wvfs.audit.check(p): | |
682 | return None |
|
685 | if (repo.wvfs.isfileorlink(p) | |
|
686 | and repo.dirstate.normalize(p) not in repo.dirstate): | |||
|
687 | return p | |||
|
688 | if not repo.wvfs.lexists(p): | |||
|
689 | self._missingdircache.add(p) | |||
|
690 | return | |||
|
691 | self._unknowndircache.add(p) | |||
|
692 | ||||
|
693 | # Check if the file conflicts with a directory containing unknown files. | |||
|
694 | if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f): | |||
|
695 | # Does the directory contain any files that are not in the dirstate? | |||
|
696 | for p, dirs, files in repo.wvfs.walk(f): | |||
|
697 | for fn in files: | |||
|
698 | relf = repo.dirstate.normalize(repo.wvfs.reljoin(p, fn)) | |||
|
699 | if relf not in repo.dirstate: | |||
|
700 | return f | |||
|
701 | return None | |||
683 |
|
702 | |||
684 | def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce): |
|
703 | def _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce): | |
685 | """ |
|
704 | """ | |
@@ -701,12 +720,13 b' def _checkunknownfiles(repo, wctx, mctx,' | |||||
701 | elif config == 'warn': |
|
720 | elif config == 'warn': | |
702 | warnconflicts.update(conflicts) |
|
721 | warnconflicts.update(conflicts) | |
703 |
|
722 | |||
|
723 | checkunknowndirs = _unknowndirschecker() | |||
704 | for f, (m, args, msg) in actions.iteritems(): |
|
724 | for f, (m, args, msg) in actions.iteritems(): | |
705 | if m in ('c', 'dc'): |
|
725 | if m in ('c', 'dc'): | |
706 | if _checkunknownfile(repo, wctx, mctx, f): |
|
726 | if _checkunknownfile(repo, wctx, mctx, f): | |
707 | fileconflicts.add(f) |
|
727 | fileconflicts.add(f) | |
708 | elif pathconfig and f not in wctx: |
|
728 | elif pathconfig and f not in wctx: | |
709 |
path = |
|
729 | path = checkunknowndirs(repo, f) | |
710 | if path is not None: |
|
730 | if path is not None: | |
711 | pathconflicts.add(path) |
|
731 | pathconflicts.add(path) | |
712 | elif m == 'dg': |
|
732 | elif m == 'dg': | |
@@ -895,34 +915,21 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
895 | # can't be updated to cleanly. |
|
915 | # can't be updated to cleanly. | |
896 | invalidconflicts = set() |
|
916 | invalidconflicts = set() | |
897 |
|
917 | |||
|
918 | # The set of directories that contain files that are being created. | |||
|
919 | createdfiledirs = set() | |||
|
920 | ||||
898 | # The set of files deleted by all the actions. |
|
921 | # The set of files deleted by all the actions. | |
899 | deletedfiles = set() |
|
922 | deletedfiles = set() | |
900 |
|
923 | |||
901 | for f, (m, args, msg) in actions.items(): |
|
924 | for f, (m, args, msg) in actions.items(): | |
902 | if m in ('c', 'dc', 'm', 'cm'): |
|
925 | if m in ('c', 'dc', 'm', 'cm'): | |
903 | # This action may create a new local file. |
|
926 | # This action may create a new local file. | |
|
927 | createdfiledirs.update(util.finddirs(f)) | |||
904 | if mf.hasdir(f): |
|
928 | if mf.hasdir(f): | |
905 | # The file aliases a local directory. This might be ok if all |
|
929 | # The file aliases a local directory. This might be ok if all | |
906 | # the files in the local directory are being deleted. This |
|
930 | # the files in the local directory are being deleted. This | |
907 | # will be checked once we know what all the deleted files are. |
|
931 | # will be checked once we know what all the deleted files are. | |
908 | remoteconflicts.add(f) |
|
932 | remoteconflicts.add(f) | |
909 | for p in util.finddirs(f): |
|
|||
910 | if p in mf: |
|
|||
911 | if p in mctx: |
|
|||
912 | # The file is in a directory which aliases both a local |
|
|||
913 | # and a remote file. This is an internal inconsistency |
|
|||
914 | # within the remote manifest. |
|
|||
915 | invalidconflicts.add(p) |
|
|||
916 | else: |
|
|||
917 | # The file is in a directory which aliases a local file. |
|
|||
918 | # We will need to rename the local file. |
|
|||
919 | localconflicts.add(p) |
|
|||
920 | if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'): |
|
|||
921 | # The file is in a directory which aliases a remote file. |
|
|||
922 | # This is an internal inconsistency within the remote |
|
|||
923 | # manifest. |
|
|||
924 | invalidconflicts.add(p) |
|
|||
925 |
|
||||
926 | # Track the names of all deleted files. |
|
933 | # Track the names of all deleted files. | |
927 | if m == 'r': |
|
934 | if m == 'r': | |
928 | deletedfiles.add(f) |
|
935 | deletedfiles.add(f) | |
@@ -934,6 +941,24 b' def checkpathconflicts(repo, wctx, mctx,' | |||||
934 | f2, flags = args |
|
941 | f2, flags = args | |
935 | deletedfiles.add(f2) |
|
942 | deletedfiles.add(f2) | |
936 |
|
943 | |||
|
944 | # Check all directories that contain created files for path conflicts. | |||
|
945 | for p in createdfiledirs: | |||
|
946 | if p in mf: | |||
|
947 | if p in mctx: | |||
|
948 | # A file is in a directory which aliases both a local | |||
|
949 | # and a remote file. This is an internal inconsistency | |||
|
950 | # within the remote manifest. | |||
|
951 | invalidconflicts.add(p) | |||
|
952 | else: | |||
|
953 | # A file is in a directory which aliases a local file. | |||
|
954 | # We will need to rename the local file. | |||
|
955 | localconflicts.add(p) | |||
|
956 | if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'): | |||
|
957 | # The file is in a directory which aliases a remote file. | |||
|
958 | # This is an internal inconsistency within the remote | |||
|
959 | # manifest. | |||
|
960 | invalidconflicts.add(p) | |||
|
961 | ||||
937 | # Rename all local conflicting files that have not been deleted. |
|
962 | # Rename all local conflicting files that have not been deleted. | |
938 | for p in localconflicts: |
|
963 | for p in localconflicts: | |
939 | if p not in deletedfiles: |
|
964 | if p not in deletedfiles: |
@@ -766,6 +766,7 b' class ui(object):' | |||||
766 |
|
766 | |||
767 | The return value can either be |
|
767 | The return value can either be | |
768 | - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT |
|
768 | - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT | |
|
769 | - False if feature is disabled by default and not included in HGPLAIN | |||
769 | - True otherwise |
|
770 | - True otherwise | |
770 | ''' |
|
771 | ''' | |
771 | if ('HGPLAIN' not in encoding.environ and |
|
772 | if ('HGPLAIN' not in encoding.environ and | |
@@ -773,6 +774,9 b' class ui(object):' | |||||
773 | return False |
|
774 | return False | |
774 | exceptions = encoding.environ.get('HGPLAINEXCEPT', |
|
775 | exceptions = encoding.environ.get('HGPLAINEXCEPT', | |
775 | '').strip().split(',') |
|
776 | '').strip().split(',') | |
|
777 | # TODO: add support for HGPLAIN=+feature,-feature syntax | |||
|
778 | if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','): | |||
|
779 | exceptions.append('strictflags') | |||
776 | if feature and exceptions: |
|
780 | if feature and exceptions: | |
777 | return feature not in exceptions |
|
781 | return feature not in exceptions | |
778 | return True |
|
782 | return True |
@@ -58,7 +58,7 b' amend with dirty subrepo' | |||||
58 |
|
58 | |||
59 | $ echo a >> s/a |
|
59 | $ echo a >> s/a | |
60 | $ hg add -R s |
|
60 | $ hg add -R s | |
61 | adding s/a |
|
61 | adding s/a (glob) | |
62 | $ hg amend |
|
62 | $ hg amend | |
63 | abort: uncommitted changes in subrepository "s" |
|
63 | abort: uncommitted changes in subrepository "s" | |
64 | (use --subrepos for recursive commit) |
|
64 | (use --subrepos for recursive commit) |
@@ -9,7 +9,7 b' on commit:' | |||||
9 | $ hg init sub/.hg |
|
9 | $ hg init sub/.hg | |
10 | $ echo 'sub/.hg = sub/.hg' >> .hgsub |
|
10 | $ echo 'sub/.hg = sub/.hg' >> .hgsub | |
11 | $ hg ci -qAm 'add subrepo "sub/.hg"' |
|
11 | $ hg ci -qAm 'add subrepo "sub/.hg"' | |
12 | abort: path 'sub/.hg' is inside nested repo 'sub' |
|
12 | abort: path 'sub/.hg' is inside nested repo 'sub' (glob) | |
13 | [255] |
|
13 | [255] | |
14 |
|
14 | |||
15 | prepare tampered repo (including the commit above): |
|
15 | prepare tampered repo (including the commit above): | |
@@ -33,7 +33,7 b' prepare tampered repo (including the com' | |||||
33 | on clone (and update): |
|
33 | on clone (and update): | |
34 |
|
34 | |||
35 | $ hg clone -q hgname hgname2 |
|
35 | $ hg clone -q hgname hgname2 | |
36 | abort: path 'sub/.hg' is inside nested repo 'sub' |
|
36 | abort: path 'sub/.hg' is inside nested repo 'sub' (glob) | |
37 | [255] |
|
37 | [255] | |
38 |
|
38 | |||
39 | Test direct symlink traversal |
|
39 | Test direct symlink traversal |
@@ -137,6 +137,20 b' typical client does not want echo-back m' | |||||
137 | summary: 1 |
|
137 | summary: 1 | |
138 |
|
138 | |||
139 |
|
139 | |||
|
140 | check strict parsing of early options: | |||
|
141 | ||||
|
142 | >>> import os | |||
|
143 | >>> from hgclient import check, readchannel, runcommand | |||
|
144 | >>> os.environ['HGPLAIN'] = '+strictflags' | |||
|
145 | >>> @check | |||
|
146 | ... def cwd(server): | |||
|
147 | ... readchannel(server) | |||
|
148 | ... runcommand(server, ['log', '-b', '--config=alias.log=!echo pwned', | |||
|
149 | ... 'default']) | |||
|
150 | *** runcommand log -b --config=alias.log=!echo pwned default | |||
|
151 | abort: unknown revision '--config=alias.log=!echo pwned'! | |||
|
152 | [255] | |||
|
153 | ||||
140 | check that "histedit --commands=-" can read rules from the input channel: |
|
154 | check that "histedit --commands=-" can read rules from the input channel: | |
141 |
|
155 | |||
142 | >>> import cStringIO |
|
156 | >>> import cStringIO |
@@ -113,6 +113,51 b' Shell aliases bypass any command parsing' | |||||
113 | $ hg log -b '--config=alias.log=!echo howdy' |
|
113 | $ hg log -b '--config=alias.log=!echo howdy' | |
114 | howdy |
|
114 | howdy | |
115 |
|
115 | |||
|
116 | Early options must come first if HGPLAIN=+strictflags is specified: | |||
|
117 | (BUG: chg cherry-picks early options to pass them as a server command) | |||
|
118 | ||||
|
119 | #if no-chg | |||
|
120 | $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default | |||
|
121 | abort: unknown revision '--config=hooks.pre-log=false'! | |||
|
122 | [255] | |||
|
123 | $ HGPLAIN=+strictflags hg log -b -R. default | |||
|
124 | abort: unknown revision '-R.'! | |||
|
125 | [255] | |||
|
126 | $ HGPLAIN=+strictflags hg log -b --cwd=. default | |||
|
127 | abort: unknown revision '--cwd=.'! | |||
|
128 | [255] | |||
|
129 | #endif | |||
|
130 | $ HGPLAIN=+strictflags hg log -b --debugger default | |||
|
131 | abort: unknown revision '--debugger'! | |||
|
132 | [255] | |||
|
133 | $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default | |||
|
134 | abort: unknown revision '--config=alias.log=!echo pwned'! | |||
|
135 | [255] | |||
|
136 | ||||
|
137 | $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default | |||
|
138 | abort: option --config may not be abbreviated! | |||
|
139 | [255] | |||
|
140 | $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default | |||
|
141 | abort: option --cwd may not be abbreviated! | |||
|
142 | [255] | |||
|
143 | $ HGPLAIN=+strictflags hg log -q -R . -b default | |||
|
144 | abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo! | |||
|
145 | [255] | |||
|
146 | ||||
|
147 | $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default | |||
|
148 | abort: pre-log hook exited with status 1 | |||
|
149 | [255] | |||
|
150 | $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default | |||
|
151 | 0:cb9a9f314b8b | |||
|
152 | ||||
|
153 | For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN: | |||
|
154 | ||||
|
155 | $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default | |||
|
156 | abort: pre-log hook exited with status 1 | |||
|
157 | [255] | |||
|
158 | $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default | |||
|
159 | 0:cb9a9f314b8b | |||
|
160 | ||||
116 | [defaults] |
|
161 | [defaults] | |
117 |
|
162 | |||
118 | $ hg cat a |
|
163 | $ hg cat a |
@@ -48,6 +48,7 b" testmod('mercurial.context')" | |||||
48 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) |
|
48 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) | |
49 | testmod('mercurial.dispatch') |
|
49 | testmod('mercurial.dispatch') | |
50 | testmod('mercurial.encoding') |
|
50 | testmod('mercurial.encoding') | |
|
51 | testmod('mercurial.fancyopts') | |||
51 | testmod('mercurial.formatter') |
|
52 | testmod('mercurial.formatter') | |
52 | testmod('mercurial.hg') |
|
53 | testmod('mercurial.hg') | |
53 | testmod('mercurial.hgweb.hgwebdir_mod') |
|
54 | testmod('mercurial.hgweb.hgwebdir_mod') |
@@ -972,6 +972,7 b' test import with similarity and git and ' | |||||
972 | adding b |
|
972 | adding b | |
973 | recording removal of a as rename to b (88% similar) |
|
973 | recording removal of a as rename to b (88% similar) | |
974 | applied to working directory |
|
974 | applied to working directory | |
|
975 | $ echo 'mod b' > b | |||
975 | $ hg st -C |
|
976 | $ hg st -C | |
976 | A b |
|
977 | A b | |
977 | a |
|
978 | a | |
@@ -979,6 +980,8 b' test import with similarity and git and ' | |||||
979 | $ hg revert -a |
|
980 | $ hg revert -a | |
980 | undeleting a |
|
981 | undeleting a | |
981 | forgetting b |
|
982 | forgetting b | |
|
983 | $ cat b | |||
|
984 | mod b | |||
982 | $ rm b |
|
985 | $ rm b | |
983 | $ hg import --no-commit -v -s 100 ../rename.diff -p2 |
|
986 | $ hg import --no-commit -v -s 100 ../rename.diff -p2 | |
984 | applying ../rename.diff |
|
987 | applying ../rename.diff |
@@ -390,8 +390,12 b' Test update with subrepos.' | |||||
390 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
390 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | |
391 | $ hg status -S |
|
391 | $ hg status -S | |
392 |
|
392 | |||
|
393 | Forget doesn't change the content of the file | |||
|
394 | $ echo 'pre-forget content' > subrepo/large.txt | |||
393 | $ hg forget -v subrepo/large.txt |
|
395 | $ hg forget -v subrepo/large.txt | |
394 | removing subrepo/large.txt (glob) |
|
396 | removing subrepo/large.txt (glob) | |
|
397 | $ cat subrepo/large.txt | |||
|
398 | pre-forget content | |||
395 |
|
399 | |||
396 | Test reverting a forgotten file |
|
400 | Test reverting a forgotten file | |
397 | $ hg revert -R subrepo subrepo/large.txt |
|
401 | $ hg revert -R subrepo subrepo/large.txt | |
@@ -1060,7 +1064,9 b' largefiles (issue4547)' | |||||
1060 | > largefiles= |
|
1064 | > largefiles= | |
1061 | > EOF |
|
1065 | > EOF | |
1062 | $ echo large > subrepo-root/large |
|
1066 | $ echo large > subrepo-root/large | |
1063 | $ hg -R subrepo-root add --large subrepo-root/large |
|
1067 | $ mkdir -p subrepo-root/dir/subdir | |
|
1068 | $ echo large2 > subrepo-root/dir/subdir/large.bin | |||
|
1069 | $ hg -R subrepo-root add --large subrepo-root/large subrepo-root/dir/subdir/large.bin | |||
1064 | $ hg clone -q no-largefiles subrepo-root/no-largefiles |
|
1070 | $ hg clone -q no-largefiles subrepo-root/no-largefiles | |
1065 | $ cat > subrepo-root/.hgsub <<EOF |
|
1071 | $ cat > subrepo-root/.hgsub <<EOF | |
1066 | > no-largefiles = no-largefiles |
|
1072 | > no-largefiles = no-largefiles | |
@@ -1069,6 +1075,7 b' largefiles (issue4547)' | |||||
1069 | $ hg -R subrepo-root commit -m '#0' |
|
1075 | $ hg -R subrepo-root commit -m '#0' | |
1070 | Invoking status precommit hook |
|
1076 | Invoking status precommit hook | |
1071 | A .hgsub |
|
1077 | A .hgsub | |
|
1078 | A dir/subdir/large.bin | |||
1072 | A large |
|
1079 | A large | |
1073 | ? .hgsubstate |
|
1080 | ? .hgsubstate | |
1074 | $ echo dirty >> subrepo-root/large |
|
1081 | $ echo dirty >> subrepo-root/large | |
@@ -1085,8 +1092,155 b' largefiles (issue4547)' | |||||
1085 | reverting subrepo no-largefiles |
|
1092 | reverting subrepo no-largefiles | |
1086 | reverting subrepo-root/no-largefiles/normal1 (glob) |
|
1093 | reverting subrepo-root/no-largefiles/normal1 (glob) | |
1087 |
|
1094 | |||
1088 | $ cd .. |
|
1095 | Move (and then undo) a directory move with only largefiles. | |
|
1096 | ||||
|
1097 | $ listtree() { | |||
|
1098 | > find $@ \( -type d -printf "%p/\n" -o -type f -printf "%p\n" \) \ | |||
|
1099 | > -a -name .hg -prune | sort | |||
|
1100 | > } | |||
|
1101 | ||||
|
1102 | $ cd subrepo-root | |||
|
1103 | $ listtree .hglf dir* large* | |||
|
1104 | .hglf/ | |||
|
1105 | .hglf/dir/ | |||
|
1106 | .hglf/dir/subdir/ | |||
|
1107 | .hglf/dir/subdir/large.bin | |||
|
1108 | .hglf/large | |||
|
1109 | dir/ | |||
|
1110 | dir/subdir/ | |||
|
1111 | dir/subdir/large.bin | |||
|
1112 | large | |||
|
1113 | large.orig | |||
|
1114 | ||||
|
1115 | $ hg mv dir/subdir dir/subdir2 | |||
|
1116 | moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin (glob) | |||
|
1117 | ||||
|
1118 | $ listtree .hglf dir* large* | |||
|
1119 | .hglf/ | |||
|
1120 | .hglf/dir/ | |||
|
1121 | .hglf/dir/subdir2/ | |||
|
1122 | .hglf/dir/subdir2/large.bin | |||
|
1123 | .hglf/large | |||
|
1124 | dir/ | |||
|
1125 | dir/subdir2/ | |||
|
1126 | dir/subdir2/large.bin | |||
|
1127 | large | |||
|
1128 | large.orig | |||
|
1129 | $ hg status -C | |||
|
1130 | A dir/subdir2/large.bin | |||
|
1131 | dir/subdir/large.bin | |||
|
1132 | R dir/subdir/large.bin | |||
|
1133 | ? large.orig | |||
|
1134 | ||||
|
1135 | $ echo 'modified' > dir/subdir2/large.bin | |||
|
1136 | $ hg status -C | |||
|
1137 | A dir/subdir2/large.bin | |||
|
1138 | dir/subdir/large.bin | |||
|
1139 | R dir/subdir/large.bin | |||
|
1140 | ? large.orig | |||
|
1141 | ||||
|
1142 | $ hg revert --all | |||
|
1143 | undeleting .hglf/dir/subdir/large.bin (glob) | |||
|
1144 | forgetting .hglf/dir/subdir2/large.bin (glob) | |||
|
1145 | reverting subrepo no-largefiles | |||
|
1146 | ||||
|
1147 | $ hg status -C | |||
|
1148 | ? dir/subdir2/large.bin | |||
|
1149 | ? large.orig | |||
|
1150 | ||||
|
1151 | The content of the forgotten file shouldn't be clobbered | |||
|
1152 | ||||
|
1153 | $ cat dir/subdir2/large.bin | |||
|
1154 | modified | |||
|
1155 | ||||
|
1156 | The standin for subdir2 should be deleted, not just dropped | |||
1089 |
|
1157 | |||
|
1158 | $ listtree .hglf dir* large* | |||
|
1159 | .hglf/ | |||
|
1160 | .hglf/dir/ | |||
|
1161 | .hglf/dir/subdir/ | |||
|
1162 | .hglf/dir/subdir/large.bin | |||
|
1163 | .hglf/large | |||
|
1164 | dir/ | |||
|
1165 | dir/subdir/ | |||
|
1166 | dir/subdir/large.bin | |||
|
1167 | dir/subdir2/ | |||
|
1168 | dir/subdir2/large.bin | |||
|
1169 | large | |||
|
1170 | large.orig | |||
|
1171 | ||||
|
1172 | $ rm -r dir/subdir2 | |||
|
1173 | ||||
|
1174 | 'subdir' should not be in the destination. It would be if the subdir2 directory | |||
|
1175 | existed under .hglf/. | |||
|
1176 | $ hg mv dir/subdir dir/subdir2 | |||
|
1177 | moving .hglf/dir/subdir/large.bin to .hglf/dir/subdir2/large.bin (glob) | |||
|
1178 | ||||
|
1179 | $ hg status -C | |||
|
1180 | A dir/subdir2/large.bin | |||
|
1181 | dir/subdir/large.bin | |||
|
1182 | R dir/subdir/large.bin | |||
|
1183 | ? large.orig | |||
|
1184 | ||||
|
1185 | $ listtree .hglf dir* large* | |||
|
1186 | .hglf/ | |||
|
1187 | .hglf/dir/ | |||
|
1188 | .hglf/dir/subdir2/ | |||
|
1189 | .hglf/dir/subdir2/large.bin | |||
|
1190 | .hglf/large | |||
|
1191 | dir/ | |||
|
1192 | dir/subdir2/ | |||
|
1193 | dir/subdir2/large.bin | |||
|
1194 | large | |||
|
1195 | large.orig | |||
|
1196 | ||||
|
1197 | Start from scratch, and rename something other than the final path component. | |||
|
1198 | ||||
|
1199 | $ hg up -qC . | |||
|
1200 | $ hg --config extensions.purge= purge | |||
|
1201 | ||||
|
1202 | $ hg mv dir/subdir dir2/subdir | |||
|
1203 | moving .hglf/dir/subdir/large.bin to .hglf/dir2/subdir/large.bin (glob) | |||
|
1204 | ||||
|
1205 | $ hg status -C | |||
|
1206 | A dir2/subdir/large.bin | |||
|
1207 | dir/subdir/large.bin | |||
|
1208 | R dir/subdir/large.bin | |||
|
1209 | ||||
|
1210 | $ listtree .hglf dir* large* | |||
|
1211 | .hglf/ | |||
|
1212 | .hglf/dir2/ | |||
|
1213 | .hglf/dir2/subdir/ | |||
|
1214 | .hglf/dir2/subdir/large.bin | |||
|
1215 | .hglf/large | |||
|
1216 | dir2/ | |||
|
1217 | dir2/subdir/ | |||
|
1218 | dir2/subdir/large.bin | |||
|
1219 | large | |||
|
1220 | ||||
|
1221 | $ hg revert --all | |||
|
1222 | undeleting .hglf/dir/subdir/large.bin (glob) | |||
|
1223 | forgetting .hglf/dir2/subdir/large.bin (glob) | |||
|
1224 | reverting subrepo no-largefiles | |||
|
1225 | ||||
|
1226 | $ hg status -C | |||
|
1227 | ? dir2/subdir/large.bin | |||
|
1228 | ||||
|
1229 | $ listtree .hglf dir* large* | |||
|
1230 | .hglf/ | |||
|
1231 | .hglf/dir/ | |||
|
1232 | .hglf/dir/subdir/ | |||
|
1233 | .hglf/dir/subdir/large.bin | |||
|
1234 | .hglf/large | |||
|
1235 | dir/ | |||
|
1236 | dir/subdir/ | |||
|
1237 | dir/subdir/large.bin | |||
|
1238 | dir2/ | |||
|
1239 | dir2/subdir/ | |||
|
1240 | dir2/subdir/large.bin | |||
|
1241 | large | |||
|
1242 | ||||
|
1243 | $ cd ../.. | |||
1090 |
|
1244 | |||
1091 | Test "pull --rebase" when rebase is enabled before largefiles (issue3861) |
|
1245 | Test "pull --rebase" when rebase is enabled before largefiles (issue3861) | |
1092 | ========================================================================= |
|
1246 | ========================================================================= |
@@ -1071,6 +1071,18 b' Prepare a repo with subrepo' | |||||
1071 | "path": "sub/repo/foo" |
|
1071 | "path": "sub/repo/foo" | |
1072 | } |
|
1072 | } | |
1073 | ] |
|
1073 | ] | |
|
1074 | ||||
|
1075 | non-exact match: | |||
|
1076 | ||||
|
1077 | $ hg cat -T '{path}\n' 'glob:**' | |||
|
1078 | .hgsub | |||
|
1079 | .hgsubstate | |||
|
1080 | sub/repo/foo (glob) | |||
|
1081 | $ hg cat -T '{path}\n' 're:^sub' | |||
|
1082 | sub/repo/foo (glob) | |||
|
1083 | ||||
|
1084 | missing subrepos in working directory: | |||
|
1085 | ||||
1074 | $ mkdir -p tmp/sub/repo |
|
1086 | $ mkdir -p tmp/sub/repo | |
1075 | $ hg cat -r 0 --output tmp/%p_p sub/repo/foo |
|
1087 | $ hg cat -r 0 --output tmp/%p_p sub/repo/foo | |
1076 | $ cat tmp/sub/repo/foo_p |
|
1088 | $ cat tmp/sub/repo/foo_p |
General Comments 0
You need to be logged in to leave comments.
Login now