##// END OF EJS Templates
diff: support diffing explicit files in subrepos...
Matt Harbison -
r42177:db26dbbe default
parent child Browse files
Show More
@@ -1,169 +1,171 b''
1 1 Subrepositories let you nest external repositories or projects into a
2 2 parent Mercurial repository, and make commands operate on them as a
3 3 group.
4 4
5 5 Mercurial currently supports Mercurial, Git, and Subversion
6 6 subrepositories.
7 7
8 8 Subrepositories are made of three components:
9 9
10 10 1. Nested repository checkouts. They can appear anywhere in the
11 11 parent working directory.
12 12
13 13 2. Nested repository references. They are defined in ``.hgsub``, which
14 14 should be placed in the root of working directory, and
15 15 tell where the subrepository checkouts come from. Mercurial
16 16 subrepositories are referenced like::
17 17
18 18 path/to/nested = https://example.com/nested/repo/path
19 19
20 20 Git and Subversion subrepos are also supported::
21 21
22 22 path/to/nested = [git]git://example.com/nested/repo/path
23 23 path/to/nested = [svn]https://example.com/nested/trunk/path
24 24
25 25 where ``path/to/nested`` is the checkout location relatively to the
26 26 parent Mercurial root, and ``https://example.com/nested/repo/path``
27 27 is the source repository path. The source can also reference a
28 28 filesystem path.
29 29
30 30 Note that ``.hgsub`` does not exist by default in Mercurial
31 31 repositories, you have to create and add it to the parent
32 32 repository before using subrepositories.
33 33
34 34 3. Nested repository states. They are defined in ``.hgsubstate``, which
35 35 is placed in the root of working directory, and
36 36 capture whatever information is required to restore the
37 37 subrepositories to the state they were committed in a parent
38 38 repository changeset. Mercurial automatically record the nested
39 39 repositories states when committing in the parent repository.
40 40
41 41 .. note::
42 42
43 43 The ``.hgsubstate`` file should not be edited manually.
44 44
45 45
46 46 Adding a Subrepository
47 47 ======================
48 48
49 49 If ``.hgsub`` does not exist, create it and add it to the parent
50 50 repository. Clone or checkout the external projects where you want it
51 51 to live in the parent repository. Edit ``.hgsub`` and add the
52 52 subrepository entry as described above. At this point, the
53 53 subrepository is tracked and the next commit will record its state in
54 54 ``.hgsubstate`` and bind it to the committed changeset.
55 55
56 56 Synchronizing a Subrepository
57 57 =============================
58 58
59 59 Subrepos do not automatically track the latest changeset of their
60 60 sources. Instead, they are updated to the changeset that corresponds
61 61 with the changeset checked out in the top-level changeset. This is so
62 62 developers always get a consistent set of compatible code and
63 63 libraries when they update.
64 64
65 65 Thus, updating subrepos is a manual process. Simply check out target
66 66 subrepo at the desired revision, test in the top-level repo, then
67 67 commit in the parent repository to record the new combination.
68 68
69 69 Deleting a Subrepository
70 70 ========================
71 71
72 72 To remove a subrepository from the parent repository, delete its
73 73 reference from ``.hgsub``, then remove its files.
74 74
75 75 Interaction with Mercurial Commands
76 76 ===================================
77 77
78 78 :add: add does not recurse in subrepos unless -S/--subrepos is
79 79 specified. However, if you specify the full path of a file in a
80 80 subrepo, it will be added even without -S/--subrepos specified.
81 81 Subversion subrepositories are currently silently
82 82 ignored.
83 83
84 84 :addremove: addremove does not recurse into subrepos unless
85 85 -S/--subrepos is specified. However, if you specify the full
86 86 path of a directory in a subrepo, addremove will be performed on
87 87 it even without -S/--subrepos being specified. Git and
88 88 Subversion subrepositories will print a warning and continue.
89 89
90 90 :archive: archive does not recurse in subrepositories unless
91 91 -S/--subrepos is specified.
92 92
93 93 :cat: Git subrepositories only support exact file matches.
94 94 Subversion subrepositories are currently ignored.
95 95
96 96 :commit: commit creates a consistent snapshot of the state of the
97 97 entire project and its subrepositories. If any subrepositories
98 98 have been modified, Mercurial will abort. Mercurial can be made
99 99 to instead commit all modified subrepositories by specifying
100 100 -S/--subrepos, or setting "ui.commitsubrepos=True" in a
101 101 configuration file (see :hg:`help config`). After there are no
102 102 longer any modified subrepositories, it records their state and
103 103 finally commits it in the parent repository. The --addremove
104 104 option also honors the -S/--subrepos option. However, Git and
105 105 Subversion subrepositories will print a warning and abort.
106 106
107 107 :diff: diff does not recurse in subrepos unless -S/--subrepos is
108 specified. Changes are displayed as usual, on the subrepositories
109 elements. Subversion subrepositories are currently silently ignored.
108 specified. However, if you specify the full path of a file or
109 directory in a subrepo, it will be diffed even without
110 -S/--subrepos being specified. Subversion subrepositories are
111 currently silently ignored.
110 112
111 113 :files: files does not recurse into subrepos unless -S/--subrepos is
112 114 specified. However, if you specify the full path of a file or
113 115 directory in a subrepo, it will be displayed even without
114 116 -S/--subrepos being specified. Git and Subversion subrepositories
115 117 are currently silently ignored.
116 118
117 119 :forget: forget currently only handles exact file matches in subrepos.
118 120 Git and Subversion subrepositories are currently silently ignored.
119 121
120 122 :incoming: incoming does not recurse in subrepos unless -S/--subrepos
121 123 is specified. Git and Subversion subrepositories are currently
122 124 silently ignored.
123 125
124 126 :outgoing: outgoing does not recurse in subrepos unless -S/--subrepos
125 127 is specified. Git and Subversion subrepositories are currently
126 128 silently ignored.
127 129
128 130 :pull: pull is not recursive since it is not clear what to pull prior
129 131 to running :hg:`update`. Listing and retrieving all
130 132 subrepositories changes referenced by the parent repository pulled
131 133 changesets is expensive at best, impossible in the Subversion
132 134 case.
133 135
134 136 :push: Mercurial will automatically push all subrepositories first
135 137 when the parent repository is being pushed. This ensures new
136 138 subrepository changes are available when referenced by top-level
137 139 repositories. Push is a no-op for Subversion subrepositories.
138 140
139 141 :serve: serve does not recurse into subrepositories unless
140 142 -S/--subrepos is specified. Git and Subversion subrepositories
141 143 are currently silently ignored.
142 144
143 145 :status: status does not recurse into subrepositories unless
144 146 -S/--subrepos is specified. Subrepository changes are displayed as
145 147 regular Mercurial changes on the subrepository
146 148 elements. Subversion subrepositories are currently silently
147 149 ignored.
148 150
149 151 :remove: remove does not recurse into subrepositories unless
150 152 -S/--subrepos is specified. However, if you specify a file or
151 153 directory path in a subrepo, it will be removed even without
152 154 -S/--subrepos. Git and Subversion subrepositories are currently
153 155 silently ignored.
154 156
155 157 :update: update restores the subrepos in the state they were
156 158 originally committed in target changeset. If the recorded
157 159 changeset is not available in the current subrepository, Mercurial
158 160 will pull it in first before updating. This means that updating
159 161 can require network access when using subrepositories.
160 162
161 163 Remapping Subrepositories Sources
162 164 =================================
163 165
164 166 A subrepository source location may change during a project life,
165 167 invalidating references stored in the parent repository history. To
166 168 fix this, rewriting rules can be defined in parent repository ``hgrc``
167 169 file or in Mercurial configuration. See the ``[subpaths]`` section in
168 170 hgrc(5) for more details.
169 171
@@ -1,938 +1,938 b''
1 1 # logcmdutil.py - utility for log-like commands
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import posixpath
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 nullid,
17 17 wdirid,
18 18 wdirrev,
19 19 )
20 20
21 21 from . import (
22 22 dagop,
23 23 error,
24 24 formatter,
25 25 graphmod,
26 26 match as matchmod,
27 27 mdiff,
28 28 patch,
29 29 pathutil,
30 30 pycompat,
31 31 revset,
32 32 revsetlang,
33 33 scmutil,
34 34 smartset,
35 35 templatekw,
36 36 templater,
37 37 util,
38 38 )
39 39 from .utils import (
40 40 dateutil,
41 41 stringutil,
42 42 )
43 43
44 44 def getlimit(opts):
45 45 """get the log limit according to option -l/--limit"""
46 46 limit = opts.get('limit')
47 47 if limit:
48 48 try:
49 49 limit = int(limit)
50 50 except ValueError:
51 51 raise error.Abort(_('limit must be a positive integer'))
52 52 if limit <= 0:
53 53 raise error.Abort(_('limit must be positive'))
54 54 else:
55 55 limit = None
56 56 return limit
57 57
58 58 def diffordiffstat(ui, repo, diffopts, node1, node2, match,
59 59 changes=None, stat=False, fp=None, graphwidth=0,
60 60 prefix='', root='', listsubrepos=False, hunksfilterfn=None):
61 61 '''show diff or diffstat.'''
62 62 ctx1 = repo[node1]
63 63 ctx2 = repo[node2]
64 64 if root:
65 65 relroot = pathutil.canonpath(repo.root, repo.getcwd(), root)
66 66 else:
67 67 relroot = ''
68 68 copysourcematch = None
69 69 def compose(f, g):
70 70 return lambda x: f(g(x))
71 71 def pathfn(f):
72 72 return posixpath.join(prefix, f)
73 73 if relroot != '':
74 74 # XXX relative roots currently don't work if the root is within a
75 75 # subrepo
76 76 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
77 77 uirelroot = uipathfn(pathfn(relroot))
78 78 relroot += '/'
79 79 for matchroot in match.files():
80 80 if not matchroot.startswith(relroot):
81 81 ui.warn(_('warning: %s not inside relative root %s\n') %
82 82 (uipathfn(pathfn(matchroot)), uirelroot))
83 83
84 84 relrootmatch = scmutil.match(ctx2, pats=[relroot], default='path')
85 85 match = matchmod.intersectmatchers(match, relrootmatch)
86 86 copysourcematch = relrootmatch
87 87
88 88 checkroot = (repo.ui.configbool('devel', 'all-warnings') or
89 89 repo.ui.configbool('devel', 'check-relroot'))
90 90 def relrootpathfn(f):
91 91 if checkroot and not f.startswith(relroot):
92 92 raise AssertionError(
93 93 "file %s doesn't start with relroot %s" % (f, relroot))
94 94 return f[len(relroot):]
95 95 pathfn = compose(relrootpathfn, pathfn)
96 96
97 97 if stat:
98 98 diffopts = diffopts.copy(context=0, noprefix=False)
99 99 width = 80
100 100 if not ui.plain():
101 101 width = ui.termwidth() - graphwidth
102 102 # If an explicit --root was given, don't respect ui.relative-paths
103 103 if not relroot:
104 104 pathfn = compose(scmutil.getuipathfn(repo), pathfn)
105 105
106 106 chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, pathfn=pathfn,
107 107 copysourcematch=copysourcematch,
108 108 hunksfilterfn=hunksfilterfn)
109 109
110 110 if fp is not None or ui.canwritewithoutlabels():
111 111 out = fp or ui
112 112 if stat:
113 113 chunks = [patch.diffstat(util.iterlines(chunks), width=width)]
114 114 for chunk in util.filechunkiter(util.chunkbuffer(chunks)):
115 115 out.write(chunk)
116 116 else:
117 117 if stat:
118 118 chunks = patch.diffstatui(util.iterlines(chunks), width=width)
119 119 else:
120 120 chunks = patch.difflabel(lambda chunks, **kwargs: chunks, chunks,
121 121 opts=diffopts)
122 122 if ui.canbatchlabeledwrites():
123 123 def gen():
124 124 for chunk, label in chunks:
125 125 yield ui.label(chunk, label=label)
126 126 for chunk in util.filechunkiter(util.chunkbuffer(gen())):
127 127 ui.write(chunk)
128 128 else:
129 129 for chunk, label in chunks:
130 130 ui.write(chunk, label=label)
131 131
132 if listsubrepos:
133 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
134 tempnode2 = node2
135 try:
136 if node2 is not None:
137 tempnode2 = ctx2.substate[subpath][1]
138 except KeyError:
139 # A subrepo that existed in node1 was deleted between node1 and
140 # node2 (inclusive). Thus, ctx2's substate won't contain that
141 # subpath. The best we can do is to ignore it.
142 tempnode2 = None
143 submatch = matchmod.subdirmatcher(subpath, match)
144 subprefix = repo.wvfs.reljoin(prefix, subpath)
132 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2):
133 tempnode2 = node2
134 try:
135 if node2 is not None:
136 tempnode2 = ctx2.substate[subpath][1]
137 except KeyError:
138 # A subrepo that existed in node1 was deleted between node1 and
139 # node2 (inclusive). Thus, ctx2's substate won't contain that
140 # subpath. The best we can do is to ignore it.
141 tempnode2 = None
142 submatch = matchmod.subdirmatcher(subpath, match)
143 subprefix = repo.wvfs.reljoin(prefix, subpath)
144 if listsubrepos or match.exact(subpath) or any(submatch.files()):
145 145 sub.diff(ui, diffopts, tempnode2, submatch, changes=changes,
146 146 stat=stat, fp=fp, prefix=subprefix)
147 147
148 148 class changesetdiffer(object):
149 149 """Generate diff of changeset with pre-configured filtering functions"""
150 150
151 151 def _makefilematcher(self, ctx):
152 152 return scmutil.matchall(ctx.repo())
153 153
154 154 def _makehunksfilter(self, ctx):
155 155 return None
156 156
157 157 def showdiff(self, ui, ctx, diffopts, graphwidth=0, stat=False):
158 158 repo = ctx.repo()
159 159 node = ctx.node()
160 160 prev = ctx.p1().node()
161 161 diffordiffstat(ui, repo, diffopts, prev, node,
162 162 match=self._makefilematcher(ctx), stat=stat,
163 163 graphwidth=graphwidth,
164 164 hunksfilterfn=self._makehunksfilter(ctx))
165 165
166 166 def changesetlabels(ctx):
167 167 labels = ['log.changeset', 'changeset.%s' % ctx.phasestr()]
168 168 if ctx.obsolete():
169 169 labels.append('changeset.obsolete')
170 170 if ctx.isunstable():
171 171 labels.append('changeset.unstable')
172 172 for instability in ctx.instabilities():
173 173 labels.append('instability.%s' % instability)
174 174 return ' '.join(labels)
175 175
176 176 class changesetprinter(object):
177 177 '''show changeset information when templating not requested.'''
178 178
179 179 def __init__(self, ui, repo, differ=None, diffopts=None, buffered=False):
180 180 self.ui = ui
181 181 self.repo = repo
182 182 self.buffered = buffered
183 183 self._differ = differ or changesetdiffer()
184 184 self._diffopts = patch.diffallopts(ui, diffopts)
185 185 self._includestat = diffopts and diffopts.get('stat')
186 186 self._includediff = diffopts and diffopts.get('patch')
187 187 self.header = {}
188 188 self.hunk = {}
189 189 self.lastheader = None
190 190 self.footer = None
191 191 self._columns = templatekw.getlogcolumns()
192 192
193 193 def flush(self, ctx):
194 194 rev = ctx.rev()
195 195 if rev in self.header:
196 196 h = self.header[rev]
197 197 if h != self.lastheader:
198 198 self.lastheader = h
199 199 self.ui.write(h)
200 200 del self.header[rev]
201 201 if rev in self.hunk:
202 202 self.ui.write(self.hunk[rev])
203 203 del self.hunk[rev]
204 204
205 205 def close(self):
206 206 if self.footer:
207 207 self.ui.write(self.footer)
208 208
209 209 def show(self, ctx, copies=None, **props):
210 210 props = pycompat.byteskwargs(props)
211 211 if self.buffered:
212 212 self.ui.pushbuffer(labeled=True)
213 213 self._show(ctx, copies, props)
214 214 self.hunk[ctx.rev()] = self.ui.popbuffer()
215 215 else:
216 216 self._show(ctx, copies, props)
217 217
218 218 def _show(self, ctx, copies, props):
219 219 '''show a single changeset or file revision'''
220 220 changenode = ctx.node()
221 221 graphwidth = props.get('graphwidth', 0)
222 222
223 223 if self.ui.quiet:
224 224 self.ui.write("%s\n" % scmutil.formatchangeid(ctx),
225 225 label='log.node')
226 226 return
227 227
228 228 columns = self._columns
229 229 self.ui.write(columns['changeset'] % scmutil.formatchangeid(ctx),
230 230 label=changesetlabels(ctx))
231 231
232 232 # branches are shown first before any other names due to backwards
233 233 # compatibility
234 234 branch = ctx.branch()
235 235 # don't show the default branch name
236 236 if branch != 'default':
237 237 self.ui.write(columns['branch'] % branch, label='log.branch')
238 238
239 239 for nsname, ns in self.repo.names.iteritems():
240 240 # branches has special logic already handled above, so here we just
241 241 # skip it
242 242 if nsname == 'branches':
243 243 continue
244 244 # we will use the templatename as the color name since those two
245 245 # should be the same
246 246 for name in ns.names(self.repo, changenode):
247 247 self.ui.write(ns.logfmt % name,
248 248 label='log.%s' % ns.colorname)
249 249 if self.ui.debugflag:
250 250 self.ui.write(columns['phase'] % ctx.phasestr(), label='log.phase')
251 251 for pctx in scmutil.meaningfulparents(self.repo, ctx):
252 252 label = 'log.parent changeset.%s' % pctx.phasestr()
253 253 self.ui.write(columns['parent'] % scmutil.formatchangeid(pctx),
254 254 label=label)
255 255
256 256 if self.ui.debugflag:
257 257 mnode = ctx.manifestnode()
258 258 if mnode is None:
259 259 mnode = wdirid
260 260 mrev = wdirrev
261 261 else:
262 262 mrev = self.repo.manifestlog.rev(mnode)
263 263 self.ui.write(columns['manifest']
264 264 % scmutil.formatrevnode(self.ui, mrev, mnode),
265 265 label='ui.debug log.manifest')
266 266 self.ui.write(columns['user'] % ctx.user(), label='log.user')
267 267 self.ui.write(columns['date'] % dateutil.datestr(ctx.date()),
268 268 label='log.date')
269 269
270 270 if ctx.isunstable():
271 271 instabilities = ctx.instabilities()
272 272 self.ui.write(columns['instability'] % ', '.join(instabilities),
273 273 label='log.instability')
274 274
275 275 elif ctx.obsolete():
276 276 self._showobsfate(ctx)
277 277
278 278 self._exthook(ctx)
279 279
280 280 if self.ui.debugflag:
281 281 files = ctx.p1().status(ctx)[:3]
282 282 for key, value in zip(['files', 'files+', 'files-'], files):
283 283 if value:
284 284 self.ui.write(columns[key] % " ".join(value),
285 285 label='ui.debug log.files')
286 286 elif ctx.files() and self.ui.verbose:
287 287 self.ui.write(columns['files'] % " ".join(ctx.files()),
288 288 label='ui.note log.files')
289 289 if copies and self.ui.verbose:
290 290 copies = ['%s (%s)' % c for c in copies]
291 291 self.ui.write(columns['copies'] % ' '.join(copies),
292 292 label='ui.note log.copies')
293 293
294 294 extra = ctx.extra()
295 295 if extra and self.ui.debugflag:
296 296 for key, value in sorted(extra.items()):
297 297 self.ui.write(columns['extra']
298 298 % (key, stringutil.escapestr(value)),
299 299 label='ui.debug log.extra')
300 300
301 301 description = ctx.description().strip()
302 302 if description:
303 303 if self.ui.verbose:
304 304 self.ui.write(_("description:\n"),
305 305 label='ui.note log.description')
306 306 self.ui.write(description,
307 307 label='ui.note log.description')
308 308 self.ui.write("\n\n")
309 309 else:
310 310 self.ui.write(columns['summary'] % description.splitlines()[0],
311 311 label='log.summary')
312 312 self.ui.write("\n")
313 313
314 314 self._showpatch(ctx, graphwidth)
315 315
316 316 def _showobsfate(self, ctx):
317 317 # TODO: do not depend on templater
318 318 tres = formatter.templateresources(self.repo.ui, self.repo)
319 319 t = formatter.maketemplater(self.repo.ui, '{join(obsfate, "\n")}',
320 320 defaults=templatekw.keywords,
321 321 resources=tres)
322 322 obsfate = t.renderdefault({'ctx': ctx}).splitlines()
323 323
324 324 if obsfate:
325 325 for obsfateline in obsfate:
326 326 self.ui.write(self._columns['obsolete'] % obsfateline,
327 327 label='log.obsfate')
328 328
329 329 def _exthook(self, ctx):
330 330 '''empty method used by extension as a hook point
331 331 '''
332 332
333 333 def _showpatch(self, ctx, graphwidth=0):
334 334 if self._includestat:
335 335 self._differ.showdiff(self.ui, ctx, self._diffopts,
336 336 graphwidth, stat=True)
337 337 if self._includestat and self._includediff:
338 338 self.ui.write("\n")
339 339 if self._includediff:
340 340 self._differ.showdiff(self.ui, ctx, self._diffopts,
341 341 graphwidth, stat=False)
342 342 if self._includestat or self._includediff:
343 343 self.ui.write("\n")
344 344
345 345 class changesetformatter(changesetprinter):
346 346 """Format changeset information by generic formatter"""
347 347
348 348 def __init__(self, ui, repo, fm, differ=None, diffopts=None,
349 349 buffered=False):
350 350 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
351 351 self._diffopts = patch.difffeatureopts(ui, diffopts, git=True)
352 352 self._fm = fm
353 353
354 354 def close(self):
355 355 self._fm.end()
356 356
357 357 def _show(self, ctx, copies, props):
358 358 '''show a single changeset or file revision'''
359 359 fm = self._fm
360 360 fm.startitem()
361 361 fm.context(ctx=ctx)
362 362 fm.data(rev=scmutil.intrev(ctx),
363 363 node=fm.hexfunc(scmutil.binnode(ctx)))
364 364
365 365 if self.ui.quiet:
366 366 return
367 367
368 368 fm.data(branch=ctx.branch(),
369 369 phase=ctx.phasestr(),
370 370 user=ctx.user(),
371 371 date=fm.formatdate(ctx.date()),
372 372 desc=ctx.description(),
373 373 bookmarks=fm.formatlist(ctx.bookmarks(), name='bookmark'),
374 374 tags=fm.formatlist(ctx.tags(), name='tag'),
375 375 parents=fm.formatlist([fm.hexfunc(c.node())
376 376 for c in ctx.parents()], name='node'))
377 377
378 378 if self.ui.debugflag:
379 379 fm.data(manifest=fm.hexfunc(ctx.manifestnode() or wdirid),
380 380 extra=fm.formatdict(ctx.extra()))
381 381
382 382 files = ctx.p1().status(ctx)
383 383 fm.data(modified=fm.formatlist(files[0], name='file'),
384 384 added=fm.formatlist(files[1], name='file'),
385 385 removed=fm.formatlist(files[2], name='file'))
386 386
387 387 elif self.ui.verbose:
388 388 fm.data(files=fm.formatlist(ctx.files(), name='file'))
389 389 if copies:
390 390 fm.data(copies=fm.formatdict(copies,
391 391 key='name', value='source'))
392 392
393 393 if self._includestat:
394 394 self.ui.pushbuffer()
395 395 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=True)
396 396 fm.data(diffstat=self.ui.popbuffer())
397 397 if self._includediff:
398 398 self.ui.pushbuffer()
399 399 self._differ.showdiff(self.ui, ctx, self._diffopts, stat=False)
400 400 fm.data(diff=self.ui.popbuffer())
401 401
402 402 class changesettemplater(changesetprinter):
403 403 '''format changeset information.
404 404
405 405 Note: there are a variety of convenience functions to build a
406 406 changesettemplater for common cases. See functions such as:
407 407 maketemplater, changesetdisplayer, buildcommittemplate, or other
408 408 functions that use changesest_templater.
409 409 '''
410 410
411 411 # Arguments before "buffered" used to be positional. Consider not
412 412 # adding/removing arguments before "buffered" to not break callers.
413 413 def __init__(self, ui, repo, tmplspec, differ=None, diffopts=None,
414 414 buffered=False):
415 415 changesetprinter.__init__(self, ui, repo, differ, diffopts, buffered)
416 416 # tres is shared with _graphnodeformatter()
417 417 self._tresources = tres = formatter.templateresources(ui, repo)
418 418 self.t = formatter.loadtemplater(ui, tmplspec,
419 419 defaults=templatekw.keywords,
420 420 resources=tres,
421 421 cache=templatekw.defaulttempl)
422 422 self._counter = itertools.count()
423 423
424 424 self._tref = tmplspec.ref
425 425 self._parts = {'header': '', 'footer': '',
426 426 tmplspec.ref: tmplspec.ref,
427 427 'docheader': '', 'docfooter': '',
428 428 'separator': ''}
429 429 if tmplspec.mapfile:
430 430 # find correct templates for current mode, for backward
431 431 # compatibility with 'log -v/-q/--debug' using a mapfile
432 432 tmplmodes = [
433 433 (True, ''),
434 434 (self.ui.verbose, '_verbose'),
435 435 (self.ui.quiet, '_quiet'),
436 436 (self.ui.debugflag, '_debug'),
437 437 ]
438 438 for mode, postfix in tmplmodes:
439 439 for t in self._parts:
440 440 cur = t + postfix
441 441 if mode and cur in self.t:
442 442 self._parts[t] = cur
443 443 else:
444 444 partnames = [p for p in self._parts.keys() if p != tmplspec.ref]
445 445 m = formatter.templatepartsmap(tmplspec, self.t, partnames)
446 446 self._parts.update(m)
447 447
448 448 if self._parts['docheader']:
449 449 self.ui.write(self.t.render(self._parts['docheader'], {}))
450 450
451 451 def close(self):
452 452 if self._parts['docfooter']:
453 453 if not self.footer:
454 454 self.footer = ""
455 455 self.footer += self.t.render(self._parts['docfooter'], {})
456 456 return super(changesettemplater, self).close()
457 457
458 458 def _show(self, ctx, copies, props):
459 459 '''show a single changeset or file revision'''
460 460 props = props.copy()
461 461 props['ctx'] = ctx
462 462 props['index'] = index = next(self._counter)
463 463 props['revcache'] = {'copies': copies}
464 464 graphwidth = props.get('graphwidth', 0)
465 465
466 466 # write separator, which wouldn't work well with the header part below
467 467 # since there's inherently a conflict between header (across items) and
468 468 # separator (per item)
469 469 if self._parts['separator'] and index > 0:
470 470 self.ui.write(self.t.render(self._parts['separator'], {}))
471 471
472 472 # write header
473 473 if self._parts['header']:
474 474 h = self.t.render(self._parts['header'], props)
475 475 if self.buffered:
476 476 self.header[ctx.rev()] = h
477 477 else:
478 478 if self.lastheader != h:
479 479 self.lastheader = h
480 480 self.ui.write(h)
481 481
482 482 # write changeset metadata, then patch if requested
483 483 key = self._parts[self._tref]
484 484 self.ui.write(self.t.render(key, props))
485 485 self._showpatch(ctx, graphwidth)
486 486
487 487 if self._parts['footer']:
488 488 if not self.footer:
489 489 self.footer = self.t.render(self._parts['footer'], props)
490 490
491 491 def templatespec(tmpl, mapfile):
492 492 if pycompat.ispy3:
493 493 assert not isinstance(tmpl, str), 'tmpl must not be a str'
494 494 if mapfile:
495 495 return formatter.templatespec('changeset', tmpl, mapfile)
496 496 else:
497 497 return formatter.templatespec('', tmpl, None)
498 498
499 499 def _lookuptemplate(ui, tmpl, style):
500 500 """Find the template matching the given template spec or style
501 501
502 502 See formatter.lookuptemplate() for details.
503 503 """
504 504
505 505 # ui settings
506 506 if not tmpl and not style: # template are stronger than style
507 507 tmpl = ui.config('ui', 'logtemplate')
508 508 if tmpl:
509 509 return templatespec(templater.unquotestring(tmpl), None)
510 510 else:
511 511 style = util.expandpath(ui.config('ui', 'style'))
512 512
513 513 if not tmpl and style:
514 514 mapfile = style
515 515 if not os.path.split(mapfile)[0]:
516 516 mapname = (templater.templatepath('map-cmdline.' + mapfile)
517 517 or templater.templatepath(mapfile))
518 518 if mapname:
519 519 mapfile = mapname
520 520 return templatespec(None, mapfile)
521 521
522 522 if not tmpl:
523 523 return templatespec(None, None)
524 524
525 525 return formatter.lookuptemplate(ui, 'changeset', tmpl)
526 526
527 527 def maketemplater(ui, repo, tmpl, buffered=False):
528 528 """Create a changesettemplater from a literal template 'tmpl'
529 529 byte-string."""
530 530 spec = templatespec(tmpl, None)
531 531 return changesettemplater(ui, repo, spec, buffered=buffered)
532 532
533 533 def changesetdisplayer(ui, repo, opts, differ=None, buffered=False):
534 534 """show one changeset using template or regular display.
535 535
536 536 Display format will be the first non-empty hit of:
537 537 1. option 'template'
538 538 2. option 'style'
539 539 3. [ui] setting 'logtemplate'
540 540 4. [ui] setting 'style'
541 541 If all of these values are either the unset or the empty string,
542 542 regular display via changesetprinter() is done.
543 543 """
544 544 postargs = (differ, opts, buffered)
545 545 if opts.get('template') in {'cbor', 'json'}:
546 546 fm = ui.formatter('log', opts)
547 547 return changesetformatter(ui, repo, fm, *postargs)
548 548
549 549 spec = _lookuptemplate(ui, opts.get('template'), opts.get('style'))
550 550
551 551 if not spec.ref and not spec.tmpl and not spec.mapfile:
552 552 return changesetprinter(ui, repo, *postargs)
553 553
554 554 return changesettemplater(ui, repo, spec, *postargs)
555 555
556 556 def _makematcher(repo, revs, pats, opts):
557 557 """Build matcher and expanded patterns from log options
558 558
559 559 If --follow, revs are the revisions to follow from.
560 560
561 561 Returns (match, pats, slowpath) where
562 562 - match: a matcher built from the given pats and -I/-X opts
563 563 - pats: patterns used (globs are expanded on Windows)
564 564 - slowpath: True if patterns aren't as simple as scanning filelogs
565 565 """
566 566 # pats/include/exclude are passed to match.match() directly in
567 567 # _matchfiles() revset but walkchangerevs() builds its matcher with
568 568 # scmutil.match(). The difference is input pats are globbed on
569 569 # platforms without shell expansion (windows).
570 570 wctx = repo[None]
571 571 match, pats = scmutil.matchandpats(wctx, pats, opts)
572 572 slowpath = match.anypats() or (not match.always() and opts.get('removed'))
573 573 if not slowpath:
574 574 follow = opts.get('follow') or opts.get('follow_first')
575 575 startctxs = []
576 576 if follow and opts.get('rev'):
577 577 startctxs = [repo[r] for r in revs]
578 578 for f in match.files():
579 579 if follow and startctxs:
580 580 # No idea if the path was a directory at that revision, so
581 581 # take the slow path.
582 582 if any(f not in c for c in startctxs):
583 583 slowpath = True
584 584 continue
585 585 elif follow and f not in wctx:
586 586 # If the file exists, it may be a directory, so let it
587 587 # take the slow path.
588 588 if os.path.exists(repo.wjoin(f)):
589 589 slowpath = True
590 590 continue
591 591 else:
592 592 raise error.Abort(_('cannot follow file not in parent '
593 593 'revision: "%s"') % f)
594 594 filelog = repo.file(f)
595 595 if not filelog:
596 596 # A zero count may be a directory or deleted file, so
597 597 # try to find matching entries on the slow path.
598 598 if follow:
599 599 raise error.Abort(
600 600 _('cannot follow nonexistent file: "%s"') % f)
601 601 slowpath = True
602 602
603 603 # We decided to fall back to the slowpath because at least one
604 604 # of the paths was not a file. Check to see if at least one of them
605 605 # existed in history - in that case, we'll continue down the
606 606 # slowpath; otherwise, we can turn off the slowpath
607 607 if slowpath:
608 608 for path in match.files():
609 609 if path == '.' or path in repo.store:
610 610 break
611 611 else:
612 612 slowpath = False
613 613
614 614 return match, pats, slowpath
615 615
616 616 def _fileancestors(repo, revs, match, followfirst):
617 617 fctxs = []
618 618 for r in revs:
619 619 ctx = repo[r]
620 620 fctxs.extend(ctx[f].introfilectx() for f in ctx.walk(match))
621 621
622 622 # When displaying a revision with --patch --follow FILE, we have
623 623 # to know which file of the revision must be diffed. With
624 624 # --follow, we want the names of the ancestors of FILE in the
625 625 # revision, stored in "fcache". "fcache" is populated as a side effect
626 626 # of the graph traversal.
627 627 fcache = {}
628 628 def filematcher(ctx):
629 629 return scmutil.matchfiles(repo, fcache.get(ctx.rev(), []))
630 630
631 631 def revgen():
632 632 for rev, cs in dagop.filectxancestors(fctxs, followfirst=followfirst):
633 633 fcache[rev] = [c.path() for c in cs]
634 634 yield rev
635 635 return smartset.generatorset(revgen(), iterasc=False), filematcher
636 636
637 637 def _makenofollowfilematcher(repo, pats, opts):
638 638 '''hook for extensions to override the filematcher for non-follow cases'''
639 639 return None
640 640
641 641 _opt2logrevset = {
642 642 'no_merges': ('not merge()', None),
643 643 'only_merges': ('merge()', None),
644 644 '_matchfiles': (None, '_matchfiles(%ps)'),
645 645 'date': ('date(%s)', None),
646 646 'branch': ('branch(%s)', '%lr'),
647 647 '_patslog': ('filelog(%s)', '%lr'),
648 648 'keyword': ('keyword(%s)', '%lr'),
649 649 'prune': ('ancestors(%s)', 'not %lr'),
650 650 'user': ('user(%s)', '%lr'),
651 651 }
652 652
653 653 def _makerevset(repo, match, pats, slowpath, opts):
654 654 """Return a revset string built from log options and file patterns"""
655 655 opts = dict(opts)
656 656 # follow or not follow?
657 657 follow = opts.get('follow') or opts.get('follow_first')
658 658
659 659 # branch and only_branch are really aliases and must be handled at
660 660 # the same time
661 661 opts['branch'] = opts.get('branch', []) + opts.get('only_branch', [])
662 662 opts['branch'] = [repo.lookupbranch(b) for b in opts['branch']]
663 663
664 664 if slowpath:
665 665 # See walkchangerevs() slow path.
666 666 #
667 667 # pats/include/exclude cannot be represented as separate
668 668 # revset expressions as their filtering logic applies at file
669 669 # level. For instance "-I a -X b" matches a revision touching
670 670 # "a" and "b" while "file(a) and not file(b)" does
671 671 # not. Besides, filesets are evaluated against the working
672 672 # directory.
673 673 matchargs = ['r:', 'd:relpath']
674 674 for p in pats:
675 675 matchargs.append('p:' + p)
676 676 for p in opts.get('include', []):
677 677 matchargs.append('i:' + p)
678 678 for p in opts.get('exclude', []):
679 679 matchargs.append('x:' + p)
680 680 opts['_matchfiles'] = matchargs
681 681 elif not follow:
682 682 opts['_patslog'] = list(pats)
683 683
684 684 expr = []
685 685 for op, val in sorted(opts.iteritems()):
686 686 if not val:
687 687 continue
688 688 if op not in _opt2logrevset:
689 689 continue
690 690 revop, listop = _opt2logrevset[op]
691 691 if revop and '%' not in revop:
692 692 expr.append(revop)
693 693 elif not listop:
694 694 expr.append(revsetlang.formatspec(revop, val))
695 695 else:
696 696 if revop:
697 697 val = [revsetlang.formatspec(revop, v) for v in val]
698 698 expr.append(revsetlang.formatspec(listop, val))
699 699
700 700 if expr:
701 701 expr = '(' + ' and '.join(expr) + ')'
702 702 else:
703 703 expr = None
704 704 return expr
705 705
706 706 def _initialrevs(repo, opts):
707 707 """Return the initial set of revisions to be filtered or followed"""
708 708 follow = opts.get('follow') or opts.get('follow_first')
709 709 if opts.get('rev'):
710 710 revs = scmutil.revrange(repo, opts['rev'])
711 711 elif follow and repo.dirstate.p1() == nullid:
712 712 revs = smartset.baseset()
713 713 elif follow:
714 714 revs = repo.revs('.')
715 715 else:
716 716 revs = smartset.spanset(repo)
717 717 revs.reverse()
718 718 return revs
719 719
720 720 def getrevs(repo, pats, opts):
721 721 """Return (revs, differ) where revs is a smartset
722 722
723 723 differ is a changesetdiffer with pre-configured file matcher.
724 724 """
725 725 follow = opts.get('follow') or opts.get('follow_first')
726 726 followfirst = opts.get('follow_first')
727 727 limit = getlimit(opts)
728 728 revs = _initialrevs(repo, opts)
729 729 if not revs:
730 730 return smartset.baseset(), None
731 731 match, pats, slowpath = _makematcher(repo, revs, pats, opts)
732 732 filematcher = None
733 733 if follow:
734 734 if slowpath or match.always():
735 735 revs = dagop.revancestors(repo, revs, followfirst=followfirst)
736 736 else:
737 737 revs, filematcher = _fileancestors(repo, revs, match, followfirst)
738 738 revs.reverse()
739 739 if filematcher is None:
740 740 filematcher = _makenofollowfilematcher(repo, pats, opts)
741 741 if filematcher is None:
742 742 def filematcher(ctx):
743 743 return match
744 744
745 745 expr = _makerevset(repo, match, pats, slowpath, opts)
746 746 if opts.get('graph') and opts.get('rev'):
747 747 # User-specified revs might be unsorted, but don't sort before
748 748 # _makerevset because it might depend on the order of revs
749 749 if not (revs.isdescending() or revs.istopo()):
750 750 revs.sort(reverse=True)
751 751 if expr:
752 752 matcher = revset.match(None, expr)
753 753 revs = matcher(repo, revs)
754 754 if limit is not None:
755 755 revs = revs.slice(0, limit)
756 756
757 757 differ = changesetdiffer()
758 758 differ._makefilematcher = filematcher
759 759 return revs, differ
760 760
761 761 def _parselinerangeopt(repo, opts):
762 762 """Parse --line-range log option and return a list of tuples (filename,
763 763 (fromline, toline)).
764 764 """
765 765 linerangebyfname = []
766 766 for pat in opts.get('line_range', []):
767 767 try:
768 768 pat, linerange = pat.rsplit(',', 1)
769 769 except ValueError:
770 770 raise error.Abort(_('malformatted line-range pattern %s') % pat)
771 771 try:
772 772 fromline, toline = map(int, linerange.split(':'))
773 773 except ValueError:
774 774 raise error.Abort(_("invalid line range for %s") % pat)
775 775 msg = _("line range pattern '%s' must match exactly one file") % pat
776 776 fname = scmutil.parsefollowlinespattern(repo, None, pat, msg)
777 777 linerangebyfname.append(
778 778 (fname, util.processlinerange(fromline, toline)))
779 779 return linerangebyfname
780 780
781 781 def getlinerangerevs(repo, userrevs, opts):
782 782 """Return (revs, differ).
783 783
784 784 "revs" are revisions obtained by processing "line-range" log options and
785 785 walking block ancestors of each specified file/line-range.
786 786
787 787 "differ" is a changesetdiffer with pre-configured file matcher and hunks
788 788 filter.
789 789 """
790 790 wctx = repo[None]
791 791
792 792 # Two-levels map of "rev -> file ctx -> [line range]".
793 793 linerangesbyrev = {}
794 794 for fname, (fromline, toline) in _parselinerangeopt(repo, opts):
795 795 if fname not in wctx:
796 796 raise error.Abort(_('cannot follow file not in parent '
797 797 'revision: "%s"') % fname)
798 798 fctx = wctx.filectx(fname)
799 799 for fctx, linerange in dagop.blockancestors(fctx, fromline, toline):
800 800 rev = fctx.introrev()
801 801 if rev not in userrevs:
802 802 continue
803 803 linerangesbyrev.setdefault(
804 804 rev, {}).setdefault(
805 805 fctx.path(), []).append(linerange)
806 806
807 807 def nofilterhunksfn(fctx, hunks):
808 808 return hunks
809 809
810 810 def hunksfilter(ctx):
811 811 fctxlineranges = linerangesbyrev.get(ctx.rev())
812 812 if fctxlineranges is None:
813 813 return nofilterhunksfn
814 814
815 815 def filterfn(fctx, hunks):
816 816 lineranges = fctxlineranges.get(fctx.path())
817 817 if lineranges is not None:
818 818 for hr, lines in hunks:
819 819 if hr is None: # binary
820 820 yield hr, lines
821 821 continue
822 822 if any(mdiff.hunkinrange(hr[2:], lr)
823 823 for lr in lineranges):
824 824 yield hr, lines
825 825 else:
826 826 for hunk in hunks:
827 827 yield hunk
828 828
829 829 return filterfn
830 830
831 831 def filematcher(ctx):
832 832 files = list(linerangesbyrev.get(ctx.rev(), []))
833 833 return scmutil.matchfiles(repo, files)
834 834
835 835 revs = sorted(linerangesbyrev, reverse=True)
836 836
837 837 differ = changesetdiffer()
838 838 differ._makefilematcher = filematcher
839 839 differ._makehunksfilter = hunksfilter
840 840 return revs, differ
841 841
842 842 def _graphnodeformatter(ui, displayer):
843 843 spec = ui.config('ui', 'graphnodetemplate')
844 844 if not spec:
845 845 return templatekw.getgraphnode # fast path for "{graphnode}"
846 846
847 847 spec = templater.unquotestring(spec)
848 848 if isinstance(displayer, changesettemplater):
849 849 # reuse cache of slow templates
850 850 tres = displayer._tresources
851 851 else:
852 852 tres = formatter.templateresources(ui)
853 853 templ = formatter.maketemplater(ui, spec, defaults=templatekw.keywords,
854 854 resources=tres)
855 855 def formatnode(repo, ctx):
856 856 props = {'ctx': ctx, 'repo': repo}
857 857 return templ.renderdefault(props)
858 858 return formatnode
859 859
860 860 def displaygraph(ui, repo, dag, displayer, edgefn, getrenamed=None, props=None):
861 861 props = props or {}
862 862 formatnode = _graphnodeformatter(ui, displayer)
863 863 state = graphmod.asciistate()
864 864 styles = state['styles']
865 865
866 866 # only set graph styling if HGPLAIN is not set.
867 867 if ui.plain('graph'):
868 868 # set all edge styles to |, the default pre-3.8 behaviour
869 869 styles.update(dict.fromkeys(styles, '|'))
870 870 else:
871 871 edgetypes = {
872 872 'parent': graphmod.PARENT,
873 873 'grandparent': graphmod.GRANDPARENT,
874 874 'missing': graphmod.MISSINGPARENT
875 875 }
876 876 for name, key in edgetypes.items():
877 877 # experimental config: experimental.graphstyle.*
878 878 styles[key] = ui.config('experimental', 'graphstyle.%s' % name,
879 879 styles[key])
880 880 if not styles[key]:
881 881 styles[key] = None
882 882
883 883 # experimental config: experimental.graphshorten
884 884 state['graphshorten'] = ui.configbool('experimental', 'graphshorten')
885 885
886 886 for rev, type, ctx, parents in dag:
887 887 char = formatnode(repo, ctx)
888 888 copies = None
889 889 if getrenamed and ctx.rev():
890 890 copies = []
891 891 for fn in ctx.files():
892 892 rename = getrenamed(fn, ctx.rev())
893 893 if rename:
894 894 copies.append((fn, rename))
895 895 edges = edgefn(type, char, state, rev, parents)
896 896 firstedge = next(edges)
897 897 width = firstedge[2]
898 898 displayer.show(ctx, copies=copies,
899 899 graphwidth=width, **pycompat.strkwargs(props))
900 900 lines = displayer.hunk.pop(rev).split('\n')
901 901 if not lines[-1]:
902 902 del lines[-1]
903 903 displayer.flush(ctx)
904 904 for type, char, width, coldata in itertools.chain([firstedge], edges):
905 905 graphmod.ascii(ui, state, type, char, lines, coldata)
906 906 lines = []
907 907 displayer.close()
908 908
909 909 def displaygraphrevs(ui, repo, revs, displayer, getrenamed):
910 910 revdag = graphmod.dagwalker(repo, revs)
911 911 displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges, getrenamed)
912 912
913 913 def displayrevs(ui, repo, revs, displayer, getrenamed):
914 914 for rev in revs:
915 915 ctx = repo[rev]
916 916 copies = None
917 917 if getrenamed is not None and rev:
918 918 copies = []
919 919 for fn in ctx.files():
920 920 rename = getrenamed(fn, rev)
921 921 if rename:
922 922 copies.append((fn, rename))
923 923 displayer.show(ctx, copies=copies)
924 924 displayer.flush(ctx)
925 925 displayer.close()
926 926
927 927 def checkunsupportedgraphflags(pats, opts):
928 928 for op in ["newest_first"]:
929 929 if op in opts and opts[op]:
930 930 raise error.Abort(_("-G/--graph option is incompatible with --%s")
931 931 % op.replace("_", "-"))
932 932
933 933 def graphrevs(repo, nodes, opts):
934 934 limit = getlimit(opts)
935 935 nodes.reverse()
936 936 if limit is not None:
937 937 nodes = nodes[:limit]
938 938 return graphmod.nodes(repo, nodes)
@@ -1,1997 +1,2010 b''
1 1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5 5
6 6 $ hg init t
7 7 $ cd t
8 8
9 9 first revision, no sub
10 10
11 11 $ echo a > a
12 12 $ hg ci -Am0
13 13 adding a
14 14
15 15 add first sub
16 16
17 17 $ echo s = s > .hgsub
18 18 $ hg add .hgsub
19 19 $ hg init s
20 20 $ echo a > s/a
21 21
22 22 Issue2232: committing a subrepo without .hgsub
23 23
24 24 $ hg ci -mbad s
25 25 abort: can't commit subrepos without .hgsub
26 26 [255]
27 27
28 28 $ hg -R s add s/a
29 29 $ hg files -S
30 30 .hgsub
31 31 a
32 32 s/a
33 33
34 34 `hg files` respects ui.relative-paths
35 35 BROKEN: shows subrepo paths relative to the subrepo
36 36 $ hg files -S --config ui.relative-paths=no
37 37 .hgsub
38 38 a
39 39 s/a
40 40
41 41 $ hg -R s ci -Ams0
42 42 $ hg sum
43 43 parent: 0:f7b1eb17ad24 tip
44 44 0
45 45 branch: default
46 46 commit: 1 added, 1 subrepos
47 47 update: (current)
48 48 phases: 1 draft
49 49 $ hg ci -m1
50 50
51 51 test handling .hgsubstate "added" explicitly.
52 52
53 53 $ hg parents --template '{node}\n{files}\n'
54 54 7cf8cfea66e410e8e3336508dfeec07b3192de51
55 55 .hgsub .hgsubstate
56 56 $ hg rollback -q
57 57 $ hg add .hgsubstate
58 58 $ hg ci -m1
59 59 $ hg parents --template '{node}\n{files}\n'
60 60 7cf8cfea66e410e8e3336508dfeec07b3192de51
61 61 .hgsub .hgsubstate
62 62
63 63 Subrepopath which overlaps with filepath, does not change warnings in remove()
64 64
65 65 $ mkdir snot
66 66 $ touch snot/file
67 67 $ hg remove -S snot/file
68 68 not removing snot/file: file is untracked
69 69 [1]
70 70 $ hg cat snot/filenot
71 71 snot/filenot: no such file in rev 7cf8cfea66e4
72 72 [1]
73 73 $ rm -r snot
74 74
75 75 Revert subrepo and test subrepo fileset keyword:
76 76
77 77 $ echo b > s/a
78 78 $ hg revert --dry-run "set:subrepo('glob:s*')"
79 79 reverting subrepo s
80 80 reverting s/a
81 81 $ cat s/a
82 82 b
83 83 $ hg revert "set:subrepo('glob:s*')"
84 84 reverting subrepo s
85 85 reverting s/a
86 86 $ cat s/a
87 87 a
88 88 $ rm s/a.orig
89 89
90 90 Revert subrepo with no backup. The "reverting s/a" line is gone since
91 91 we're really running 'hg update' in the subrepo:
92 92
93 93 $ echo b > s/a
94 94 $ hg revert --no-backup s
95 95 reverting subrepo s
96 96
97 97 Issue2022: update -C
98 98
99 99 $ echo b > s/a
100 100 $ hg sum
101 101 parent: 1:7cf8cfea66e4 tip
102 102 1
103 103 branch: default
104 104 commit: 1 subrepos
105 105 update: (current)
106 106 phases: 2 draft
107 107 $ hg co -C 1
108 108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 $ hg sum
110 110 parent: 1:7cf8cfea66e4 tip
111 111 1
112 112 branch: default
113 113 commit: (clean)
114 114 update: (current)
115 115 phases: 2 draft
116 116
117 117 commands that require a clean repo should respect subrepos
118 118
119 119 $ echo b >> s/a
120 120 $ hg backout tip
121 121 abort: uncommitted changes in subrepository "s"
122 122 [255]
123 123 $ hg revert -C -R s s/a
124 124
125 125 add sub sub
126 126
127 127 $ echo ss = ss > s/.hgsub
128 128 $ hg init s/ss
129 129 $ echo a > s/ss/a
130 130 $ hg -R s add s/.hgsub
131 131 $ hg -R s/ss add s/ss/a
132 132 $ hg sum
133 133 parent: 1:7cf8cfea66e4 tip
134 134 1
135 135 branch: default
136 136 commit: 1 subrepos
137 137 update: (current)
138 138 phases: 2 draft
139 139 $ hg ci -m2
140 140 committing subrepository s
141 141 committing subrepository s/ss
142 142 $ hg sum
143 143 parent: 2:df30734270ae tip
144 144 2
145 145 branch: default
146 146 commit: (clean)
147 147 update: (current)
148 148 phases: 3 draft
149 149
150 150 test handling .hgsubstate "modified" explicitly.
151 151
152 152 $ hg parents --template '{node}\n{files}\n'
153 153 df30734270ae757feb35e643b7018e818e78a9aa
154 154 .hgsubstate
155 155 $ hg rollback -q
156 156 $ hg status -A .hgsubstate
157 157 M .hgsubstate
158 158 $ hg ci -m2
159 159 $ hg parents --template '{node}\n{files}\n'
160 160 df30734270ae757feb35e643b7018e818e78a9aa
161 161 .hgsubstate
162 162
163 163 bump sub rev (and check it is ignored by ui.commitsubrepos)
164 164
165 165 $ echo b > s/a
166 166 $ hg -R s ci -ms1
167 167 $ hg --config ui.commitsubrepos=no ci -m3
168 168
169 169 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
170 170
171 171 $ echo c > s/a
172 172 $ hg --config ui.commitsubrepos=no ci -m4
173 173 abort: uncommitted changes in subrepository "s"
174 174 (use --subrepos for recursive commit)
175 175 [255]
176 176 $ hg id
177 177 f6affe3fbfaa+ tip
178 178 $ hg -R s ci -mc
179 179 $ hg id
180 180 f6affe3fbfaa+ tip
181 181 $ echo d > s/a
182 182 $ hg ci -m4
183 183 committing subrepository s
184 184 $ hg tip -R s
185 185 changeset: 4:02dcf1d70411
186 186 tag: tip
187 187 user: test
188 188 date: Thu Jan 01 00:00:00 1970 +0000
189 189 summary: 4
190 190
191 191
192 192 check caching
193 193
194 194 $ hg co 0
195 195 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
196 196 $ hg debugsub
197 197
198 198 restore
199 199
200 200 $ hg co
201 201 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 202 $ hg debugsub
203 203 path s
204 204 source s
205 205 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
206 206
207 207 new branch for merge tests
208 208
209 209 $ hg co 1
210 210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 211 $ echo t = t >> .hgsub
212 212 $ hg init t
213 213 $ echo t > t/t
214 214 $ hg -R t add t
215 215 adding t/t
216 216
217 217 5
218 218
219 219 $ hg ci -m5 # add sub
220 220 committing subrepository t
221 221 created new head
222 222 $ echo t2 > t/t
223 223
224 224 6
225 225
226 226 $ hg st -R s
227 227 $ hg ci -m6 # change sub
228 228 committing subrepository t
229 229 $ hg debugsub
230 230 path s
231 231 source s
232 232 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
233 233 path t
234 234 source t
235 235 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
236 236 $ echo t3 > t/t
237 237
238 238 7
239 239
240 240 $ hg ci -m7 # change sub again for conflict test
241 241 committing subrepository t
242 242 $ hg rm .hgsub
243 243
244 244 8
245 245
246 246 $ hg ci -m8 # remove sub
247 247
248 248 test handling .hgsubstate "removed" explicitly.
249 249
250 250 $ hg parents --template '{node}\n{files}\n'
251 251 96615c1dad2dc8e3796d7332c77ce69156f7b78e
252 252 .hgsub .hgsubstate
253 253 $ hg rollback -q
254 254 $ hg remove .hgsubstate
255 255 $ hg ci -m8
256 256 $ hg parents --template '{node}\n{files}\n'
257 257 96615c1dad2dc8e3796d7332c77ce69156f7b78e
258 258 .hgsub .hgsubstate
259 259
260 260 merge tests
261 261
262 262 $ hg co -C 3
263 263 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 264 $ hg merge 5 # test adding
265 265 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 266 (branch merge, don't forget to commit)
267 267 $ hg debugsub
268 268 path s
269 269 source s
270 270 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
271 271 path t
272 272 source t
273 273 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
274 274 $ hg ci -m9
275 275 created new head
276 276 $ hg merge 6 --debug # test change
277 277 searching for copies back to rev 2
278 278 resolving manifests
279 279 branchmerge: True, force: False, partial: False
280 280 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
281 281 starting 4 threads for background file closing (?)
282 282 .hgsubstate: versions differ -> m (premerge)
283 283 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
284 284 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
285 285 getting subrepo t
286 286 resolving manifests
287 287 branchmerge: False, force: False, partial: False
288 288 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
289 289 t: remote is newer -> g
290 290 getting t
291 291 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
292 292 (branch merge, don't forget to commit)
293 293 $ hg debugsub
294 294 path s
295 295 source s
296 296 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
297 297 path t
298 298 source t
299 299 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
300 300 $ echo conflict > t/t
301 301 $ hg ci -m10
302 302 committing subrepository t
303 303 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
304 304 searching for copies back to rev 2
305 305 resolving manifests
306 306 branchmerge: True, force: False, partial: False
307 307 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
308 308 starting 4 threads for background file closing (?)
309 309 .hgsubstate: versions differ -> m (premerge)
310 310 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
311 311 subrepo t: both sides changed
312 312 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
313 313 starting 4 threads for background file closing (?)
314 314 (M)erge, keep (l)ocal [working copy] or keep (r)emote [merge rev]? m
315 315 merging subrepository "t"
316 316 searching for copies back to rev 2
317 317 resolving manifests
318 318 branchmerge: True, force: False, partial: False
319 319 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
320 320 preserving t for resolve of t
321 321 starting 4 threads for background file closing (?)
322 322 t: versions differ -> m (premerge)
323 323 picked tool ':merge' for t (binary False symlink False changedelete False)
324 324 merging t
325 325 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
326 326 t: versions differ -> m (merge)
327 327 picked tool ':merge' for t (binary False symlink False changedelete False)
328 328 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
329 329 warning: conflicts while merging t! (edit, then use 'hg resolve --mark')
330 330 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
331 331 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
332 332 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
333 333 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 334 (branch merge, don't forget to commit)
335 335
336 336 should conflict
337 337
338 338 $ cat t/t
339 339 <<<<<<< local: 20a0db6fbf6c - test: 10
340 340 conflict
341 341 =======
342 342 t3
343 343 >>>>>>> other: 7af322bc1198 - test: 7
344 344
345 345 11: remove subrepo t
346 346
347 347 $ hg co -C 5
348 348 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
349 349 $ hg revert -r 4 .hgsub # remove t
350 350 $ hg ci -m11
351 351 created new head
352 352 $ hg debugsub
353 353 path s
354 354 source s
355 355 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
356 356
357 357 local removed, remote changed, keep changed
358 358
359 359 $ hg merge 6
360 360 remote [merge rev] changed subrepository t which local [working copy] removed
361 361 use (c)hanged version or (d)elete? c
362 362 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 363 (branch merge, don't forget to commit)
364 364 BROKEN: should include subrepo t
365 365 $ hg debugsub
366 366 path s
367 367 source s
368 368 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
369 369 $ cat .hgsubstate
370 370 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
371 371 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
372 372 $ hg ci -m 'local removed, remote changed, keep changed'
373 373 BROKEN: should include subrepo t
374 374 $ hg debugsub
375 375 path s
376 376 source s
377 377 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
378 378 BROKEN: should include subrepo t
379 379 $ cat .hgsubstate
380 380 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
381 381 $ cat t/t
382 382 t2
383 383
384 384 local removed, remote changed, keep removed
385 385
386 386 $ hg co -C 11
387 387 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 388 $ hg merge --config ui.interactive=true 6 <<EOF
389 389 > d
390 390 > EOF
391 391 remote [merge rev] changed subrepository t which local [working copy] removed
392 392 use (c)hanged version or (d)elete? d
393 393 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
394 394 (branch merge, don't forget to commit)
395 395 $ hg debugsub
396 396 path s
397 397 source s
398 398 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
399 399 $ cat .hgsubstate
400 400 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
401 401 $ hg ci -m 'local removed, remote changed, keep removed'
402 402 created new head
403 403 $ hg debugsub
404 404 path s
405 405 source s
406 406 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
407 407 $ cat .hgsubstate
408 408 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
409 409
410 410 local changed, remote removed, keep changed
411 411
412 412 $ hg co -C 6
413 413 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 414 $ hg merge 11
415 415 local [working copy] changed subrepository t which remote [merge rev] removed
416 416 use (c)hanged version or (d)elete? c
417 417 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
418 418 (branch merge, don't forget to commit)
419 419 BROKEN: should include subrepo t
420 420 $ hg debugsub
421 421 path s
422 422 source s
423 423 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
424 424 BROKEN: should include subrepo t
425 425 $ cat .hgsubstate
426 426 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
427 427 $ hg ci -m 'local changed, remote removed, keep changed'
428 428 created new head
429 429 BROKEN: should include subrepo t
430 430 $ hg debugsub
431 431 path s
432 432 source s
433 433 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
434 434 BROKEN: should include subrepo t
435 435 $ cat .hgsubstate
436 436 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
437 437 $ cat t/t
438 438 t2
439 439
440 440 local changed, remote removed, keep removed
441 441
442 442 $ hg co -C 6
443 443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 444 $ hg merge --config ui.interactive=true 11 <<EOF
445 445 > d
446 446 > EOF
447 447 local [working copy] changed subrepository t which remote [merge rev] removed
448 448 use (c)hanged version or (d)elete? d
449 449 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 450 (branch merge, don't forget to commit)
451 451 $ hg debugsub
452 452 path s
453 453 source s
454 454 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
455 455 $ cat .hgsubstate
456 456 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
457 457 $ hg ci -m 'local changed, remote removed, keep removed'
458 458 created new head
459 459 $ hg debugsub
460 460 path s
461 461 source s
462 462 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
463 463 $ cat .hgsubstate
464 464 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
465 465
466 466 clean up to avoid having to fix up the tests below
467 467
468 468 $ hg co -C 10
469 469 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 470 $ cat >> $HGRCPATH <<EOF
471 471 > [extensions]
472 472 > strip=
473 473 > EOF
474 474 $ hg strip -r 11:15
475 475 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
476 476
477 477 clone
478 478
479 479 $ cd ..
480 480 $ hg clone t tc
481 481 updating to branch default
482 482 cloning subrepo s from $TESTTMP/t/s
483 483 cloning subrepo s/ss from $TESTTMP/t/s/ss
484 484 cloning subrepo t from $TESTTMP/t/t
485 485 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 486 $ cd tc
487 487 $ hg debugsub
488 488 path s
489 489 source s
490 490 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
491 491 path t
492 492 source t
493 493 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
494 494 $ cd ..
495 495
496 496 clone with subrepo disabled (update should fail)
497 497
498 498 $ hg clone t -U tc2 --config subrepos.allowed=false
499 499 $ hg update -R tc2 --config subrepos.allowed=false
500 500 abort: subrepos not enabled
501 501 (see 'hg help config.subrepos' for details)
502 502 [255]
503 503 $ ls tc2
504 504 a
505 505
506 506 $ hg clone t tc3 --config subrepos.allowed=false
507 507 updating to branch default
508 508 abort: subrepos not enabled
509 509 (see 'hg help config.subrepos' for details)
510 510 [255]
511 511 $ ls tc3
512 512 a
513 513
514 514 And again with just the hg type disabled
515 515
516 516 $ hg clone t -U tc4 --config subrepos.hg:allowed=false
517 517 $ hg update -R tc4 --config subrepos.hg:allowed=false
518 518 abort: hg subrepos not allowed
519 519 (see 'hg help config.subrepos' for details)
520 520 [255]
521 521 $ ls tc4
522 522 a
523 523
524 524 $ hg clone t tc5 --config subrepos.hg:allowed=false
525 525 updating to branch default
526 526 abort: hg subrepos not allowed
527 527 (see 'hg help config.subrepos' for details)
528 528 [255]
529 529 $ ls tc5
530 530 a
531 531
532 532 push
533 533
534 534 $ cd tc
535 535 $ echo bah > t/t
536 536 $ hg ci -m11
537 537 committing subrepository t
538 538 $ hg push
539 539 pushing to $TESTTMP/t
540 540 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
541 541 no changes made to subrepo s since last push to $TESTTMP/t/s
542 542 pushing subrepo t to $TESTTMP/t/t
543 543 searching for changes
544 544 adding changesets
545 545 adding manifests
546 546 adding file changes
547 547 added 1 changesets with 1 changes to 1 files
548 548 searching for changes
549 549 adding changesets
550 550 adding manifests
551 551 adding file changes
552 552 added 1 changesets with 1 changes to 1 files
553 553
554 554 push -f
555 555
556 556 $ echo bah > s/a
557 557 $ hg ci -m12
558 558 committing subrepository s
559 559 $ hg push
560 560 pushing to $TESTTMP/t
561 561 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
562 562 pushing subrepo s to $TESTTMP/t/s
563 563 searching for changes
564 564 abort: push creates new remote head 12a213df6fa9! (in subrepository "s")
565 565 (merge or see 'hg help push' for details about pushing new heads)
566 566 [255]
567 567 $ hg push -f
568 568 pushing to $TESTTMP/t
569 569 pushing subrepo s/ss to $TESTTMP/t/s/ss
570 570 searching for changes
571 571 no changes found
572 572 pushing subrepo s to $TESTTMP/t/s
573 573 searching for changes
574 574 adding changesets
575 575 adding manifests
576 576 adding file changes
577 577 added 1 changesets with 1 changes to 1 files (+1 heads)
578 578 pushing subrepo t to $TESTTMP/t/t
579 579 searching for changes
580 580 no changes found
581 581 searching for changes
582 582 adding changesets
583 583 adding manifests
584 584 adding file changes
585 585 added 1 changesets with 1 changes to 1 files
586 586
587 587 check that unmodified subrepos are not pushed
588 588
589 589 $ hg clone . ../tcc
590 590 updating to branch default
591 591 cloning subrepo s from $TESTTMP/tc/s
592 592 cloning subrepo s/ss from $TESTTMP/tc/s/ss
593 593 cloning subrepo t from $TESTTMP/tc/t
594 594 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
595 595
596 596 the subrepos on the new clone have nothing to push to its source
597 597
598 598 $ hg push -R ../tcc .
599 599 pushing to .
600 600 no changes made to subrepo s/ss since last push to s/ss
601 601 no changes made to subrepo s since last push to s
602 602 no changes made to subrepo t since last push to t
603 603 searching for changes
604 604 no changes found
605 605 [1]
606 606
607 607 the subrepos on the source do not have a clean store versus the clone target
608 608 because they were never explicitly pushed to the source
609 609
610 610 $ hg push ../tcc
611 611 pushing to ../tcc
612 612 pushing subrepo s/ss to ../tcc/s/ss
613 613 searching for changes
614 614 no changes found
615 615 pushing subrepo s to ../tcc/s
616 616 searching for changes
617 617 no changes found
618 618 pushing subrepo t to ../tcc/t
619 619 searching for changes
620 620 no changes found
621 621 searching for changes
622 622 no changes found
623 623 [1]
624 624
625 625 after push their stores become clean
626 626
627 627 $ hg push ../tcc
628 628 pushing to ../tcc
629 629 no changes made to subrepo s/ss since last push to ../tcc/s/ss
630 630 no changes made to subrepo s since last push to ../tcc/s
631 631 no changes made to subrepo t since last push to ../tcc/t
632 632 searching for changes
633 633 no changes found
634 634 [1]
635 635
636 636 updating a subrepo to a different revision or changing
637 637 its working directory does not make its store dirty
638 638
639 639 $ hg -R s update '.^'
640 640 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
641 641 $ hg push
642 642 pushing to $TESTTMP/t
643 643 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
644 644 no changes made to subrepo s since last push to $TESTTMP/t/s
645 645 no changes made to subrepo t since last push to $TESTTMP/t/t
646 646 searching for changes
647 647 no changes found
648 648 [1]
649 649 $ echo foo >> s/a
650 650 $ hg push
651 651 pushing to $TESTTMP/t
652 652 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
653 653 no changes made to subrepo s since last push to $TESTTMP/t/s
654 654 no changes made to subrepo t since last push to $TESTTMP/t/t
655 655 searching for changes
656 656 no changes found
657 657 [1]
658 658 $ hg -R s update -C tip
659 659 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
660 660
661 661 committing into a subrepo makes its store (but not its parent's store) dirty
662 662
663 663 $ echo foo >> s/ss/a
664 664 $ hg -R s/ss commit -m 'test dirty store detection'
665 665
666 666 $ hg out -S -r `hg log -r tip -T "{node|short}"`
667 667 comparing with $TESTTMP/t
668 668 searching for changes
669 669 no changes found
670 670 comparing with $TESTTMP/t/s
671 671 searching for changes
672 672 no changes found
673 673 comparing with $TESTTMP/t/s/ss
674 674 searching for changes
675 675 changeset: 1:79ea5566a333
676 676 tag: tip
677 677 user: test
678 678 date: Thu Jan 01 00:00:00 1970 +0000
679 679 summary: test dirty store detection
680 680
681 681 comparing with $TESTTMP/t/t
682 682 searching for changes
683 683 no changes found
684 684
685 685 $ hg push
686 686 pushing to $TESTTMP/t
687 687 pushing subrepo s/ss to $TESTTMP/t/s/ss
688 688 searching for changes
689 689 adding changesets
690 690 adding manifests
691 691 adding file changes
692 692 added 1 changesets with 1 changes to 1 files
693 693 no changes made to subrepo s since last push to $TESTTMP/t/s
694 694 no changes made to subrepo t since last push to $TESTTMP/t/t
695 695 searching for changes
696 696 no changes found
697 697 [1]
698 698
699 699 a subrepo store may be clean versus one repo but not versus another
700 700
701 701 $ hg push
702 702 pushing to $TESTTMP/t
703 703 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss
704 704 no changes made to subrepo s since last push to $TESTTMP/t/s
705 705 no changes made to subrepo t since last push to $TESTTMP/t/t
706 706 searching for changes
707 707 no changes found
708 708 [1]
709 709 $ hg push ../tcc
710 710 pushing to ../tcc
711 711 pushing subrepo s/ss to ../tcc/s/ss
712 712 searching for changes
713 713 adding changesets
714 714 adding manifests
715 715 adding file changes
716 716 added 1 changesets with 1 changes to 1 files
717 717 no changes made to subrepo s since last push to ../tcc/s
718 718 no changes made to subrepo t since last push to ../tcc/t
719 719 searching for changes
720 720 no changes found
721 721 [1]
722 722
723 723 update
724 724
725 725 $ cd ../t
726 726 $ hg up -C # discard our earlier merge
727 727 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
728 728 updated to "c373c8102e68: 12"
729 729 2 other heads for branch "default"
730 730 $ echo blah > t/t
731 731 $ hg ci -m13
732 732 committing subrepository t
733 733
734 734 backout calls revert internally with minimal opts, which should not raise
735 735 KeyError
736 736
737 737 $ hg backout ".^" --no-commit
738 738 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
739 739 changeset c373c8102e68 backed out, don't forget to commit.
740 740
741 741 $ hg up -C # discard changes
742 742 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
743 743 updated to "925c17564ef8: 13"
744 744 2 other heads for branch "default"
745 745
746 746 pull
747 747
748 748 $ cd ../tc
749 749 $ hg pull
750 750 pulling from $TESTTMP/t
751 751 searching for changes
752 752 adding changesets
753 753 adding manifests
754 754 adding file changes
755 755 added 1 changesets with 1 changes to 1 files
756 756 new changesets 925c17564ef8
757 757 (run 'hg update' to get a working copy)
758 758
759 759 should pull t
760 760
761 761 $ hg incoming -S -r `hg log -r tip -T "{node|short}"`
762 762 comparing with $TESTTMP/t
763 763 no changes found
764 764 comparing with $TESTTMP/t/s
765 765 searching for changes
766 766 no changes found
767 767 comparing with $TESTTMP/t/s/ss
768 768 searching for changes
769 769 no changes found
770 770 comparing with $TESTTMP/t/t
771 771 searching for changes
772 772 changeset: 5:52c0adc0515a
773 773 tag: tip
774 774 user: test
775 775 date: Thu Jan 01 00:00:00 1970 +0000
776 776 summary: 13
777 777
778 778
779 779 $ hg up
780 780 pulling subrepo t from $TESTTMP/t/t
781 781 searching for changes
782 782 adding changesets
783 783 adding manifests
784 784 adding file changes
785 785 added 1 changesets with 1 changes to 1 files
786 786 new changesets 52c0adc0515a
787 787 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
788 788 updated to "925c17564ef8: 13"
789 789 2 other heads for branch "default"
790 790 $ cat t/t
791 791 blah
792 792
793 793 bogus subrepo path aborts
794 794
795 795 $ echo 'bogus=[boguspath' >> .hgsub
796 796 $ hg ci -m 'bogus subrepo path'
797 797 abort: missing ] in subrepository source
798 798 [255]
799 799
800 800 Issue1986: merge aborts when trying to merge a subrepo that
801 801 shouldn't need merging
802 802
803 803 # subrepo layout
804 804 #
805 805 # o 5 br
806 806 # /|
807 807 # o | 4 default
808 808 # | |
809 809 # | o 3 br
810 810 # |/|
811 811 # o | 2 default
812 812 # | |
813 813 # | o 1 br
814 814 # |/
815 815 # o 0 default
816 816
817 817 $ cd ..
818 818 $ rm -rf sub
819 819 $ hg init main
820 820 $ cd main
821 821 $ hg init s
822 822 $ cd s
823 823 $ echo a > a
824 824 $ hg ci -Am1
825 825 adding a
826 826 $ hg branch br
827 827 marked working directory as branch br
828 828 (branches are permanent and global, did you want a bookmark?)
829 829 $ echo a >> a
830 830 $ hg ci -m1
831 831 $ hg up default
832 832 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
833 833 $ echo b > b
834 834 $ hg ci -Am1
835 835 adding b
836 836 $ hg up br
837 837 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
838 838 $ hg merge tip
839 839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 840 (branch merge, don't forget to commit)
841 841 $ hg ci -m1
842 842 $ hg up 2
843 843 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
844 844 $ echo c > c
845 845 $ hg ci -Am1
846 846 adding c
847 847 $ hg up 3
848 848 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
849 849 $ hg merge 4
850 850 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
851 851 (branch merge, don't forget to commit)
852 852 $ hg ci -m1
853 853
854 854 # main repo layout:
855 855 #
856 856 # * <-- try to merge default into br again
857 857 # .`|
858 858 # . o 5 br --> substate = 5
859 859 # . |
860 860 # o | 4 default --> substate = 4
861 861 # | |
862 862 # | o 3 br --> substate = 2
863 863 # |/|
864 864 # o | 2 default --> substate = 2
865 865 # | |
866 866 # | o 1 br --> substate = 3
867 867 # |/
868 868 # o 0 default --> substate = 2
869 869
870 870 $ cd ..
871 871 $ echo 's = s' > .hgsub
872 872 $ hg -R s up 2
873 873 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
874 874 $ hg ci -Am1
875 875 adding .hgsub
876 876 $ hg branch br
877 877 marked working directory as branch br
878 878 (branches are permanent and global, did you want a bookmark?)
879 879 $ echo b > b
880 880 $ hg -R s up 3
881 881 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
882 882 $ hg ci -Am1
883 883 adding b
884 884 $ hg up default
885 885 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
886 886 $ echo c > c
887 887 $ hg ci -Am1
888 888 adding c
889 889 $ hg up 1
890 890 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
891 891 $ hg merge 2
892 892 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
893 893 (branch merge, don't forget to commit)
894 894 $ hg ci -m1
895 895 $ hg up 2
896 896 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
897 897 $ hg -R s up 4
898 898 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
899 899 $ echo d > d
900 900 $ hg ci -Am1
901 901 adding d
902 902 $ hg up 3
903 903 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
904 904 $ hg -R s up 5
905 905 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
906 906 $ echo e > e
907 907 $ hg ci -Am1
908 908 adding e
909 909
910 910 $ hg up 5
911 911 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
912 912 $ hg merge 4 # try to merge default into br again
913 913 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
914 914 (M)erge, keep (l)ocal [working copy] or keep (r)emote [merge rev]? m
915 915 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
916 916 (branch merge, don't forget to commit)
917 917 $ cd ..
918 918
919 919 test subrepo delete from .hgsubstate
920 920
921 921 $ hg init testdelete
922 922 $ mkdir testdelete/nested testdelete/nested2
923 923 $ hg init testdelete/nested
924 924 $ hg init testdelete/nested2
925 925 $ echo test > testdelete/nested/foo
926 926 $ echo test > testdelete/nested2/foo
927 927 $ hg -R testdelete/nested add
928 928 adding testdelete/nested/foo
929 929 $ hg -R testdelete/nested2 add
930 930 adding testdelete/nested2/foo
931 931 $ hg -R testdelete/nested ci -m test
932 932 $ hg -R testdelete/nested2 ci -m test
933 933 $ echo nested = nested > testdelete/.hgsub
934 934 $ echo nested2 = nested2 >> testdelete/.hgsub
935 935 $ hg -R testdelete add
936 936 adding testdelete/.hgsub
937 937 $ hg -R testdelete ci -m "nested 1 & 2 added"
938 938 $ echo nested = nested > testdelete/.hgsub
939 939 $ hg -R testdelete ci -m "nested 2 deleted"
940 940 $ cat testdelete/.hgsubstate
941 941 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
942 942 $ hg -R testdelete remove testdelete/.hgsub
943 943 $ hg -R testdelete ci -m ".hgsub deleted"
944 944 $ cat testdelete/.hgsubstate
945 945 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
946 946
947 947 test repository cloning
948 948
949 949 $ mkdir mercurial mercurial2
950 950 $ hg init nested_absolute
951 951 $ echo test > nested_absolute/foo
952 952 $ hg -R nested_absolute add
953 953 adding nested_absolute/foo
954 954 $ hg -R nested_absolute ci -mtest
955 955 $ cd mercurial
956 956 $ hg init nested_relative
957 957 $ echo test2 > nested_relative/foo2
958 958 $ hg -R nested_relative add
959 959 adding nested_relative/foo2
960 960 $ hg -R nested_relative ci -mtest2
961 961 $ hg init main
962 962 $ echo "nested_relative = ../nested_relative" > main/.hgsub
963 963 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
964 964 $ hg -R main add
965 965 adding main/.hgsub
966 966 $ hg -R main ci -m "add subrepos"
967 967 $ cd ..
968 968 $ hg clone mercurial/main mercurial2/main
969 969 updating to branch default
970 970 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
971 971 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
972 972 > mercurial2/main/nested_relative/.hg/hgrc
973 973 [paths]
974 974 default = $TESTTMP/mercurial/nested_absolute
975 975 [paths]
976 976 default = $TESTTMP/mercurial/nested_relative
977 977 $ rm -rf mercurial mercurial2
978 978
979 979 Issue1977: multirepo push should fail if subrepo push fails
980 980
981 981 $ hg init repo
982 982 $ hg init repo/s
983 983 $ echo a > repo/s/a
984 984 $ hg -R repo/s ci -Am0
985 985 adding a
986 986 $ echo s = s > repo/.hgsub
987 987 $ hg -R repo ci -Am1
988 988 adding .hgsub
989 989 $ hg clone repo repo2
990 990 updating to branch default
991 991 cloning subrepo s from $TESTTMP/repo/s
992 992 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
993 993 $ hg -q -R repo2 pull -u
994 994 $ echo 1 > repo2/s/a
995 995 $ hg -R repo2/s ci -m2
996 996 $ hg -q -R repo2/s push
997 997 $ hg -R repo2/s up -C 0
998 998 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
999 999 $ echo 2 > repo2/s/b
1000 1000 $ hg -R repo2/s ci -m3 -A
1001 1001 adding b
1002 1002 created new head
1003 1003 $ hg -R repo2 ci -m3
1004 1004 $ hg -q -R repo2 push
1005 1005 abort: push creates new remote head cc505f09a8b2! (in subrepository "s")
1006 1006 (merge or see 'hg help push' for details about pushing new heads)
1007 1007 [255]
1008 1008 $ hg -R repo update
1009 1009 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1010 1010
1011 1011 test if untracked file is not overwritten
1012 1012
1013 1013 (this also tests that updated .hgsubstate is treated as "modified",
1014 1014 when 'merge.update()' is aborted before 'merge.recordupdates()', even
1015 1015 if none of mode, size and timestamp of it isn't changed on the
1016 1016 filesystem (see also issue4583))
1017 1017
1018 1018 $ echo issue3276_ok > repo/s/b
1019 1019 $ hg -R repo2 push -f -q
1020 1020 $ touch -t 200001010000 repo/.hgsubstate
1021 1021
1022 1022 $ cat >> repo/.hg/hgrc <<EOF
1023 1023 > [fakedirstatewritetime]
1024 1024 > # emulate invoking dirstate.write() via repo.status()
1025 1025 > # at 2000-01-01 00:00
1026 1026 > fakenow = 200001010000
1027 1027 >
1028 1028 > [extensions]
1029 1029 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
1030 1030 > EOF
1031 1031 $ hg -R repo update
1032 1032 b: untracked file differs
1033 1033 abort: untracked files in working directory differ from files in requested revision (in subrepository "s")
1034 1034 [255]
1035 1035 $ cat >> repo/.hg/hgrc <<EOF
1036 1036 > [extensions]
1037 1037 > fakedirstatewritetime = !
1038 1038 > EOF
1039 1039
1040 1040 $ cat repo/s/b
1041 1041 issue3276_ok
1042 1042 $ rm repo/s/b
1043 1043 $ touch -t 200001010000 repo/.hgsubstate
1044 1044 $ hg -R repo revert --all
1045 1045 reverting repo/.hgsubstate
1046 1046 reverting subrepo s
1047 1047 $ hg -R repo update
1048 1048 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1049 1049 $ cat repo/s/b
1050 1050 2
1051 1051 $ rm -rf repo2 repo
1052 1052
1053 1053
1054 1054 Issue1852 subrepos with relative paths always push/pull relative to default
1055 1055
1056 1056 Prepare a repo with subrepo
1057 1057
1058 1058 $ hg init issue1852a
1059 1059 $ cd issue1852a
1060 1060 $ hg init sub/repo
1061 1061 $ echo test > sub/repo/foo
1062 1062 $ hg -R sub/repo add sub/repo/foo
1063 1063 $ echo sub/repo = sub/repo > .hgsub
1064 1064 $ hg add .hgsub
1065 1065 $ hg ci -mtest
1066 1066 committing subrepository sub/repo
1067 1067 $ echo test >> sub/repo/foo
1068 1068 $ hg ci -mtest
1069 1069 committing subrepository sub/repo
1070 1070 $ hg cat sub/repo/foo
1071 1071 test
1072 1072 test
1073 1073 $ hg cat sub/repo/foo -Tjson | sed 's|\\\\|/|g'
1074 1074 [
1075 1075 {
1076 1076 "data": "test\ntest\n",
1077 1077 "path": "foo"
1078 1078 }
1079 1079 ]
1080 1080
1081 1081 non-exact match:
1082 1082
1083 1083 $ hg cat -T '{path|relpath}\n' 'glob:**'
1084 1084 .hgsub
1085 1085 .hgsubstate
1086 1086 sub/repo/foo
1087 1087 $ hg cat -T '{path|relpath}\n' 're:^sub'
1088 1088 sub/repo/foo
1089 1089
1090 1090 missing subrepos in working directory:
1091 1091
1092 1092 $ mkdir -p tmp/sub/repo
1093 1093 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
1094 1094 $ cat tmp/sub/repo/foo_p
1095 1095 test
1096 1096 $ mv sub/repo sub_
1097 1097 $ hg cat sub/repo/baz
1098 1098 skipping missing subrepository: sub/repo
1099 1099 [1]
1100 1100 $ rm -rf sub/repo
1101 1101 $ mv sub_ sub/repo
1102 1102 $ cd ..
1103 1103
1104 1104 Create repo without default path, pull top repo, and see what happens on update
1105 1105
1106 1106 $ hg init issue1852b
1107 1107 $ hg -R issue1852b pull issue1852a
1108 1108 pulling from issue1852a
1109 1109 requesting all changes
1110 1110 adding changesets
1111 1111 adding manifests
1112 1112 adding file changes
1113 1113 added 2 changesets with 3 changes to 2 files
1114 1114 new changesets 19487b456929:be5eb94e7215
1115 1115 (run 'hg update' to get a working copy)
1116 1116 $ hg -R issue1852b update
1117 1117 abort: default path for subrepository not found (in subrepository "sub/repo")
1118 1118 [255]
1119 1119
1120 1120 Ensure a full traceback, not just the SubrepoAbort part
1121 1121
1122 1122 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise error\.Abort'
1123 1123 raise error.Abort(_("default path for subrepository not found"))
1124 1124
1125 1125 Pull -u now doesn't help
1126 1126
1127 1127 $ hg -R issue1852b pull -u issue1852a
1128 1128 pulling from issue1852a
1129 1129 searching for changes
1130 1130 no changes found
1131 1131
1132 1132 Try the same, but with pull -u
1133 1133
1134 1134 $ hg init issue1852c
1135 1135 $ hg -R issue1852c pull -r0 -u issue1852a
1136 1136 pulling from issue1852a
1137 1137 adding changesets
1138 1138 adding manifests
1139 1139 adding file changes
1140 1140 added 1 changesets with 2 changes to 2 files
1141 1141 new changesets 19487b456929
1142 1142 cloning subrepo sub/repo from issue1852a/sub/repo
1143 1143 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1144 1144
1145 1145 Try to push from the other side
1146 1146
1147 1147 $ hg -R issue1852a push `pwd`/issue1852c
1148 1148 pushing to $TESTTMP/issue1852c
1149 1149 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo
1150 1150 searching for changes
1151 1151 no changes found
1152 1152 searching for changes
1153 1153 adding changesets
1154 1154 adding manifests
1155 1155 adding file changes
1156 1156 added 1 changesets with 1 changes to 1 files
1157 1157
1158 1158 Incoming and outgoing should not use the default path:
1159 1159
1160 1160 $ hg clone -q issue1852a issue1852d
1161 1161 $ hg -R issue1852d outgoing --subrepos issue1852c
1162 1162 comparing with issue1852c
1163 1163 searching for changes
1164 1164 no changes found
1165 1165 comparing with issue1852c/sub/repo
1166 1166 searching for changes
1167 1167 no changes found
1168 1168 [1]
1169 1169 $ hg -R issue1852d incoming --subrepos issue1852c
1170 1170 comparing with issue1852c
1171 1171 searching for changes
1172 1172 no changes found
1173 1173 comparing with issue1852c/sub/repo
1174 1174 searching for changes
1175 1175 no changes found
1176 1176 [1]
1177 1177
1178 1178 Check that merge of a new subrepo doesn't write the uncommitted state to
1179 1179 .hgsubstate (issue4622)
1180 1180
1181 1181 $ hg init issue1852a/addedsub
1182 1182 $ echo zzz > issue1852a/addedsub/zz.txt
1183 1183 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1184 1184
1185 1185 $ hg clone issue1852a/addedsub issue1852d/addedsub
1186 1186 updating to branch default
1187 1187 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1188 1188
1189 1189 $ echo def > issue1852a/sub/repo/foo
1190 1190 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1191 1191 adding tmp/sub/repo/foo_p
1192 1192 committing subrepository sub/repo
1193 1193
1194 1194 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1195 1195 $ echo xyz > issue1852d/sub/repo/foo
1196 1196 $ hg -R issue1852d pull -u
1197 1197 pulling from $TESTTMP/issue1852a
1198 1198 searching for changes
1199 1199 adding changesets
1200 1200 adding manifests
1201 1201 adding file changes
1202 1202 added 1 changesets with 2 changes to 2 files
1203 1203 new changesets c82b79fdcc5b
1204 1204 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1205 1205 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1206 1206 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo
1207 1207 searching for changes
1208 1208 adding changesets
1209 1209 adding manifests
1210 1210 adding file changes
1211 1211 added 1 changesets with 1 changes to 1 files
1212 1212 new changesets 46cd4aac504c
1213 1213 subrepository sources for sub/repo differ
1214 1214 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1215 1215 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1216 1216 $ cat issue1852d/.hgsubstate
1217 1217 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1218 1218
1219 1219 Check status of files when none of them belong to the first
1220 1220 subrepository:
1221 1221
1222 1222 $ hg init subrepo-status
1223 1223 $ cd subrepo-status
1224 1224 $ hg init subrepo-1
1225 1225 $ hg init subrepo-2
1226 1226 $ cd subrepo-2
1227 1227 $ touch file
1228 1228 $ hg add file
1229 1229 $ cd ..
1230 1230 $ echo subrepo-1 = subrepo-1 > .hgsub
1231 1231 $ echo subrepo-2 = subrepo-2 >> .hgsub
1232 1232 $ hg add .hgsub
1233 1233 $ hg ci -m 'Added subrepos'
1234 1234 committing subrepository subrepo-2
1235 1235 $ hg st subrepo-2/file
1236 1236
1237 1237 Check that share works with subrepo
1238 1238 $ hg --config extensions.share= share . ../shared
1239 1239 updating working directory
1240 1240 sharing subrepo subrepo-1 from $TESTTMP/subrepo-status/subrepo-1
1241 1241 sharing subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1242 1242 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1243 1243 $ find ../shared/* | sort
1244 1244 ../shared/subrepo-1
1245 1245 ../shared/subrepo-1/.hg
1246 1246 ../shared/subrepo-1/.hg/cache
1247 1247 ../shared/subrepo-1/.hg/cache/storehash
1248 1248 ../shared/subrepo-1/.hg/cache/storehash/* (glob)
1249 1249 ../shared/subrepo-1/.hg/hgrc
1250 1250 ../shared/subrepo-1/.hg/requires
1251 1251 ../shared/subrepo-1/.hg/sharedpath
1252 1252 ../shared/subrepo-1/.hg/wcache
1253 1253 ../shared/subrepo-2
1254 1254 ../shared/subrepo-2/.hg
1255 1255 ../shared/subrepo-2/.hg/branch
1256 1256 ../shared/subrepo-2/.hg/cache
1257 1257 ../shared/subrepo-2/.hg/cache/storehash
1258 1258 ../shared/subrepo-2/.hg/cache/storehash/* (glob)
1259 1259 ../shared/subrepo-2/.hg/dirstate
1260 1260 ../shared/subrepo-2/.hg/hgrc
1261 1261 ../shared/subrepo-2/.hg/requires
1262 1262 ../shared/subrepo-2/.hg/sharedpath
1263 1263 ../shared/subrepo-2/.hg/wcache
1264 1264 ../shared/subrepo-2/.hg/wcache/checkisexec (execbit !)
1265 1265 ../shared/subrepo-2/.hg/wcache/checklink (symlink !)
1266 1266 ../shared/subrepo-2/.hg/wcache/checklink-target (symlink !)
1267 1267 ../shared/subrepo-2/.hg/wcache/manifestfulltextcache (reporevlogstore !)
1268 1268 ../shared/subrepo-2/file
1269 1269 $ hg -R ../shared in
1270 1270 abort: repository default not found!
1271 1271 [255]
1272 1272 $ hg -R ../shared/subrepo-2 showconfig paths
1273 1273 paths.default=$TESTTMP/subrepo-status/subrepo-2
1274 1274 $ hg -R ../shared/subrepo-1 sum --remote
1275 1275 parent: -1:000000000000 tip (empty repository)
1276 1276 branch: default
1277 1277 commit: (clean)
1278 1278 update: (current)
1279 1279 remote: (synced)
1280 1280
1281 1281 Check hg update --clean
1282 1282 $ cd $TESTTMP/t
1283 1283 $ rm -r t/t.orig
1284 1284 $ hg status -S --all
1285 1285 C .hgsub
1286 1286 C .hgsubstate
1287 1287 C a
1288 1288 C s/.hgsub
1289 1289 C s/.hgsubstate
1290 1290 C s/a
1291 1291 C s/ss/a
1292 1292 C t/t
1293 1293 $ echo c1 > s/a
1294 1294 $ cd s
1295 1295 $ echo c1 > b
1296 1296 $ echo c1 > c
1297 1297 $ hg add b
1298 1298 $ cd ..
1299 1299 $ hg status -S
1300 1300 M s/a
1301 1301 A s/b
1302 1302 ? s/c
1303 1303 $ hg update -C
1304 1304 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1305 1305 updated to "925c17564ef8: 13"
1306 1306 2 other heads for branch "default"
1307 1307 $ hg status -S
1308 1308 ? s/b
1309 1309 ? s/c
1310 1310
1311 1311 Sticky subrepositories, no changes
1312 1312 $ cd $TESTTMP/t
1313 1313 $ hg id
1314 1314 925c17564ef8 tip
1315 1315 $ hg -R s id
1316 1316 12a213df6fa9 tip
1317 1317 $ hg -R t id
1318 1318 52c0adc0515a tip
1319 1319 $ hg update 11
1320 1320 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1321 1321 $ hg id
1322 1322 365661e5936a
1323 1323 $ hg -R s id
1324 1324 fc627a69481f
1325 1325 $ hg -R t id
1326 1326 e95bcfa18a35
1327 1327
1328 1328 Sticky subrepositories, file changes
1329 1329 $ touch s/f1
1330 1330 $ touch t/f1
1331 1331 $ hg add -S s/f1
1332 1332 $ hg add -S t/f1
1333 1333 $ hg id
1334 1334 365661e5936a+
1335 1335 $ hg -R s id
1336 1336 fc627a69481f+
1337 1337 $ hg -R t id
1338 1338 e95bcfa18a35+
1339 1339 $ hg update tip
1340 1340 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1341 1341 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1342 1342 subrepository sources for s differ
1343 1343 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1344 1344 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1345 1345 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1346 1346 subrepository sources for t differ
1347 1347 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1348 1348 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1349 1349 $ hg id
1350 1350 925c17564ef8+ tip
1351 1351 $ hg -R s id
1352 1352 fc627a69481f+
1353 1353 $ hg -R t id
1354 1354 e95bcfa18a35+
1355 1355 $ hg update --clean tip
1356 1356 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1357 1357
1358 1358 Sticky subrepository, revision updates
1359 1359 $ hg id
1360 1360 925c17564ef8 tip
1361 1361 $ hg -R s id
1362 1362 12a213df6fa9 tip
1363 1363 $ hg -R t id
1364 1364 52c0adc0515a tip
1365 1365 $ cd s
1366 1366 $ hg update -r -2
1367 1367 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1368 1368 $ cd ../t
1369 1369 $ hg update -r 2
1370 1370 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1371 1371 $ cd ..
1372 1372 $ hg update 10
1373 1373 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1374 1374 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1375 1375 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1376 1376 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1377 1377 subrepository sources for t differ (in checked out version)
1378 1378 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1379 1379 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1380 1380 $ hg id
1381 1381 e45c8b14af55+
1382 1382 $ hg -R s id
1383 1383 02dcf1d70411
1384 1384 $ hg -R t id
1385 1385 7af322bc1198
1386 1386
1387 1387 Sticky subrepository, file changes and revision updates
1388 1388 $ touch s/f1
1389 1389 $ touch t/f1
1390 1390 $ hg add -S s/f1
1391 1391 $ hg add -S t/f1
1392 1392 $ hg id
1393 1393 e45c8b14af55+
1394 1394 $ hg -R s id
1395 1395 02dcf1d70411+
1396 1396 $ hg -R t id
1397 1397 7af322bc1198+
1398 1398 $ hg update tip
1399 1399 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1400 1400 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1401 1401 subrepository sources for s differ
1402 1402 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1403 1403 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1404 1404 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1405 1405 subrepository sources for t differ
1406 1406 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1407 1407 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1408 1408 $ hg id
1409 1409 925c17564ef8+ tip
1410 1410 $ hg -R s id
1411 1411 02dcf1d70411+
1412 1412 $ hg -R t id
1413 1413 7af322bc1198+
1414 1414
1415 1415 Sticky repository, update --clean
1416 1416 $ hg update --clean tip
1417 1417 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1418 1418 $ hg id
1419 1419 925c17564ef8 tip
1420 1420 $ hg -R s id
1421 1421 12a213df6fa9 tip
1422 1422 $ hg -R t id
1423 1423 52c0adc0515a tip
1424 1424
1425 1425 Test subrepo already at intended revision:
1426 1426 $ cd s
1427 1427 $ hg update fc627a69481f
1428 1428 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1429 1429 $ cd ..
1430 1430 $ hg update 11
1431 1431 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1432 1432 (M)erge, keep (l)ocal [working copy] or keep (r)emote [destination]? m
1433 1433 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1434 1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1435 1435 $ hg id -n
1436 1436 11+
1437 1437 $ hg -R s id
1438 1438 fc627a69481f
1439 1439 $ hg -R t id
1440 1440 e95bcfa18a35
1441 1441
1442 1442 Test that removing .hgsubstate doesn't break anything:
1443 1443
1444 1444 $ hg rm -f .hgsubstate
1445 1445 $ hg ci -mrm
1446 1446 nothing changed
1447 1447 [1]
1448 1448 $ hg log -vr tip
1449 1449 changeset: 13:925c17564ef8
1450 1450 tag: tip
1451 1451 user: test
1452 1452 date: Thu Jan 01 00:00:00 1970 +0000
1453 1453 files: .hgsubstate
1454 1454 description:
1455 1455 13
1456 1456
1457 1457
1458 1458
1459 1459 Test that removing .hgsub removes .hgsubstate:
1460 1460
1461 1461 $ hg rm .hgsub
1462 1462 $ hg ci -mrm2
1463 1463 created new head
1464 1464 $ hg log -vr tip
1465 1465 changeset: 14:2400bccd50af
1466 1466 tag: tip
1467 1467 parent: 11:365661e5936a
1468 1468 user: test
1469 1469 date: Thu Jan 01 00:00:00 1970 +0000
1470 1470 files: .hgsub .hgsubstate
1471 1471 description:
1472 1472 rm2
1473 1473
1474 1474
1475 1475 Test issue3153: diff -S with deleted subrepos
1476 1476
1477 1477 $ hg diff --nodates -S -c .
1478 1478 diff -r 365661e5936a -r 2400bccd50af .hgsub
1479 1479 --- a/.hgsub
1480 1480 +++ /dev/null
1481 1481 @@ -1,2 +0,0 @@
1482 1482 -s = s
1483 1483 -t = t
1484 1484 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1485 1485 --- a/.hgsubstate
1486 1486 +++ /dev/null
1487 1487 @@ -1,2 +0,0 @@
1488 1488 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1489 1489 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1490 1490
1491 1491 Test behavior of add for explicit path in subrepo:
1492 1492 $ cd ..
1493 1493 $ hg init explicit
1494 1494 $ cd explicit
1495 1495 $ echo s = s > .hgsub
1496 1496 $ hg add .hgsub
1497 1497 $ hg init s
1498 1498 $ hg ci -m0
1499 1499 Adding with an explicit path in a subrepo adds the file
1500 1500 $ echo c1 > f1
1501 1501 $ echo c2 > s/f2
1502 1502 $ hg st -S
1503 1503 ? f1
1504 1504 ? s/f2
1505 1505 $ hg add s/f2
1506 1506 $ hg st -S
1507 1507 A s/f2
1508 1508 ? f1
1509 1509 $ hg ci -R s -m0
1510 1510 $ hg ci -Am1
1511 1511 adding f1
1512 1512 Adding with an explicit path in a subrepo with -S has the same behavior
1513 1513 $ echo c3 > f3
1514 1514 $ echo c4 > s/f4
1515 1515 $ hg st -S
1516 1516 ? f3
1517 1517 ? s/f4
1518 1518 $ hg add -S s/f4
1519 1519 $ hg st -S
1520 1520 A s/f4
1521 1521 ? f3
1522 1522 $ hg ci -R s -m1
1523 1523 $ hg ci -Ama2
1524 1524 adding f3
1525 1525 Adding without a path or pattern silently ignores subrepos
1526 1526 $ echo c5 > f5
1527 1527 $ echo c6 > s/f6
1528 1528 $ echo c7 > s/f7
1529 1529 $ hg st -S
1530 1530 ? f5
1531 1531 ? s/f6
1532 1532 ? s/f7
1533 1533 $ hg add
1534 1534 adding f5
1535 1535 $ hg st -S
1536 1536 A f5
1537 1537 ? s/f6
1538 1538 ? s/f7
1539 1539 $ hg ci -R s -Am2
1540 1540 adding f6
1541 1541 adding f7
1542 1542 $ hg ci -m3
1543 1543 Adding without a path or pattern with -S also adds files in subrepos
1544 1544 $ echo c8 > f8
1545 1545 $ echo c9 > s/f9
1546 1546 $ echo c10 > s/f10
1547 1547 $ hg st -S
1548 1548 ? f8
1549 1549 ? s/f10
1550 1550 ? s/f9
1551 1551 $ hg add -S
1552 1552 adding f8
1553 1553 adding s/f10
1554 1554 adding s/f9
1555 1555 $ hg st -S
1556 1556 A f8
1557 1557 A s/f10
1558 1558 A s/f9
1559 1559 $ hg ci -R s -m3
1560 1560 $ hg ci -m4
1561 1561 Adding with a pattern silently ignores subrepos
1562 1562 $ echo c11 > fm11
1563 1563 $ echo c12 > fn12
1564 1564 $ echo c13 > s/fm13
1565 1565 $ echo c14 > s/fn14
1566 1566 $ hg st -S
1567 1567 ? fm11
1568 1568 ? fn12
1569 1569 ? s/fm13
1570 1570 ? s/fn14
1571 1571 $ hg add 'glob:**fm*'
1572 1572 adding fm11
1573 1573 $ hg st -S
1574 1574 A fm11
1575 1575 ? fn12
1576 1576 ? s/fm13
1577 1577 ? s/fn14
1578 1578 $ hg ci -R s -Am4
1579 1579 adding fm13
1580 1580 adding fn14
1581 1581 $ hg ci -Am5
1582 1582 adding fn12
1583 1583 Adding with a pattern with -S also adds matches in subrepos
1584 1584 $ echo c15 > fm15
1585 1585 $ echo c16 > fn16
1586 1586 $ echo c17 > s/fm17
1587 1587 $ echo c18 > s/fn18
1588 1588 $ hg st -S
1589 1589 ? fm15
1590 1590 ? fn16
1591 1591 ? s/fm17
1592 1592 ? s/fn18
1593 1593 $ hg add -S 'glob:**fm*'
1594 1594 adding fm15
1595 1595 adding s/fm17
1596 1596 $ hg st -S
1597 1597 A fm15
1598 1598 A s/fm17
1599 1599 ? fn16
1600 1600 ? s/fn18
1601 1601 $ hg ci -R s -Am5
1602 1602 adding fn18
1603 1603 $ hg ci -Am6
1604 1604 adding fn16
1605 1605
1606 1606 Test behavior of forget for explicit path in subrepo:
1607 1607 Forgetting an explicit path in a subrepo untracks the file
1608 1608 $ echo c19 > s/f19
1609 1609 $ hg add s/f19
1610 1610 $ hg st -S
1611 1611 A s/f19
1612 1612 $ hg forget s/f19
1613 1613 $ hg st -S
1614 1614 ? s/f19
1615 1615 $ rm s/f19
1616 1616 $ cd ..
1617 1617
1618 1618 Courtesy phases synchronisation to publishing server does not block the push
1619 1619 (issue3781)
1620 1620
1621 1621 $ cp -R main issue3781
1622 1622 $ cp -R main issue3781-dest
1623 1623 $ cd issue3781-dest/s
1624 1624 $ hg phase tip # show we have draft changeset
1625 1625 5: draft
1626 1626 $ chmod a-w .hg/store/phaseroots # prevent phase push
1627 1627 $ cd ../../issue3781
1628 1628 $ cat >> .hg/hgrc << EOF
1629 1629 > [paths]
1630 1630 > default=../issue3781-dest/
1631 1631 > EOF
1632 1632 $ hg push --config devel.legacy.exchange=bundle1
1633 1633 pushing to $TESTTMP/issue3781-dest
1634 1634 pushing subrepo s to $TESTTMP/issue3781-dest/s
1635 1635 searching for changes
1636 1636 no changes found
1637 1637 searching for changes
1638 1638 no changes found
1639 1639 [1]
1640 1640 # clean the push cache
1641 1641 $ rm s/.hg/cache/storehash/*
1642 1642 $ hg push # bundle2+
1643 1643 pushing to $TESTTMP/issue3781-dest
1644 1644 pushing subrepo s to $TESTTMP/issue3781-dest/s
1645 1645 searching for changes
1646 1646 no changes found
1647 1647 searching for changes
1648 1648 no changes found
1649 1649 [1]
1650 1650 $ cd ..
1651 1651
1652 1652 Test phase choice for newly created commit with "phases.subrepochecks"
1653 1653 configuration
1654 1654
1655 1655 $ cd t
1656 1656 $ hg update -q -r 12
1657 1657
1658 1658 $ cat >> s/ss/.hg/hgrc <<EOF
1659 1659 > [phases]
1660 1660 > new-commit = secret
1661 1661 > EOF
1662 1662 $ cat >> s/.hg/hgrc <<EOF
1663 1663 > [phases]
1664 1664 > new-commit = draft
1665 1665 > EOF
1666 1666 $ echo phasecheck1 >> s/ss/a
1667 1667 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1668 1668 committing subrepository ss
1669 1669 transaction abort!
1670 1670 rollback completed
1671 1671 abort: can't commit in draft phase conflicting secret from subrepository ss
1672 1672 [255]
1673 1673 $ echo phasecheck2 >> s/ss/a
1674 1674 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1675 1675 committing subrepository ss
1676 1676 $ hg -R s/ss phase tip
1677 1677 3: secret
1678 1678 $ hg -R s phase tip
1679 1679 6: draft
1680 1680 $ echo phasecheck3 >> s/ss/a
1681 1681 $ hg -R s commit -S -m phasecheck3
1682 1682 committing subrepository ss
1683 1683 warning: changes are committed in secret phase from subrepository ss
1684 1684 $ hg -R s/ss phase tip
1685 1685 4: secret
1686 1686 $ hg -R s phase tip
1687 1687 7: secret
1688 1688
1689 1689 $ cat >> t/.hg/hgrc <<EOF
1690 1690 > [phases]
1691 1691 > new-commit = draft
1692 1692 > EOF
1693 1693 $ cat >> .hg/hgrc <<EOF
1694 1694 > [phases]
1695 1695 > new-commit = public
1696 1696 > EOF
1697 1697 $ echo phasecheck4 >> s/ss/a
1698 1698 $ echo phasecheck4 >> t/t
1699 1699 $ hg commit -S -m phasecheck4
1700 1700 committing subrepository s
1701 1701 committing subrepository s/ss
1702 1702 warning: changes are committed in secret phase from subrepository ss
1703 1703 committing subrepository t
1704 1704 warning: changes are committed in secret phase from subrepository s
1705 1705 created new head
1706 1706 $ hg -R s/ss phase tip
1707 1707 5: secret
1708 1708 $ hg -R s phase tip
1709 1709 8: secret
1710 1710 $ hg -R t phase tip
1711 1711 6: draft
1712 1712 $ hg phase tip
1713 1713 15: secret
1714 1714
1715 1715 $ cd ..
1716 1716
1717 1717
1718 1718 Test that commit --secret works on both repo and subrepo (issue4182)
1719 1719
1720 1720 $ cd main
1721 1721 $ echo secret >> b
1722 1722 $ echo secret >> s/b
1723 1723 $ hg commit --secret --subrepo -m "secret"
1724 1724 committing subrepository s
1725 1725 $ hg phase -r .
1726 1726 6: secret
1727 1727 $ cd s
1728 1728 $ hg phase -r .
1729 1729 6: secret
1730 1730 $ cd ../../
1731 1731
1732 1732 Test "subrepos" template keyword
1733 1733
1734 1734 $ cd t
1735 1735 $ hg update -q 15
1736 1736 $ cat > .hgsub <<EOF
1737 1737 > s = s
1738 1738 > EOF
1739 1739 $ hg commit -m "16"
1740 1740 warning: changes are committed in secret phase from subrepository s
1741 1741
1742 1742 (addition of ".hgsub" itself)
1743 1743
1744 1744 $ hg diff --nodates -c 1 .hgsubstate
1745 1745 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1746 1746 --- /dev/null
1747 1747 +++ b/.hgsubstate
1748 1748 @@ -0,0 +1,1 @@
1749 1749 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1750 1750 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1751 1751 f7b1eb17ad24 000000000000
1752 1752 s
1753 1753
1754 1754 (modification of existing entry)
1755 1755
1756 1756 $ hg diff --nodates -c 2 .hgsubstate
1757 1757 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1758 1758 --- a/.hgsubstate
1759 1759 +++ b/.hgsubstate
1760 1760 @@ -1,1 +1,1 @@
1761 1761 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1762 1762 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1763 1763 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1764 1764 7cf8cfea66e4 000000000000
1765 1765 s
1766 1766
1767 1767 (addition of entry)
1768 1768
1769 1769 $ hg diff --nodates -c 5 .hgsubstate
1770 1770 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1771 1771 --- a/.hgsubstate
1772 1772 +++ b/.hgsubstate
1773 1773 @@ -1,1 +1,2 @@
1774 1774 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1775 1775 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1776 1776 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1777 1777 7cf8cfea66e4 000000000000
1778 1778 t
1779 1779
1780 1780 (removal of existing entry)
1781 1781
1782 1782 $ hg diff --nodates -c 16 .hgsubstate
1783 1783 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1784 1784 --- a/.hgsubstate
1785 1785 +++ b/.hgsubstate
1786 1786 @@ -1,2 +1,1 @@
1787 1787 0731af8ca9423976d3743119d0865097c07bdc1b s
1788 1788 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1789 1789 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1790 1790 8bec38d2bd0b 000000000000
1791 1791 t
1792 1792
1793 1793 (merging)
1794 1794
1795 1795 $ hg diff --nodates -c 9 .hgsubstate
1796 1796 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1797 1797 --- a/.hgsubstate
1798 1798 +++ b/.hgsubstate
1799 1799 @@ -1,1 +1,2 @@
1800 1800 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1801 1801 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1802 1802 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1803 1803 f6affe3fbfaa 1f14a2e2d3ec
1804 1804 t
1805 1805
1806 1806 (removal of ".hgsub" itself)
1807 1807
1808 1808 $ hg diff --nodates -c 8 .hgsubstate
1809 1809 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1810 1810 --- a/.hgsubstate
1811 1811 +++ /dev/null
1812 1812 @@ -1,2 +0,0 @@
1813 1813 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1814 1814 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1815 1815 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1816 1816 f94576341bcf 000000000000
1817 1817
1818 1818 Test that '[paths]' is configured correctly at subrepo creation
1819 1819
1820 1820 $ cd $TESTTMP/tc
1821 1821 $ cat > .hgsub <<EOF
1822 1822 > # to clear bogus subrepo path 'bogus=[boguspath'
1823 1823 > s = s
1824 1824 > t = t
1825 1825 > EOF
1826 1826 $ hg update -q --clean null
1827 1827 $ rm -rf s t
1828 1828 $ cat >> .hg/hgrc <<EOF
1829 1829 > [paths]
1830 1830 > default-push = /foo/bar
1831 1831 > EOF
1832 1832 $ hg update -q
1833 1833 $ cat s/.hg/hgrc
1834 1834 [paths]
1835 1835 default = $TESTTMP/t/s
1836 1836 default-push = /foo/bar/s
1837 1837 $ cat s/ss/.hg/hgrc
1838 1838 [paths]
1839 1839 default = $TESTTMP/t/s/ss
1840 1840 default-push = /foo/bar/s/ss
1841 1841 $ cat t/.hg/hgrc
1842 1842 [paths]
1843 1843 default = $TESTTMP/t/t
1844 1844 default-push = /foo/bar/t
1845 1845
1846 1846 $ cd $TESTTMP/t
1847 1847 $ hg up -qC 0
1848 1848 $ echo 'bar' > bar.txt
1849 1849 $ hg ci -Am 'branch before subrepo add'
1850 1850 adding bar.txt
1851 1851 created new head
1852 1852 $ hg merge -r "first(subrepo('s'))"
1853 1853 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1854 1854 (branch merge, don't forget to commit)
1855 1855 $ hg status -S -X '.hgsub*'
1856 1856 A s/a
1857 1857 ? s/b
1858 1858 ? s/c
1859 1859 ? s/f1
1860 1860 $ hg status -S --rev 'p2()'
1861 1861 A bar.txt
1862 1862 ? s/b
1863 1863 ? s/c
1864 1864 ? s/f1
1865 1865 $ hg diff -S -X '.hgsub*' --nodates
1866 1866 diff -r 000000000000 s/a
1867 1867 --- /dev/null
1868 1868 +++ b/s/a
1869 1869 @@ -0,0 +1,1 @@
1870 1870 +a
1871 1871 $ hg diff -S --rev 'p2()' --nodates
1872 1872 diff -r 7cf8cfea66e4 bar.txt
1873 1873 --- /dev/null
1874 1874 +++ b/bar.txt
1875 1875 @@ -0,0 +1,1 @@
1876 1876 +bar
1877 1877
1878 $ hg diff -X '.hgsub*' --nodates s
1879 diff -r 000000000000 s/a
1880 --- /dev/null
1881 +++ b/s/a
1882 @@ -0,0 +1,1 @@
1883 +a
1884 $ hg diff -X '.hgsub*' --nodates s/a
1885 diff -r 000000000000 s/a
1886 --- /dev/null
1887 +++ b/s/a
1888 @@ -0,0 +1,1 @@
1889 +a
1890
1878 1891 $ cd ..
1879 1892
1880 1893 test for ssh exploit 2017-07-25
1881 1894
1882 1895 $ cat >> $HGRCPATH << EOF
1883 1896 > [ui]
1884 1897 > ssh = sh -c "read l; read l; read l"
1885 1898 > EOF
1886 1899
1887 1900 $ hg init malicious-proxycommand
1888 1901 $ cd malicious-proxycommand
1889 1902 $ echo 's = [hg]ssh://-oProxyCommand=touch${IFS}owned/path' > .hgsub
1890 1903 $ hg init s
1891 1904 $ cd s
1892 1905 $ echo init > init
1893 1906 $ hg add
1894 1907 adding init
1895 1908 $ hg commit -m init
1896 1909 $ cd ..
1897 1910 $ hg add .hgsub
1898 1911 $ hg ci -m 'add subrepo'
1899 1912 $ cd ..
1900 1913 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1901 1914 updating to branch default
1902 1915 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
1903 1916 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s")
1904 1917 [255]
1905 1918
1906 1919 also check that a percent encoded '-' (%2D) doesn't work
1907 1920
1908 1921 $ cd malicious-proxycommand
1909 1922 $ echo 's = [hg]ssh://%2DoProxyCommand=touch${IFS}owned/path' > .hgsub
1910 1923 $ hg ci -m 'change url to percent encoded'
1911 1924 $ cd ..
1912 1925 $ rm -r malicious-proxycommand-clone
1913 1926 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1914 1927 updating to branch default
1915 1928 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%24%7BIFS%7Downed/path
1916 1929 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch${IFS}owned/path' (in subrepository "s")
1917 1930 [255]
1918 1931
1919 1932 also check for a pipe
1920 1933
1921 1934 $ cd malicious-proxycommand
1922 1935 $ echo 's = [hg]ssh://fakehost|touch${IFS}owned/path' > .hgsub
1923 1936 $ hg ci -m 'change url to pipe'
1924 1937 $ cd ..
1925 1938 $ rm -r malicious-proxycommand-clone
1926 1939 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1927 1940 updating to branch default
1928 1941 cloning subrepo s from ssh://fakehost%7Ctouch%24%7BIFS%7Downed/path
1929 1942 abort: no suitable response from remote hg!
1930 1943 [255]
1931 1944 $ [ ! -f owned ] || echo 'you got owned'
1932 1945
1933 1946 also check that a percent encoded '|' (%7C) doesn't work
1934 1947
1935 1948 $ cd malicious-proxycommand
1936 1949 $ echo 's = [hg]ssh://fakehost%7Ctouch%20owned/path' > .hgsub
1937 1950 $ hg ci -m 'change url to percent encoded pipe'
1938 1951 $ cd ..
1939 1952 $ rm -r malicious-proxycommand-clone
1940 1953 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1941 1954 updating to branch default
1942 1955 cloning subrepo s from ssh://fakehost%7Ctouch%20owned/path
1943 1956 abort: no suitable response from remote hg!
1944 1957 [255]
1945 1958 $ [ ! -f owned ] || echo 'you got owned'
1946 1959
1947 1960 and bad usernames:
1948 1961 $ cd malicious-proxycommand
1949 1962 $ echo 's = [hg]ssh://-oProxyCommand=touch owned@example.com/path' > .hgsub
1950 1963 $ hg ci -m 'owned username'
1951 1964 $ cd ..
1952 1965 $ rm -r malicious-proxycommand-clone
1953 1966 $ hg clone malicious-proxycommand malicious-proxycommand-clone
1954 1967 updating to branch default
1955 1968 cloning subrepo s from ssh://-oProxyCommand%3Dtouch%20owned@example.com/path
1956 1969 abort: potentially unsafe url: 'ssh://-oProxyCommand=touch owned@example.com/path' (in subrepository "s")
1957 1970 [255]
1958 1971
1959 1972 Test convert subrepositories including merge (issue5526):
1960 1973
1961 1974 $ hg init tconv
1962 1975 $ hg convert --config extensions.convert= -q t/s tconv/s
1963 1976 $ hg convert --config extensions.convert= -q t/s/ss tconv/s/ss
1964 1977 $ hg convert --config extensions.convert= -q t/t tconv/t
1965 1978
1966 1979 convert shouldn't fail because of pseudo filenode:
1967 1980
1968 1981 $ hg convert --config extensions.convert= t tconv
1969 1982 scanning source...
1970 1983 sorting...
1971 1984 converting...
1972 1985 17 0
1973 1986 16 1
1974 1987 15 2
1975 1988 14 3
1976 1989 13 4
1977 1990 12 5
1978 1991 11 6
1979 1992 10 7
1980 1993 9 8
1981 1994 8 9
1982 1995 7 10
1983 1996 6 11
1984 1997 5 12
1985 1998 4 13
1986 1999 3 rm2
1987 2000 2 phasecheck4
1988 2001 1 16
1989 2002 0 branch before subrepo add
1990 2003
1991 2004 converted .hgsubstate should point to valid nodes:
1992 2005
1993 2006 $ hg up -R tconv 9
1994 2007 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
1995 2008 $ cat tconv/.hgsubstate
1996 2009 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1997 2010 60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
General Comments 0
You need to be logged in to leave comments. Login now