##// END OF EJS Templates
subrepo: don't pass the outer repo's --rev or --branch to subrepo incoming()...
Matt Harbison -
r24876:b5513ee8 stable
parent child Browse files
Show More
@@ -1,1831 +1,1835 b''
1 # subrepo.py - sub-repository handling for Mercurial
1 # subrepo.py - sub-repository handling for Mercurial
2 #
2 #
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import copy
8 import copy
9 import errno, os, re, posixpath, sys
9 import errno, os, re, posixpath, sys
10 import xml.dom.minidom
10 import xml.dom.minidom
11 import stat, subprocess, tarfile
11 import stat, subprocess, tarfile
12 from i18n import _
12 from i18n import _
13 import config, util, node, error, cmdutil, scmutil, match as matchmod
13 import config, util, node, error, cmdutil, scmutil, match as matchmod
14 import phases
14 import phases
15 import pathutil
15 import pathutil
16 import exchange
16 import exchange
17 hg = None
17 hg = None
18 propertycache = util.propertycache
18 propertycache = util.propertycache
19
19
20 nullstate = ('', '', 'empty')
20 nullstate = ('', '', 'empty')
21
21
22 def _expandedabspath(path):
22 def _expandedabspath(path):
23 '''
23 '''
24 get a path or url and if it is a path expand it and return an absolute path
24 get a path or url and if it is a path expand it and return an absolute path
25 '''
25 '''
26 expandedpath = util.urllocalpath(util.expandpath(path))
26 expandedpath = util.urllocalpath(util.expandpath(path))
27 u = util.url(expandedpath)
27 u = util.url(expandedpath)
28 if not u.scheme:
28 if not u.scheme:
29 path = util.normpath(os.path.abspath(u.path))
29 path = util.normpath(os.path.abspath(u.path))
30 return path
30 return path
31
31
32 def _getstorehashcachename(remotepath):
32 def _getstorehashcachename(remotepath):
33 '''get a unique filename for the store hash cache of a remote repository'''
33 '''get a unique filename for the store hash cache of a remote repository'''
34 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
34 return util.sha1(_expandedabspath(remotepath)).hexdigest()[0:12]
35
35
36 class SubrepoAbort(error.Abort):
36 class SubrepoAbort(error.Abort):
37 """Exception class used to avoid handling a subrepo error more than once"""
37 """Exception class used to avoid handling a subrepo error more than once"""
38 def __init__(self, *args, **kw):
38 def __init__(self, *args, **kw):
39 error.Abort.__init__(self, *args, **kw)
39 error.Abort.__init__(self, *args, **kw)
40 self.subrepo = kw.get('subrepo')
40 self.subrepo = kw.get('subrepo')
41 self.cause = kw.get('cause')
41 self.cause = kw.get('cause')
42
42
43 def annotatesubrepoerror(func):
43 def annotatesubrepoerror(func):
44 def decoratedmethod(self, *args, **kargs):
44 def decoratedmethod(self, *args, **kargs):
45 try:
45 try:
46 res = func(self, *args, **kargs)
46 res = func(self, *args, **kargs)
47 except SubrepoAbort, ex:
47 except SubrepoAbort, ex:
48 # This exception has already been handled
48 # This exception has already been handled
49 raise ex
49 raise ex
50 except error.Abort, ex:
50 except error.Abort, ex:
51 subrepo = subrelpath(self)
51 subrepo = subrelpath(self)
52 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
52 errormsg = str(ex) + ' ' + _('(in subrepo %s)') % subrepo
53 # avoid handling this exception by raising a SubrepoAbort exception
53 # avoid handling this exception by raising a SubrepoAbort exception
54 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
54 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo,
55 cause=sys.exc_info())
55 cause=sys.exc_info())
56 return res
56 return res
57 return decoratedmethod
57 return decoratedmethod
58
58
59 def state(ctx, ui):
59 def state(ctx, ui):
60 """return a state dict, mapping subrepo paths configured in .hgsub
60 """return a state dict, mapping subrepo paths configured in .hgsub
61 to tuple: (source from .hgsub, revision from .hgsubstate, kind
61 to tuple: (source from .hgsub, revision from .hgsubstate, kind
62 (key in types dict))
62 (key in types dict))
63 """
63 """
64 p = config.config()
64 p = config.config()
65 def read(f, sections=None, remap=None):
65 def read(f, sections=None, remap=None):
66 if f in ctx:
66 if f in ctx:
67 try:
67 try:
68 data = ctx[f].data()
68 data = ctx[f].data()
69 except IOError, err:
69 except IOError, err:
70 if err.errno != errno.ENOENT:
70 if err.errno != errno.ENOENT:
71 raise
71 raise
72 # handle missing subrepo spec files as removed
72 # handle missing subrepo spec files as removed
73 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") %
73 ui.warn(_("warning: subrepo spec file \'%s\' not found\n") %
74 util.pathto(ctx.repo().root, ctx.repo().getcwd(), f))
74 util.pathto(ctx.repo().root, ctx.repo().getcwd(), f))
75 return
75 return
76 p.parse(f, data, sections, remap, read)
76 p.parse(f, data, sections, remap, read)
77 else:
77 else:
78 repo = ctx.repo()
78 repo = ctx.repo()
79 raise util.Abort(_("subrepo spec file \'%s\' not found") %
79 raise util.Abort(_("subrepo spec file \'%s\' not found") %
80 util.pathto(repo.root, repo.getcwd(), f))
80 util.pathto(repo.root, repo.getcwd(), f))
81
81
82 if '.hgsub' in ctx:
82 if '.hgsub' in ctx:
83 read('.hgsub')
83 read('.hgsub')
84
84
85 for path, src in ui.configitems('subpaths'):
85 for path, src in ui.configitems('subpaths'):
86 p.set('subpaths', path, src, ui.configsource('subpaths', path))
86 p.set('subpaths', path, src, ui.configsource('subpaths', path))
87
87
88 rev = {}
88 rev = {}
89 if '.hgsubstate' in ctx:
89 if '.hgsubstate' in ctx:
90 try:
90 try:
91 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
91 for i, l in enumerate(ctx['.hgsubstate'].data().splitlines()):
92 l = l.lstrip()
92 l = l.lstrip()
93 if not l:
93 if not l:
94 continue
94 continue
95 try:
95 try:
96 revision, path = l.split(" ", 1)
96 revision, path = l.split(" ", 1)
97 except ValueError:
97 except ValueError:
98 repo = ctx.repo()
98 repo = ctx.repo()
99 raise util.Abort(_("invalid subrepository revision "
99 raise util.Abort(_("invalid subrepository revision "
100 "specifier in \'%s\' line %d")
100 "specifier in \'%s\' line %d")
101 % (util.pathto(repo.root, repo.getcwd(),
101 % (util.pathto(repo.root, repo.getcwd(),
102 '.hgsubstate'), (i + 1)))
102 '.hgsubstate'), (i + 1)))
103 rev[path] = revision
103 rev[path] = revision
104 except IOError, err:
104 except IOError, err:
105 if err.errno != errno.ENOENT:
105 if err.errno != errno.ENOENT:
106 raise
106 raise
107
107
108 def remap(src):
108 def remap(src):
109 for pattern, repl in p.items('subpaths'):
109 for pattern, repl in p.items('subpaths'):
110 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
110 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
111 # does a string decode.
111 # does a string decode.
112 repl = repl.encode('string-escape')
112 repl = repl.encode('string-escape')
113 # However, we still want to allow back references to go
113 # However, we still want to allow back references to go
114 # through unharmed, so we turn r'\\1' into r'\1'. Again,
114 # through unharmed, so we turn r'\\1' into r'\1'. Again,
115 # extra escapes are needed because re.sub string decodes.
115 # extra escapes are needed because re.sub string decodes.
116 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
116 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
117 try:
117 try:
118 src = re.sub(pattern, repl, src, 1)
118 src = re.sub(pattern, repl, src, 1)
119 except re.error, e:
119 except re.error, e:
120 raise util.Abort(_("bad subrepository pattern in %s: %s")
120 raise util.Abort(_("bad subrepository pattern in %s: %s")
121 % (p.source('subpaths', pattern), e))
121 % (p.source('subpaths', pattern), e))
122 return src
122 return src
123
123
124 state = {}
124 state = {}
125 for path, src in p[''].items():
125 for path, src in p[''].items():
126 kind = 'hg'
126 kind = 'hg'
127 if src.startswith('['):
127 if src.startswith('['):
128 if ']' not in src:
128 if ']' not in src:
129 raise util.Abort(_('missing ] in subrepo source'))
129 raise util.Abort(_('missing ] in subrepo source'))
130 kind, src = src.split(']', 1)
130 kind, src = src.split(']', 1)
131 kind = kind[1:]
131 kind = kind[1:]
132 src = src.lstrip() # strip any extra whitespace after ']'
132 src = src.lstrip() # strip any extra whitespace after ']'
133
133
134 if not util.url(src).isabs():
134 if not util.url(src).isabs():
135 parent = _abssource(ctx.repo(), abort=False)
135 parent = _abssource(ctx.repo(), abort=False)
136 if parent:
136 if parent:
137 parent = util.url(parent)
137 parent = util.url(parent)
138 parent.path = posixpath.join(parent.path or '', src)
138 parent.path = posixpath.join(parent.path or '', src)
139 parent.path = posixpath.normpath(parent.path)
139 parent.path = posixpath.normpath(parent.path)
140 joined = str(parent)
140 joined = str(parent)
141 # Remap the full joined path and use it if it changes,
141 # Remap the full joined path and use it if it changes,
142 # else remap the original source.
142 # else remap the original source.
143 remapped = remap(joined)
143 remapped = remap(joined)
144 if remapped == joined:
144 if remapped == joined:
145 src = remap(src)
145 src = remap(src)
146 else:
146 else:
147 src = remapped
147 src = remapped
148
148
149 src = remap(src)
149 src = remap(src)
150 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
150 state[util.pconvert(path)] = (src.strip(), rev.get(path, ''), kind)
151
151
152 return state
152 return state
153
153
154 def writestate(repo, state):
154 def writestate(repo, state):
155 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
155 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
156 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)
156 lines = ['%s %s\n' % (state[s][1], s) for s in sorted(state)
157 if state[s][1] != nullstate[1]]
157 if state[s][1] != nullstate[1]]
158 repo.wwrite('.hgsubstate', ''.join(lines), '')
158 repo.wwrite('.hgsubstate', ''.join(lines), '')
159
159
160 def submerge(repo, wctx, mctx, actx, overwrite):
160 def submerge(repo, wctx, mctx, actx, overwrite):
161 """delegated from merge.applyupdates: merging of .hgsubstate file
161 """delegated from merge.applyupdates: merging of .hgsubstate file
162 in working context, merging context and ancestor context"""
162 in working context, merging context and ancestor context"""
163 if mctx == actx: # backwards?
163 if mctx == actx: # backwards?
164 actx = wctx.p1()
164 actx = wctx.p1()
165 s1 = wctx.substate
165 s1 = wctx.substate
166 s2 = mctx.substate
166 s2 = mctx.substate
167 sa = actx.substate
167 sa = actx.substate
168 sm = {}
168 sm = {}
169
169
170 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
170 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
171
171
172 def debug(s, msg, r=""):
172 def debug(s, msg, r=""):
173 if r:
173 if r:
174 r = "%s:%s:%s" % r
174 r = "%s:%s:%s" % r
175 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
175 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
176
176
177 for s, l in sorted(s1.iteritems()):
177 for s, l in sorted(s1.iteritems()):
178 a = sa.get(s, nullstate)
178 a = sa.get(s, nullstate)
179 ld = l # local state with possible dirty flag for compares
179 ld = l # local state with possible dirty flag for compares
180 if wctx.sub(s).dirty():
180 if wctx.sub(s).dirty():
181 ld = (l[0], l[1] + "+")
181 ld = (l[0], l[1] + "+")
182 if wctx == actx: # overwrite
182 if wctx == actx: # overwrite
183 a = ld
183 a = ld
184
184
185 if s in s2:
185 if s in s2:
186 r = s2[s]
186 r = s2[s]
187 if ld == r or r == a: # no change or local is newer
187 if ld == r or r == a: # no change or local is newer
188 sm[s] = l
188 sm[s] = l
189 continue
189 continue
190 elif ld == a: # other side changed
190 elif ld == a: # other side changed
191 debug(s, "other changed, get", r)
191 debug(s, "other changed, get", r)
192 wctx.sub(s).get(r, overwrite)
192 wctx.sub(s).get(r, overwrite)
193 sm[s] = r
193 sm[s] = r
194 elif ld[0] != r[0]: # sources differ
194 elif ld[0] != r[0]: # sources differ
195 if repo.ui.promptchoice(
195 if repo.ui.promptchoice(
196 _(' subrepository sources for %s differ\n'
196 _(' subrepository sources for %s differ\n'
197 'use (l)ocal source (%s) or (r)emote source (%s)?'
197 'use (l)ocal source (%s) or (r)emote source (%s)?'
198 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
198 '$$ &Local $$ &Remote') % (s, l[0], r[0]), 0):
199 debug(s, "prompt changed, get", r)
199 debug(s, "prompt changed, get", r)
200 wctx.sub(s).get(r, overwrite)
200 wctx.sub(s).get(r, overwrite)
201 sm[s] = r
201 sm[s] = r
202 elif ld[1] == a[1]: # local side is unchanged
202 elif ld[1] == a[1]: # local side is unchanged
203 debug(s, "other side changed, get", r)
203 debug(s, "other side changed, get", r)
204 wctx.sub(s).get(r, overwrite)
204 wctx.sub(s).get(r, overwrite)
205 sm[s] = r
205 sm[s] = r
206 else:
206 else:
207 debug(s, "both sides changed")
207 debug(s, "both sides changed")
208 srepo = wctx.sub(s)
208 srepo = wctx.sub(s)
209 option = repo.ui.promptchoice(
209 option = repo.ui.promptchoice(
210 _(' subrepository %s diverged (local revision: %s, '
210 _(' subrepository %s diverged (local revision: %s, '
211 'remote revision: %s)\n'
211 'remote revision: %s)\n'
212 '(M)erge, keep (l)ocal or keep (r)emote?'
212 '(M)erge, keep (l)ocal or keep (r)emote?'
213 '$$ &Merge $$ &Local $$ &Remote')
213 '$$ &Merge $$ &Local $$ &Remote')
214 % (s, srepo.shortid(l[1]), srepo.shortid(r[1])), 0)
214 % (s, srepo.shortid(l[1]), srepo.shortid(r[1])), 0)
215 if option == 0:
215 if option == 0:
216 wctx.sub(s).merge(r)
216 wctx.sub(s).merge(r)
217 sm[s] = l
217 sm[s] = l
218 debug(s, "merge with", r)
218 debug(s, "merge with", r)
219 elif option == 1:
219 elif option == 1:
220 sm[s] = l
220 sm[s] = l
221 debug(s, "keep local subrepo revision", l)
221 debug(s, "keep local subrepo revision", l)
222 else:
222 else:
223 wctx.sub(s).get(r, overwrite)
223 wctx.sub(s).get(r, overwrite)
224 sm[s] = r
224 sm[s] = r
225 debug(s, "get remote subrepo revision", r)
225 debug(s, "get remote subrepo revision", r)
226 elif ld == a: # remote removed, local unchanged
226 elif ld == a: # remote removed, local unchanged
227 debug(s, "remote removed, remove")
227 debug(s, "remote removed, remove")
228 wctx.sub(s).remove()
228 wctx.sub(s).remove()
229 elif a == nullstate: # not present in remote or ancestor
229 elif a == nullstate: # not present in remote or ancestor
230 debug(s, "local added, keep")
230 debug(s, "local added, keep")
231 sm[s] = l
231 sm[s] = l
232 continue
232 continue
233 else:
233 else:
234 if repo.ui.promptchoice(
234 if repo.ui.promptchoice(
235 _(' local changed subrepository %s which remote removed\n'
235 _(' local changed subrepository %s which remote removed\n'
236 'use (c)hanged version or (d)elete?'
236 'use (c)hanged version or (d)elete?'
237 '$$ &Changed $$ &Delete') % s, 0):
237 '$$ &Changed $$ &Delete') % s, 0):
238 debug(s, "prompt remove")
238 debug(s, "prompt remove")
239 wctx.sub(s).remove()
239 wctx.sub(s).remove()
240
240
241 for s, r in sorted(s2.items()):
241 for s, r in sorted(s2.items()):
242 if s in s1:
242 if s in s1:
243 continue
243 continue
244 elif s not in sa:
244 elif s not in sa:
245 debug(s, "remote added, get", r)
245 debug(s, "remote added, get", r)
246 mctx.sub(s).get(r)
246 mctx.sub(s).get(r)
247 sm[s] = r
247 sm[s] = r
248 elif r != sa[s]:
248 elif r != sa[s]:
249 if repo.ui.promptchoice(
249 if repo.ui.promptchoice(
250 _(' remote changed subrepository %s which local removed\n'
250 _(' remote changed subrepository %s which local removed\n'
251 'use (c)hanged version or (d)elete?'
251 'use (c)hanged version or (d)elete?'
252 '$$ &Changed $$ &Delete') % s, 0) == 0:
252 '$$ &Changed $$ &Delete') % s, 0) == 0:
253 debug(s, "prompt recreate", r)
253 debug(s, "prompt recreate", r)
254 mctx.sub(s).get(r)
254 mctx.sub(s).get(r)
255 sm[s] = r
255 sm[s] = r
256
256
257 # record merged .hgsubstate
257 # record merged .hgsubstate
258 writestate(repo, sm)
258 writestate(repo, sm)
259 return sm
259 return sm
260
260
261 def _updateprompt(ui, sub, dirty, local, remote):
261 def _updateprompt(ui, sub, dirty, local, remote):
262 if dirty:
262 if dirty:
263 msg = (_(' subrepository sources for %s differ\n'
263 msg = (_(' subrepository sources for %s differ\n'
264 'use (l)ocal source (%s) or (r)emote source (%s)?'
264 'use (l)ocal source (%s) or (r)emote source (%s)?'
265 '$$ &Local $$ &Remote')
265 '$$ &Local $$ &Remote')
266 % (subrelpath(sub), local, remote))
266 % (subrelpath(sub), local, remote))
267 else:
267 else:
268 msg = (_(' subrepository sources for %s differ (in checked out '
268 msg = (_(' subrepository sources for %s differ (in checked out '
269 'version)\n'
269 'version)\n'
270 'use (l)ocal source (%s) or (r)emote source (%s)?'
270 'use (l)ocal source (%s) or (r)emote source (%s)?'
271 '$$ &Local $$ &Remote')
271 '$$ &Local $$ &Remote')
272 % (subrelpath(sub), local, remote))
272 % (subrelpath(sub), local, remote))
273 return ui.promptchoice(msg, 0)
273 return ui.promptchoice(msg, 0)
274
274
275 def reporelpath(repo):
275 def reporelpath(repo):
276 """return path to this (sub)repo as seen from outermost repo"""
276 """return path to this (sub)repo as seen from outermost repo"""
277 parent = repo
277 parent = repo
278 while util.safehasattr(parent, '_subparent'):
278 while util.safehasattr(parent, '_subparent'):
279 parent = parent._subparent
279 parent = parent._subparent
280 return repo.root[len(pathutil.normasprefix(parent.root)):]
280 return repo.root[len(pathutil.normasprefix(parent.root)):]
281
281
282 def subrelpath(sub):
282 def subrelpath(sub):
283 """return path to this subrepo as seen from outermost repo"""
283 """return path to this subrepo as seen from outermost repo"""
284 return sub._relpath
284 return sub._relpath
285
285
286 def _abssource(repo, push=False, abort=True):
286 def _abssource(repo, push=False, abort=True):
287 """return pull/push path of repo - either based on parent repo .hgsub info
287 """return pull/push path of repo - either based on parent repo .hgsub info
288 or on the top repo config. Abort or return None if no source found."""
288 or on the top repo config. Abort or return None if no source found."""
289 if util.safehasattr(repo, '_subparent'):
289 if util.safehasattr(repo, '_subparent'):
290 source = util.url(repo._subsource)
290 source = util.url(repo._subsource)
291 if source.isabs():
291 if source.isabs():
292 return str(source)
292 return str(source)
293 source.path = posixpath.normpath(source.path)
293 source.path = posixpath.normpath(source.path)
294 parent = _abssource(repo._subparent, push, abort=False)
294 parent = _abssource(repo._subparent, push, abort=False)
295 if parent:
295 if parent:
296 parent = util.url(util.pconvert(parent))
296 parent = util.url(util.pconvert(parent))
297 parent.path = posixpath.join(parent.path or '', source.path)
297 parent.path = posixpath.join(parent.path or '', source.path)
298 parent.path = posixpath.normpath(parent.path)
298 parent.path = posixpath.normpath(parent.path)
299 return str(parent)
299 return str(parent)
300 else: # recursion reached top repo
300 else: # recursion reached top repo
301 if util.safehasattr(repo, '_subtoppath'):
301 if util.safehasattr(repo, '_subtoppath'):
302 return repo._subtoppath
302 return repo._subtoppath
303 if push and repo.ui.config('paths', 'default-push'):
303 if push and repo.ui.config('paths', 'default-push'):
304 return repo.ui.config('paths', 'default-push')
304 return repo.ui.config('paths', 'default-push')
305 if repo.ui.config('paths', 'default'):
305 if repo.ui.config('paths', 'default'):
306 return repo.ui.config('paths', 'default')
306 return repo.ui.config('paths', 'default')
307 if repo.shared():
307 if repo.shared():
308 # chop off the .hg component to get the default path form
308 # chop off the .hg component to get the default path form
309 return os.path.dirname(repo.sharedpath)
309 return os.path.dirname(repo.sharedpath)
310 if abort:
310 if abort:
311 raise util.Abort(_("default path for subrepository not found"))
311 raise util.Abort(_("default path for subrepository not found"))
312
312
313 def _sanitize(ui, vfs, ignore):
313 def _sanitize(ui, vfs, ignore):
314 for dirname, dirs, names in vfs.walk():
314 for dirname, dirs, names in vfs.walk():
315 for i, d in enumerate(dirs):
315 for i, d in enumerate(dirs):
316 if d.lower() == ignore:
316 if d.lower() == ignore:
317 del dirs[i]
317 del dirs[i]
318 break
318 break
319 if os.path.basename(dirname).lower() != '.hg':
319 if os.path.basename(dirname).lower() != '.hg':
320 continue
320 continue
321 for f in names:
321 for f in names:
322 if f.lower() == 'hgrc':
322 if f.lower() == 'hgrc':
323 ui.warn(_("warning: removing potentially hostile 'hgrc' "
323 ui.warn(_("warning: removing potentially hostile 'hgrc' "
324 "in '%s'\n") % vfs.join(dirname))
324 "in '%s'\n") % vfs.join(dirname))
325 vfs.unlink(vfs.reljoin(dirname, f))
325 vfs.unlink(vfs.reljoin(dirname, f))
326
326
327 def subrepo(ctx, path):
327 def subrepo(ctx, path):
328 """return instance of the right subrepo class for subrepo in path"""
328 """return instance of the right subrepo class for subrepo in path"""
329 # subrepo inherently violates our import layering rules
329 # subrepo inherently violates our import layering rules
330 # because it wants to make repo objects from deep inside the stack
330 # because it wants to make repo objects from deep inside the stack
331 # so we manually delay the circular imports to not break
331 # so we manually delay the circular imports to not break
332 # scripts that don't use our demand-loading
332 # scripts that don't use our demand-loading
333 global hg
333 global hg
334 import hg as h
334 import hg as h
335 hg = h
335 hg = h
336
336
337 pathutil.pathauditor(ctx.repo().root)(path)
337 pathutil.pathauditor(ctx.repo().root)(path)
338 state = ctx.substate[path]
338 state = ctx.substate[path]
339 if state[2] not in types:
339 if state[2] not in types:
340 raise util.Abort(_('unknown subrepo type %s') % state[2])
340 raise util.Abort(_('unknown subrepo type %s') % state[2])
341 return types[state[2]](ctx, path, state[:2])
341 return types[state[2]](ctx, path, state[:2])
342
342
343 def newcommitphase(ui, ctx):
343 def newcommitphase(ui, ctx):
344 commitphase = phases.newcommitphase(ui)
344 commitphase = phases.newcommitphase(ui)
345 substate = getattr(ctx, "substate", None)
345 substate = getattr(ctx, "substate", None)
346 if not substate:
346 if not substate:
347 return commitphase
347 return commitphase
348 check = ui.config('phases', 'checksubrepos', 'follow')
348 check = ui.config('phases', 'checksubrepos', 'follow')
349 if check not in ('ignore', 'follow', 'abort'):
349 if check not in ('ignore', 'follow', 'abort'):
350 raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
350 raise util.Abort(_('invalid phases.checksubrepos configuration: %s')
351 % (check))
351 % (check))
352 if check == 'ignore':
352 if check == 'ignore':
353 return commitphase
353 return commitphase
354 maxphase = phases.public
354 maxphase = phases.public
355 maxsub = None
355 maxsub = None
356 for s in sorted(substate):
356 for s in sorted(substate):
357 sub = ctx.sub(s)
357 sub = ctx.sub(s)
358 subphase = sub.phase(substate[s][1])
358 subphase = sub.phase(substate[s][1])
359 if maxphase < subphase:
359 if maxphase < subphase:
360 maxphase = subphase
360 maxphase = subphase
361 maxsub = s
361 maxsub = s
362 if commitphase < maxphase:
362 if commitphase < maxphase:
363 if check == 'abort':
363 if check == 'abort':
364 raise util.Abort(_("can't commit in %s phase"
364 raise util.Abort(_("can't commit in %s phase"
365 " conflicting %s from subrepository %s") %
365 " conflicting %s from subrepository %s") %
366 (phases.phasenames[commitphase],
366 (phases.phasenames[commitphase],
367 phases.phasenames[maxphase], maxsub))
367 phases.phasenames[maxphase], maxsub))
368 ui.warn(_("warning: changes are committed in"
368 ui.warn(_("warning: changes are committed in"
369 " %s phase from subrepository %s\n") %
369 " %s phase from subrepository %s\n") %
370 (phases.phasenames[maxphase], maxsub))
370 (phases.phasenames[maxphase], maxsub))
371 return maxphase
371 return maxphase
372 return commitphase
372 return commitphase
373
373
374 # subrepo classes need to implement the following abstract class:
374 # subrepo classes need to implement the following abstract class:
375
375
376 class abstractsubrepo(object):
376 class abstractsubrepo(object):
377
377
378 def __init__(self, ctx, path):
378 def __init__(self, ctx, path):
379 """Initialize abstractsubrepo part
379 """Initialize abstractsubrepo part
380
380
381 ``ctx`` is the context referring this subrepository in the
381 ``ctx`` is the context referring this subrepository in the
382 parent repository.
382 parent repository.
383
383
384 ``path`` is the path to this subrepositiry as seen from
384 ``path`` is the path to this subrepositiry as seen from
385 innermost repository.
385 innermost repository.
386 """
386 """
387 self.ui = ctx.repo().ui
387 self.ui = ctx.repo().ui
388 self._ctx = ctx
388 self._ctx = ctx
389 self._path = path
389 self._path = path
390
390
391 def storeclean(self, path):
391 def storeclean(self, path):
392 """
392 """
393 returns true if the repository has not changed since it was last
393 returns true if the repository has not changed since it was last
394 cloned from or pushed to a given repository.
394 cloned from or pushed to a given repository.
395 """
395 """
396 return False
396 return False
397
397
398 def dirty(self, ignoreupdate=False):
398 def dirty(self, ignoreupdate=False):
399 """returns true if the dirstate of the subrepo is dirty or does not
399 """returns true if the dirstate of the subrepo is dirty or does not
400 match current stored state. If ignoreupdate is true, only check
400 match current stored state. If ignoreupdate is true, only check
401 whether the subrepo has uncommitted changes in its dirstate.
401 whether the subrepo has uncommitted changes in its dirstate.
402 """
402 """
403 raise NotImplementedError
403 raise NotImplementedError
404
404
405 def dirtyreason(self, ignoreupdate=False):
405 def dirtyreason(self, ignoreupdate=False):
406 """return reason string if it is ``dirty()``
406 """return reason string if it is ``dirty()``
407
407
408 Returned string should have enough information for the message
408 Returned string should have enough information for the message
409 of exception.
409 of exception.
410
410
411 This returns None, otherwise.
411 This returns None, otherwise.
412 """
412 """
413 if self.dirty(ignoreupdate=ignoreupdate):
413 if self.dirty(ignoreupdate=ignoreupdate):
414 return _("uncommitted changes in subrepository '%s'"
414 return _("uncommitted changes in subrepository '%s'"
415 ) % subrelpath(self)
415 ) % subrelpath(self)
416
416
417 def bailifchanged(self, ignoreupdate=False):
417 def bailifchanged(self, ignoreupdate=False):
418 """raise Abort if subrepository is ``dirty()``
418 """raise Abort if subrepository is ``dirty()``
419 """
419 """
420 dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate)
420 dirtyreason = self.dirtyreason(ignoreupdate=ignoreupdate)
421 if dirtyreason:
421 if dirtyreason:
422 raise util.Abort(dirtyreason)
422 raise util.Abort(dirtyreason)
423
423
424 def basestate(self):
424 def basestate(self):
425 """current working directory base state, disregarding .hgsubstate
425 """current working directory base state, disregarding .hgsubstate
426 state and working directory modifications"""
426 state and working directory modifications"""
427 raise NotImplementedError
427 raise NotImplementedError
428
428
429 def checknested(self, path):
429 def checknested(self, path):
430 """check if path is a subrepository within this repository"""
430 """check if path is a subrepository within this repository"""
431 return False
431 return False
432
432
433 def commit(self, text, user, date):
433 def commit(self, text, user, date):
434 """commit the current changes to the subrepo with the given
434 """commit the current changes to the subrepo with the given
435 log message. Use given user and date if possible. Return the
435 log message. Use given user and date if possible. Return the
436 new state of the subrepo.
436 new state of the subrepo.
437 """
437 """
438 raise NotImplementedError
438 raise NotImplementedError
439
439
440 def phase(self, state):
440 def phase(self, state):
441 """returns phase of specified state in the subrepository.
441 """returns phase of specified state in the subrepository.
442 """
442 """
443 return phases.public
443 return phases.public
444
444
445 def remove(self):
445 def remove(self):
446 """remove the subrepo
446 """remove the subrepo
447
447
448 (should verify the dirstate is not dirty first)
448 (should verify the dirstate is not dirty first)
449 """
449 """
450 raise NotImplementedError
450 raise NotImplementedError
451
451
452 def get(self, state, overwrite=False):
452 def get(self, state, overwrite=False):
453 """run whatever commands are needed to put the subrepo into
453 """run whatever commands are needed to put the subrepo into
454 this state
454 this state
455 """
455 """
456 raise NotImplementedError
456 raise NotImplementedError
457
457
458 def merge(self, state):
458 def merge(self, state):
459 """merge currently-saved state with the new state."""
459 """merge currently-saved state with the new state."""
460 raise NotImplementedError
460 raise NotImplementedError
461
461
462 def push(self, opts):
462 def push(self, opts):
463 """perform whatever action is analogous to 'hg push'
463 """perform whatever action is analogous to 'hg push'
464
464
465 This may be a no-op on some systems.
465 This may be a no-op on some systems.
466 """
466 """
467 raise NotImplementedError
467 raise NotImplementedError
468
468
469 def add(self, ui, match, prefix, explicitonly, **opts):
469 def add(self, ui, match, prefix, explicitonly, **opts):
470 return []
470 return []
471
471
472 def addremove(self, matcher, prefix, opts, dry_run, similarity):
472 def addremove(self, matcher, prefix, opts, dry_run, similarity):
473 self.ui.warn("%s: %s" % (prefix, _("addremove is not supported")))
473 self.ui.warn("%s: %s" % (prefix, _("addremove is not supported")))
474 return 1
474 return 1
475
475
476 def cat(self, match, prefix, **opts):
476 def cat(self, match, prefix, **opts):
477 return 1
477 return 1
478
478
479 def status(self, rev2, **opts):
479 def status(self, rev2, **opts):
480 return scmutil.status([], [], [], [], [], [], [])
480 return scmutil.status([], [], [], [], [], [], [])
481
481
482 def diff(self, ui, diffopts, node2, match, prefix, **opts):
482 def diff(self, ui, diffopts, node2, match, prefix, **opts):
483 pass
483 pass
484
484
485 def outgoing(self, ui, dest, opts):
485 def outgoing(self, ui, dest, opts):
486 return 1
486 return 1
487
487
488 def incoming(self, ui, source, opts):
488 def incoming(self, ui, source, opts):
489 return 1
489 return 1
490
490
491 def files(self):
491 def files(self):
492 """return filename iterator"""
492 """return filename iterator"""
493 raise NotImplementedError
493 raise NotImplementedError
494
494
495 def filedata(self, name):
495 def filedata(self, name):
496 """return file data"""
496 """return file data"""
497 raise NotImplementedError
497 raise NotImplementedError
498
498
499 def fileflags(self, name):
499 def fileflags(self, name):
500 """return file flags"""
500 """return file flags"""
501 return ''
501 return ''
502
502
503 def printfiles(self, ui, m, fm, fmt):
503 def printfiles(self, ui, m, fm, fmt):
504 """handle the files command for this subrepo"""
504 """handle the files command for this subrepo"""
505 return 1
505 return 1
506
506
507 def archive(self, archiver, prefix, match=None):
507 def archive(self, archiver, prefix, match=None):
508 if match is not None:
508 if match is not None:
509 files = [f for f in self.files() if match(f)]
509 files = [f for f in self.files() if match(f)]
510 else:
510 else:
511 files = self.files()
511 files = self.files()
512 total = len(files)
512 total = len(files)
513 relpath = subrelpath(self)
513 relpath = subrelpath(self)
514 self.ui.progress(_('archiving (%s)') % relpath, 0,
514 self.ui.progress(_('archiving (%s)') % relpath, 0,
515 unit=_('files'), total=total)
515 unit=_('files'), total=total)
516 for i, name in enumerate(files):
516 for i, name in enumerate(files):
517 flags = self.fileflags(name)
517 flags = self.fileflags(name)
518 mode = 'x' in flags and 0755 or 0644
518 mode = 'x' in flags and 0755 or 0644
519 symlink = 'l' in flags
519 symlink = 'l' in flags
520 archiver.addfile(self.wvfs.reljoin(prefix, self._path, name),
520 archiver.addfile(self.wvfs.reljoin(prefix, self._path, name),
521 mode, symlink, self.filedata(name))
521 mode, symlink, self.filedata(name))
522 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
522 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
523 unit=_('files'), total=total)
523 unit=_('files'), total=total)
524 self.ui.progress(_('archiving (%s)') % relpath, None)
524 self.ui.progress(_('archiving (%s)') % relpath, None)
525 return total
525 return total
526
526
527 def walk(self, match):
527 def walk(self, match):
528 '''
528 '''
529 walk recursively through the directory tree, finding all files
529 walk recursively through the directory tree, finding all files
530 matched by the match function
530 matched by the match function
531 '''
531 '''
532 pass
532 pass
533
533
534 def forget(self, match, prefix):
534 def forget(self, match, prefix):
535 return ([], [])
535 return ([], [])
536
536
537 def removefiles(self, matcher, prefix, after, force, subrepos):
537 def removefiles(self, matcher, prefix, after, force, subrepos):
538 """remove the matched files from the subrepository and the filesystem,
538 """remove the matched files from the subrepository and the filesystem,
539 possibly by force and/or after the file has been removed from the
539 possibly by force and/or after the file has been removed from the
540 filesystem. Return 0 on success, 1 on any warning.
540 filesystem. Return 0 on success, 1 on any warning.
541 """
541 """
542 return 1
542 return 1
543
543
544 def revert(self, substate, *pats, **opts):
544 def revert(self, substate, *pats, **opts):
545 self.ui.warn('%s: reverting %s subrepos is unsupported\n' \
545 self.ui.warn('%s: reverting %s subrepos is unsupported\n' \
546 % (substate[0], substate[2]))
546 % (substate[0], substate[2]))
547 return []
547 return []
548
548
549 def shortid(self, revid):
549 def shortid(self, revid):
550 return revid
550 return revid
551
551
552 @propertycache
552 @propertycache
553 def wvfs(self):
553 def wvfs(self):
554 """return vfs to access the working directory of this subrepository
554 """return vfs to access the working directory of this subrepository
555 """
555 """
556 return scmutil.vfs(self._ctx.repo().wvfs.join(self._path))
556 return scmutil.vfs(self._ctx.repo().wvfs.join(self._path))
557
557
558 @propertycache
558 @propertycache
559 def _relpath(self):
559 def _relpath(self):
560 """return path to this subrepository as seen from outermost repository
560 """return path to this subrepository as seen from outermost repository
561 """
561 """
562 return self.wvfs.reljoin(reporelpath(self._ctx.repo()), self._path)
562 return self.wvfs.reljoin(reporelpath(self._ctx.repo()), self._path)
563
563
564 class hgsubrepo(abstractsubrepo):
564 class hgsubrepo(abstractsubrepo):
565 def __init__(self, ctx, path, state):
565 def __init__(self, ctx, path, state):
566 super(hgsubrepo, self).__init__(ctx, path)
566 super(hgsubrepo, self).__init__(ctx, path)
567 self._state = state
567 self._state = state
568 r = ctx.repo()
568 r = ctx.repo()
569 root = r.wjoin(path)
569 root = r.wjoin(path)
570 create = not r.wvfs.exists('%s/.hg' % path)
570 create = not r.wvfs.exists('%s/.hg' % path)
571 self._repo = hg.repository(r.baseui, root, create=create)
571 self._repo = hg.repository(r.baseui, root, create=create)
572 self.ui = self._repo.ui
572 self.ui = self._repo.ui
573 for s, k in [('ui', 'commitsubrepos')]:
573 for s, k in [('ui', 'commitsubrepos')]:
574 v = r.ui.config(s, k)
574 v = r.ui.config(s, k)
575 if v:
575 if v:
576 self.ui.setconfig(s, k, v, 'subrepo')
576 self.ui.setconfig(s, k, v, 'subrepo')
577 self.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo')
577 self.ui.setconfig('ui', '_usedassubrepo', 'True', 'subrepo')
578 self._initrepo(r, state[0], create)
578 self._initrepo(r, state[0], create)
579
579
580 def storeclean(self, path):
580 def storeclean(self, path):
581 lock = self._repo.lock()
581 lock = self._repo.lock()
582 try:
582 try:
583 return self._storeclean(path)
583 return self._storeclean(path)
584 finally:
584 finally:
585 lock.release()
585 lock.release()
586
586
587 def _storeclean(self, path):
587 def _storeclean(self, path):
588 clean = True
588 clean = True
589 itercache = self._calcstorehash(path)
589 itercache = self._calcstorehash(path)
590 try:
590 try:
591 for filehash in self._readstorehashcache(path):
591 for filehash in self._readstorehashcache(path):
592 if filehash != itercache.next():
592 if filehash != itercache.next():
593 clean = False
593 clean = False
594 break
594 break
595 except StopIteration:
595 except StopIteration:
596 # the cached and current pull states have a different size
596 # the cached and current pull states have a different size
597 clean = False
597 clean = False
598 if clean:
598 if clean:
599 try:
599 try:
600 itercache.next()
600 itercache.next()
601 # the cached and current pull states have a different size
601 # the cached and current pull states have a different size
602 clean = False
602 clean = False
603 except StopIteration:
603 except StopIteration:
604 pass
604 pass
605 return clean
605 return clean
606
606
607 def _calcstorehash(self, remotepath):
607 def _calcstorehash(self, remotepath):
608 '''calculate a unique "store hash"
608 '''calculate a unique "store hash"
609
609
610 This method is used to to detect when there are changes that may
610 This method is used to to detect when there are changes that may
611 require a push to a given remote path.'''
611 require a push to a given remote path.'''
612 # sort the files that will be hashed in increasing (likely) file size
612 # sort the files that will be hashed in increasing (likely) file size
613 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
613 filelist = ('bookmarks', 'store/phaseroots', 'store/00changelog.i')
614 yield '# %s\n' % _expandedabspath(remotepath)
614 yield '# %s\n' % _expandedabspath(remotepath)
615 vfs = self._repo.vfs
615 vfs = self._repo.vfs
616 for relname in filelist:
616 for relname in filelist:
617 filehash = util.sha1(vfs.tryread(relname)).hexdigest()
617 filehash = util.sha1(vfs.tryread(relname)).hexdigest()
618 yield '%s = %s\n' % (relname, filehash)
618 yield '%s = %s\n' % (relname, filehash)
619
619
620 @propertycache
620 @propertycache
621 def _cachestorehashvfs(self):
621 def _cachestorehashvfs(self):
622 return scmutil.vfs(self._repo.join('cache/storehash'))
622 return scmutil.vfs(self._repo.join('cache/storehash'))
623
623
624 def _readstorehashcache(self, remotepath):
624 def _readstorehashcache(self, remotepath):
625 '''read the store hash cache for a given remote repository'''
625 '''read the store hash cache for a given remote repository'''
626 cachefile = _getstorehashcachename(remotepath)
626 cachefile = _getstorehashcachename(remotepath)
627 return self._cachestorehashvfs.tryreadlines(cachefile, 'r')
627 return self._cachestorehashvfs.tryreadlines(cachefile, 'r')
628
628
629 def _cachestorehash(self, remotepath):
629 def _cachestorehash(self, remotepath):
630 '''cache the current store hash
630 '''cache the current store hash
631
631
632 Each remote repo requires its own store hash cache, because a subrepo
632 Each remote repo requires its own store hash cache, because a subrepo
633 store may be "clean" versus a given remote repo, but not versus another
633 store may be "clean" versus a given remote repo, but not versus another
634 '''
634 '''
635 cachefile = _getstorehashcachename(remotepath)
635 cachefile = _getstorehashcachename(remotepath)
636 lock = self._repo.lock()
636 lock = self._repo.lock()
637 try:
637 try:
638 storehash = list(self._calcstorehash(remotepath))
638 storehash = list(self._calcstorehash(remotepath))
639 vfs = self._cachestorehashvfs
639 vfs = self._cachestorehashvfs
640 vfs.writelines(cachefile, storehash, mode='w', notindexed=True)
640 vfs.writelines(cachefile, storehash, mode='w', notindexed=True)
641 finally:
641 finally:
642 lock.release()
642 lock.release()
643
643
644 @annotatesubrepoerror
644 @annotatesubrepoerror
645 def _initrepo(self, parentrepo, source, create):
645 def _initrepo(self, parentrepo, source, create):
646 self._repo._subparent = parentrepo
646 self._repo._subparent = parentrepo
647 self._repo._subsource = source
647 self._repo._subsource = source
648
648
649 if create:
649 if create:
650 lines = ['[paths]\n']
650 lines = ['[paths]\n']
651
651
652 def addpathconfig(key, value):
652 def addpathconfig(key, value):
653 if value:
653 if value:
654 lines.append('%s = %s\n' % (key, value))
654 lines.append('%s = %s\n' % (key, value))
655 self.ui.setconfig('paths', key, value, 'subrepo')
655 self.ui.setconfig('paths', key, value, 'subrepo')
656
656
657 defpath = _abssource(self._repo, abort=False)
657 defpath = _abssource(self._repo, abort=False)
658 defpushpath = _abssource(self._repo, True, abort=False)
658 defpushpath = _abssource(self._repo, True, abort=False)
659 addpathconfig('default', defpath)
659 addpathconfig('default', defpath)
660 if defpath != defpushpath:
660 if defpath != defpushpath:
661 addpathconfig('default-push', defpushpath)
661 addpathconfig('default-push', defpushpath)
662
662
663 fp = self._repo.vfs("hgrc", "w", text=True)
663 fp = self._repo.vfs("hgrc", "w", text=True)
664 try:
664 try:
665 fp.write(''.join(lines))
665 fp.write(''.join(lines))
666 finally:
666 finally:
667 fp.close()
667 fp.close()
668
668
669 @annotatesubrepoerror
669 @annotatesubrepoerror
670 def add(self, ui, match, prefix, explicitonly, **opts):
670 def add(self, ui, match, prefix, explicitonly, **opts):
671 return cmdutil.add(ui, self._repo, match,
671 return cmdutil.add(ui, self._repo, match,
672 self.wvfs.reljoin(prefix, self._path),
672 self.wvfs.reljoin(prefix, self._path),
673 explicitonly, **opts)
673 explicitonly, **opts)
674
674
675 @annotatesubrepoerror
675 @annotatesubrepoerror
676 def addremove(self, m, prefix, opts, dry_run, similarity):
676 def addremove(self, m, prefix, opts, dry_run, similarity):
677 # In the same way as sub directories are processed, once in a subrepo,
677 # In the same way as sub directories are processed, once in a subrepo,
678 # always entry any of its subrepos. Don't corrupt the options that will
678 # always entry any of its subrepos. Don't corrupt the options that will
679 # be used to process sibling subrepos however.
679 # be used to process sibling subrepos however.
680 opts = copy.copy(opts)
680 opts = copy.copy(opts)
681 opts['subrepos'] = True
681 opts['subrepos'] = True
682 return scmutil.addremove(self._repo, m,
682 return scmutil.addremove(self._repo, m,
683 self.wvfs.reljoin(prefix, self._path), opts,
683 self.wvfs.reljoin(prefix, self._path), opts,
684 dry_run, similarity)
684 dry_run, similarity)
685
685
686 @annotatesubrepoerror
686 @annotatesubrepoerror
687 def cat(self, match, prefix, **opts):
687 def cat(self, match, prefix, **opts):
688 rev = self._state[1]
688 rev = self._state[1]
689 ctx = self._repo[rev]
689 ctx = self._repo[rev]
690 return cmdutil.cat(self.ui, self._repo, ctx, match, prefix, **opts)
690 return cmdutil.cat(self.ui, self._repo, ctx, match, prefix, **opts)
691
691
692 @annotatesubrepoerror
692 @annotatesubrepoerror
693 def status(self, rev2, **opts):
693 def status(self, rev2, **opts):
694 try:
694 try:
695 rev1 = self._state[1]
695 rev1 = self._state[1]
696 ctx1 = self._repo[rev1]
696 ctx1 = self._repo[rev1]
697 ctx2 = self._repo[rev2]
697 ctx2 = self._repo[rev2]
698 return self._repo.status(ctx1, ctx2, **opts)
698 return self._repo.status(ctx1, ctx2, **opts)
699 except error.RepoLookupError, inst:
699 except error.RepoLookupError, inst:
700 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
700 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
701 % (inst, subrelpath(self)))
701 % (inst, subrelpath(self)))
702 return scmutil.status([], [], [], [], [], [], [])
702 return scmutil.status([], [], [], [], [], [], [])
703
703
704 @annotatesubrepoerror
704 @annotatesubrepoerror
705 def diff(self, ui, diffopts, node2, match, prefix, **opts):
705 def diff(self, ui, diffopts, node2, match, prefix, **opts):
706 try:
706 try:
707 node1 = node.bin(self._state[1])
707 node1 = node.bin(self._state[1])
708 # We currently expect node2 to come from substate and be
708 # We currently expect node2 to come from substate and be
709 # in hex format
709 # in hex format
710 if node2 is not None:
710 if node2 is not None:
711 node2 = node.bin(node2)
711 node2 = node.bin(node2)
712 cmdutil.diffordiffstat(ui, self._repo, diffopts,
712 cmdutil.diffordiffstat(ui, self._repo, diffopts,
713 node1, node2, match,
713 node1, node2, match,
714 prefix=posixpath.join(prefix, self._path),
714 prefix=posixpath.join(prefix, self._path),
715 listsubrepos=True, **opts)
715 listsubrepos=True, **opts)
716 except error.RepoLookupError, inst:
716 except error.RepoLookupError, inst:
717 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
717 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
718 % (inst, subrelpath(self)))
718 % (inst, subrelpath(self)))
719
719
720 @annotatesubrepoerror
720 @annotatesubrepoerror
721 def archive(self, archiver, prefix, match=None):
721 def archive(self, archiver, prefix, match=None):
722 self._get(self._state + ('hg',))
722 self._get(self._state + ('hg',))
723 total = abstractsubrepo.archive(self, archiver, prefix, match)
723 total = abstractsubrepo.archive(self, archiver, prefix, match)
724 rev = self._state[1]
724 rev = self._state[1]
725 ctx = self._repo[rev]
725 ctx = self._repo[rev]
726 for subpath in ctx.substate:
726 for subpath in ctx.substate:
727 s = subrepo(ctx, subpath)
727 s = subrepo(ctx, subpath)
728 submatch = matchmod.narrowmatcher(subpath, match)
728 submatch = matchmod.narrowmatcher(subpath, match)
729 total += s.archive(
729 total += s.archive(
730 archiver, self.wvfs.reljoin(prefix, self._path), submatch)
730 archiver, self.wvfs.reljoin(prefix, self._path), submatch)
731 return total
731 return total
732
732
733 @annotatesubrepoerror
733 @annotatesubrepoerror
734 def dirty(self, ignoreupdate=False):
734 def dirty(self, ignoreupdate=False):
735 r = self._state[1]
735 r = self._state[1]
736 if r == '' and not ignoreupdate: # no state recorded
736 if r == '' and not ignoreupdate: # no state recorded
737 return True
737 return True
738 w = self._repo[None]
738 w = self._repo[None]
739 if r != w.p1().hex() and not ignoreupdate:
739 if r != w.p1().hex() and not ignoreupdate:
740 # different version checked out
740 # different version checked out
741 return True
741 return True
742 return w.dirty() # working directory changed
742 return w.dirty() # working directory changed
743
743
744 def basestate(self):
744 def basestate(self):
745 return self._repo['.'].hex()
745 return self._repo['.'].hex()
746
746
747 def checknested(self, path):
747 def checknested(self, path):
748 return self._repo._checknested(self._repo.wjoin(path))
748 return self._repo._checknested(self._repo.wjoin(path))
749
749
750 @annotatesubrepoerror
750 @annotatesubrepoerror
751 def commit(self, text, user, date):
751 def commit(self, text, user, date):
752 # don't bother committing in the subrepo if it's only been
752 # don't bother committing in the subrepo if it's only been
753 # updated
753 # updated
754 if not self.dirty(True):
754 if not self.dirty(True):
755 return self._repo['.'].hex()
755 return self._repo['.'].hex()
756 self.ui.debug("committing subrepo %s\n" % subrelpath(self))
756 self.ui.debug("committing subrepo %s\n" % subrelpath(self))
757 n = self._repo.commit(text, user, date)
757 n = self._repo.commit(text, user, date)
758 if not n:
758 if not n:
759 return self._repo['.'].hex() # different version checked out
759 return self._repo['.'].hex() # different version checked out
760 return node.hex(n)
760 return node.hex(n)
761
761
762 @annotatesubrepoerror
762 @annotatesubrepoerror
763 def phase(self, state):
763 def phase(self, state):
764 return self._repo[state].phase()
764 return self._repo[state].phase()
765
765
766 @annotatesubrepoerror
766 @annotatesubrepoerror
767 def remove(self):
767 def remove(self):
768 # we can't fully delete the repository as it may contain
768 # we can't fully delete the repository as it may contain
769 # local-only history
769 # local-only history
770 self.ui.note(_('removing subrepo %s\n') % subrelpath(self))
770 self.ui.note(_('removing subrepo %s\n') % subrelpath(self))
771 hg.clean(self._repo, node.nullid, False)
771 hg.clean(self._repo, node.nullid, False)
772
772
773 def _get(self, state):
773 def _get(self, state):
774 source, revision, kind = state
774 source, revision, kind = state
775 if revision in self._repo.unfiltered():
775 if revision in self._repo.unfiltered():
776 return True
776 return True
777 self._repo._subsource = source
777 self._repo._subsource = source
778 srcurl = _abssource(self._repo)
778 srcurl = _abssource(self._repo)
779 other = hg.peer(self._repo, {}, srcurl)
779 other = hg.peer(self._repo, {}, srcurl)
780 if len(self._repo) == 0:
780 if len(self._repo) == 0:
781 self.ui.status(_('cloning subrepo %s from %s\n')
781 self.ui.status(_('cloning subrepo %s from %s\n')
782 % (subrelpath(self), srcurl))
782 % (subrelpath(self), srcurl))
783 parentrepo = self._repo._subparent
783 parentrepo = self._repo._subparent
784 # use self._repo.vfs instead of self.wvfs to remove .hg only
784 # use self._repo.vfs instead of self.wvfs to remove .hg only
785 self._repo.vfs.rmtree()
785 self._repo.vfs.rmtree()
786 other, cloned = hg.clone(self._repo._subparent.baseui, {},
786 other, cloned = hg.clone(self._repo._subparent.baseui, {},
787 other, self._repo.root,
787 other, self._repo.root,
788 update=False)
788 update=False)
789 self._repo = cloned.local()
789 self._repo = cloned.local()
790 self._initrepo(parentrepo, source, create=True)
790 self._initrepo(parentrepo, source, create=True)
791 self._cachestorehash(srcurl)
791 self._cachestorehash(srcurl)
792 else:
792 else:
793 self.ui.status(_('pulling subrepo %s from %s\n')
793 self.ui.status(_('pulling subrepo %s from %s\n')
794 % (subrelpath(self), srcurl))
794 % (subrelpath(self), srcurl))
795 cleansub = self.storeclean(srcurl)
795 cleansub = self.storeclean(srcurl)
796 exchange.pull(self._repo, other)
796 exchange.pull(self._repo, other)
797 if cleansub:
797 if cleansub:
798 # keep the repo clean after pull
798 # keep the repo clean after pull
799 self._cachestorehash(srcurl)
799 self._cachestorehash(srcurl)
800 return False
800 return False
801
801
802 @annotatesubrepoerror
802 @annotatesubrepoerror
803 def get(self, state, overwrite=False):
803 def get(self, state, overwrite=False):
804 inrepo = self._get(state)
804 inrepo = self._get(state)
805 source, revision, kind = state
805 source, revision, kind = state
806 repo = self._repo
806 repo = self._repo
807 repo.ui.debug("getting subrepo %s\n" % self._path)
807 repo.ui.debug("getting subrepo %s\n" % self._path)
808 if inrepo:
808 if inrepo:
809 urepo = repo.unfiltered()
809 urepo = repo.unfiltered()
810 ctx = urepo[revision]
810 ctx = urepo[revision]
811 if ctx.hidden():
811 if ctx.hidden():
812 urepo.ui.warn(
812 urepo.ui.warn(
813 _('revision %s in subrepo %s is hidden\n') \
813 _('revision %s in subrepo %s is hidden\n') \
814 % (revision[0:12], self._path))
814 % (revision[0:12], self._path))
815 repo = urepo
815 repo = urepo
816 hg.updaterepo(repo, revision, overwrite)
816 hg.updaterepo(repo, revision, overwrite)
817
817
818 @annotatesubrepoerror
818 @annotatesubrepoerror
819 def merge(self, state):
819 def merge(self, state):
820 self._get(state)
820 self._get(state)
821 cur = self._repo['.']
821 cur = self._repo['.']
822 dst = self._repo[state[1]]
822 dst = self._repo[state[1]]
823 anc = dst.ancestor(cur)
823 anc = dst.ancestor(cur)
824
824
825 def mergefunc():
825 def mergefunc():
826 if anc == cur and dst.branch() == cur.branch():
826 if anc == cur and dst.branch() == cur.branch():
827 self.ui.debug("updating subrepo %s\n" % subrelpath(self))
827 self.ui.debug("updating subrepo %s\n" % subrelpath(self))
828 hg.update(self._repo, state[1])
828 hg.update(self._repo, state[1])
829 elif anc == dst:
829 elif anc == dst:
830 self.ui.debug("skipping subrepo %s\n" % subrelpath(self))
830 self.ui.debug("skipping subrepo %s\n" % subrelpath(self))
831 else:
831 else:
832 self.ui.debug("merging subrepo %s\n" % subrelpath(self))
832 self.ui.debug("merging subrepo %s\n" % subrelpath(self))
833 hg.merge(self._repo, state[1], remind=False)
833 hg.merge(self._repo, state[1], remind=False)
834
834
835 wctx = self._repo[None]
835 wctx = self._repo[None]
836 if self.dirty():
836 if self.dirty():
837 if anc != dst:
837 if anc != dst:
838 if _updateprompt(self.ui, self, wctx.dirty(), cur, dst):
838 if _updateprompt(self.ui, self, wctx.dirty(), cur, dst):
839 mergefunc()
839 mergefunc()
840 else:
840 else:
841 mergefunc()
841 mergefunc()
842 else:
842 else:
843 mergefunc()
843 mergefunc()
844
844
845 @annotatesubrepoerror
845 @annotatesubrepoerror
846 def push(self, opts):
846 def push(self, opts):
847 force = opts.get('force')
847 force = opts.get('force')
848 newbranch = opts.get('new_branch')
848 newbranch = opts.get('new_branch')
849 ssh = opts.get('ssh')
849 ssh = opts.get('ssh')
850
850
851 # push subrepos depth-first for coherent ordering
851 # push subrepos depth-first for coherent ordering
852 c = self._repo['']
852 c = self._repo['']
853 subs = c.substate # only repos that are committed
853 subs = c.substate # only repos that are committed
854 for s in sorted(subs):
854 for s in sorted(subs):
855 if c.sub(s).push(opts) == 0:
855 if c.sub(s).push(opts) == 0:
856 return False
856 return False
857
857
858 dsturl = _abssource(self._repo, True)
858 dsturl = _abssource(self._repo, True)
859 if not force:
859 if not force:
860 if self.storeclean(dsturl):
860 if self.storeclean(dsturl):
861 self.ui.status(
861 self.ui.status(
862 _('no changes made to subrepo %s since last push to %s\n')
862 _('no changes made to subrepo %s since last push to %s\n')
863 % (subrelpath(self), dsturl))
863 % (subrelpath(self), dsturl))
864 return None
864 return None
865 self.ui.status(_('pushing subrepo %s to %s\n') %
865 self.ui.status(_('pushing subrepo %s to %s\n') %
866 (subrelpath(self), dsturl))
866 (subrelpath(self), dsturl))
867 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
867 other = hg.peer(self._repo, {'ssh': ssh}, dsturl)
868 res = exchange.push(self._repo, other, force, newbranch=newbranch)
868 res = exchange.push(self._repo, other, force, newbranch=newbranch)
869
869
870 # the repo is now clean
870 # the repo is now clean
871 self._cachestorehash(dsturl)
871 self._cachestorehash(dsturl)
872 return res.cgresult
872 return res.cgresult
873
873
874 @annotatesubrepoerror
874 @annotatesubrepoerror
875 def outgoing(self, ui, dest, opts):
875 def outgoing(self, ui, dest, opts):
876 if 'rev' in opts or 'branch' in opts:
876 if 'rev' in opts or 'branch' in opts:
877 opts = copy.copy(opts)
877 opts = copy.copy(opts)
878 opts.pop('rev', None)
878 opts.pop('rev', None)
879 opts.pop('branch', None)
879 opts.pop('branch', None)
880 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
880 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
881
881
882 @annotatesubrepoerror
882 @annotatesubrepoerror
883 def incoming(self, ui, source, opts):
883 def incoming(self, ui, source, opts):
884 if 'rev' in opts or 'branch' in opts:
885 opts = copy.copy(opts)
886 opts.pop('rev', None)
887 opts.pop('branch', None)
884 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
888 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
885
889
886 @annotatesubrepoerror
890 @annotatesubrepoerror
887 def files(self):
891 def files(self):
888 rev = self._state[1]
892 rev = self._state[1]
889 ctx = self._repo[rev]
893 ctx = self._repo[rev]
890 return ctx.manifest().keys()
894 return ctx.manifest().keys()
891
895
892 def filedata(self, name):
896 def filedata(self, name):
893 rev = self._state[1]
897 rev = self._state[1]
894 return self._repo[rev][name].data()
898 return self._repo[rev][name].data()
895
899
896 def fileflags(self, name):
900 def fileflags(self, name):
897 rev = self._state[1]
901 rev = self._state[1]
898 ctx = self._repo[rev]
902 ctx = self._repo[rev]
899 return ctx.flags(name)
903 return ctx.flags(name)
900
904
901 @annotatesubrepoerror
905 @annotatesubrepoerror
902 def printfiles(self, ui, m, fm, fmt):
906 def printfiles(self, ui, m, fm, fmt):
903 # If the parent context is a workingctx, use the workingctx here for
907 # If the parent context is a workingctx, use the workingctx here for
904 # consistency.
908 # consistency.
905 if self._ctx.rev() is None:
909 if self._ctx.rev() is None:
906 ctx = self._repo[None]
910 ctx = self._repo[None]
907 else:
911 else:
908 rev = self._state[1]
912 rev = self._state[1]
909 ctx = self._repo[rev]
913 ctx = self._repo[rev]
910 return cmdutil.files(ui, ctx, m, fm, fmt, True)
914 return cmdutil.files(ui, ctx, m, fm, fmt, True)
911
915
912 def walk(self, match):
916 def walk(self, match):
913 ctx = self._repo[None]
917 ctx = self._repo[None]
914 return ctx.walk(match)
918 return ctx.walk(match)
915
919
916 @annotatesubrepoerror
920 @annotatesubrepoerror
917 def forget(self, match, prefix):
921 def forget(self, match, prefix):
918 return cmdutil.forget(self.ui, self._repo, match,
922 return cmdutil.forget(self.ui, self._repo, match,
919 self.wvfs.reljoin(prefix, self._path), True)
923 self.wvfs.reljoin(prefix, self._path), True)
920
924
921 @annotatesubrepoerror
925 @annotatesubrepoerror
922 def removefiles(self, matcher, prefix, after, force, subrepos):
926 def removefiles(self, matcher, prefix, after, force, subrepos):
923 return cmdutil.remove(self.ui, self._repo, matcher,
927 return cmdutil.remove(self.ui, self._repo, matcher,
924 self.wvfs.reljoin(prefix, self._path),
928 self.wvfs.reljoin(prefix, self._path),
925 after, force, subrepos)
929 after, force, subrepos)
926
930
927 @annotatesubrepoerror
931 @annotatesubrepoerror
928 def revert(self, substate, *pats, **opts):
932 def revert(self, substate, *pats, **opts):
929 # reverting a subrepo is a 2 step process:
933 # reverting a subrepo is a 2 step process:
930 # 1. if the no_backup is not set, revert all modified
934 # 1. if the no_backup is not set, revert all modified
931 # files inside the subrepo
935 # files inside the subrepo
932 # 2. update the subrepo to the revision specified in
936 # 2. update the subrepo to the revision specified in
933 # the corresponding substate dictionary
937 # the corresponding substate dictionary
934 self.ui.status(_('reverting subrepo %s\n') % substate[0])
938 self.ui.status(_('reverting subrepo %s\n') % substate[0])
935 if not opts.get('no_backup'):
939 if not opts.get('no_backup'):
936 # Revert all files on the subrepo, creating backups
940 # Revert all files on the subrepo, creating backups
937 # Note that this will not recursively revert subrepos
941 # Note that this will not recursively revert subrepos
938 # We could do it if there was a set:subrepos() predicate
942 # We could do it if there was a set:subrepos() predicate
939 opts = opts.copy()
943 opts = opts.copy()
940 opts['date'] = None
944 opts['date'] = None
941 opts['rev'] = substate[1]
945 opts['rev'] = substate[1]
942
946
943 self.filerevert(*pats, **opts)
947 self.filerevert(*pats, **opts)
944
948
945 # Update the repo to the revision specified in the given substate
949 # Update the repo to the revision specified in the given substate
946 if not opts.get('dry_run'):
950 if not opts.get('dry_run'):
947 self.get(substate, overwrite=True)
951 self.get(substate, overwrite=True)
948
952
949 def filerevert(self, *pats, **opts):
953 def filerevert(self, *pats, **opts):
950 ctx = self._repo[opts['rev']]
954 ctx = self._repo[opts['rev']]
951 parents = self._repo.dirstate.parents()
955 parents = self._repo.dirstate.parents()
952 if opts.get('all'):
956 if opts.get('all'):
953 pats = ['set:modified()']
957 pats = ['set:modified()']
954 else:
958 else:
955 pats = []
959 pats = []
956 cmdutil.revert(self.ui, self._repo, ctx, parents, *pats, **opts)
960 cmdutil.revert(self.ui, self._repo, ctx, parents, *pats, **opts)
957
961
958 def shortid(self, revid):
962 def shortid(self, revid):
959 return revid[:12]
963 return revid[:12]
960
964
961 @propertycache
965 @propertycache
962 def wvfs(self):
966 def wvfs(self):
963 """return own wvfs for efficiency and consitency
967 """return own wvfs for efficiency and consitency
964 """
968 """
965 return self._repo.wvfs
969 return self._repo.wvfs
966
970
967 @propertycache
971 @propertycache
968 def _relpath(self):
972 def _relpath(self):
969 """return path to this subrepository as seen from outermost repository
973 """return path to this subrepository as seen from outermost repository
970 """
974 """
971 # Keep consistent dir separators by avoiding vfs.join(self._path)
975 # Keep consistent dir separators by avoiding vfs.join(self._path)
972 return reporelpath(self._repo)
976 return reporelpath(self._repo)
973
977
974 class svnsubrepo(abstractsubrepo):
978 class svnsubrepo(abstractsubrepo):
975 def __init__(self, ctx, path, state):
979 def __init__(self, ctx, path, state):
976 super(svnsubrepo, self).__init__(ctx, path)
980 super(svnsubrepo, self).__init__(ctx, path)
977 self._state = state
981 self._state = state
978 self._exe = util.findexe('svn')
982 self._exe = util.findexe('svn')
979 if not self._exe:
983 if not self._exe:
980 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
984 raise util.Abort(_("'svn' executable not found for subrepo '%s'")
981 % self._path)
985 % self._path)
982
986
983 def _svncommand(self, commands, filename='', failok=False):
987 def _svncommand(self, commands, filename='', failok=False):
984 cmd = [self._exe]
988 cmd = [self._exe]
985 extrakw = {}
989 extrakw = {}
986 if not self.ui.interactive():
990 if not self.ui.interactive():
987 # Making stdin be a pipe should prevent svn from behaving
991 # Making stdin be a pipe should prevent svn from behaving
988 # interactively even if we can't pass --non-interactive.
992 # interactively even if we can't pass --non-interactive.
989 extrakw['stdin'] = subprocess.PIPE
993 extrakw['stdin'] = subprocess.PIPE
990 # Starting in svn 1.5 --non-interactive is a global flag
994 # Starting in svn 1.5 --non-interactive is a global flag
991 # instead of being per-command, but we need to support 1.4 so
995 # instead of being per-command, but we need to support 1.4 so
992 # we have to be intelligent about what commands take
996 # we have to be intelligent about what commands take
993 # --non-interactive.
997 # --non-interactive.
994 if commands[0] in ('update', 'checkout', 'commit'):
998 if commands[0] in ('update', 'checkout', 'commit'):
995 cmd.append('--non-interactive')
999 cmd.append('--non-interactive')
996 cmd.extend(commands)
1000 cmd.extend(commands)
997 if filename is not None:
1001 if filename is not None:
998 path = self.wvfs.reljoin(self._ctx.repo().origroot,
1002 path = self.wvfs.reljoin(self._ctx.repo().origroot,
999 self._path, filename)
1003 self._path, filename)
1000 cmd.append(path)
1004 cmd.append(path)
1001 env = dict(os.environ)
1005 env = dict(os.environ)
1002 # Avoid localized output, preserve current locale for everything else.
1006 # Avoid localized output, preserve current locale for everything else.
1003 lc_all = env.get('LC_ALL')
1007 lc_all = env.get('LC_ALL')
1004 if lc_all:
1008 if lc_all:
1005 env['LANG'] = lc_all
1009 env['LANG'] = lc_all
1006 del env['LC_ALL']
1010 del env['LC_ALL']
1007 env['LC_MESSAGES'] = 'C'
1011 env['LC_MESSAGES'] = 'C'
1008 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
1012 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
1009 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
1013 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
1010 universal_newlines=True, env=env, **extrakw)
1014 universal_newlines=True, env=env, **extrakw)
1011 stdout, stderr = p.communicate()
1015 stdout, stderr = p.communicate()
1012 stderr = stderr.strip()
1016 stderr = stderr.strip()
1013 if not failok:
1017 if not failok:
1014 if p.returncode:
1018 if p.returncode:
1015 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
1019 raise util.Abort(stderr or 'exited with code %d' % p.returncode)
1016 if stderr:
1020 if stderr:
1017 self.ui.warn(stderr + '\n')
1021 self.ui.warn(stderr + '\n')
1018 return stdout, stderr
1022 return stdout, stderr
1019
1023
1020 @propertycache
1024 @propertycache
1021 def _svnversion(self):
1025 def _svnversion(self):
1022 output, err = self._svncommand(['--version', '--quiet'], filename=None)
1026 output, err = self._svncommand(['--version', '--quiet'], filename=None)
1023 m = re.search(r'^(\d+)\.(\d+)', output)
1027 m = re.search(r'^(\d+)\.(\d+)', output)
1024 if not m:
1028 if not m:
1025 raise util.Abort(_('cannot retrieve svn tool version'))
1029 raise util.Abort(_('cannot retrieve svn tool version'))
1026 return (int(m.group(1)), int(m.group(2)))
1030 return (int(m.group(1)), int(m.group(2)))
1027
1031
1028 def _wcrevs(self):
1032 def _wcrevs(self):
1029 # Get the working directory revision as well as the last
1033 # Get the working directory revision as well as the last
1030 # commit revision so we can compare the subrepo state with
1034 # commit revision so we can compare the subrepo state with
1031 # both. We used to store the working directory one.
1035 # both. We used to store the working directory one.
1032 output, err = self._svncommand(['info', '--xml'])
1036 output, err = self._svncommand(['info', '--xml'])
1033 doc = xml.dom.minidom.parseString(output)
1037 doc = xml.dom.minidom.parseString(output)
1034 entries = doc.getElementsByTagName('entry')
1038 entries = doc.getElementsByTagName('entry')
1035 lastrev, rev = '0', '0'
1039 lastrev, rev = '0', '0'
1036 if entries:
1040 if entries:
1037 rev = str(entries[0].getAttribute('revision')) or '0'
1041 rev = str(entries[0].getAttribute('revision')) or '0'
1038 commits = entries[0].getElementsByTagName('commit')
1042 commits = entries[0].getElementsByTagName('commit')
1039 if commits:
1043 if commits:
1040 lastrev = str(commits[0].getAttribute('revision')) or '0'
1044 lastrev = str(commits[0].getAttribute('revision')) or '0'
1041 return (lastrev, rev)
1045 return (lastrev, rev)
1042
1046
1043 def _wcrev(self):
1047 def _wcrev(self):
1044 return self._wcrevs()[0]
1048 return self._wcrevs()[0]
1045
1049
1046 def _wcchanged(self):
1050 def _wcchanged(self):
1047 """Return (changes, extchanges, missing) where changes is True
1051 """Return (changes, extchanges, missing) where changes is True
1048 if the working directory was changed, extchanges is
1052 if the working directory was changed, extchanges is
1049 True if any of these changes concern an external entry and missing
1053 True if any of these changes concern an external entry and missing
1050 is True if any change is a missing entry.
1054 is True if any change is a missing entry.
1051 """
1055 """
1052 output, err = self._svncommand(['status', '--xml'])
1056 output, err = self._svncommand(['status', '--xml'])
1053 externals, changes, missing = [], [], []
1057 externals, changes, missing = [], [], []
1054 doc = xml.dom.minidom.parseString(output)
1058 doc = xml.dom.minidom.parseString(output)
1055 for e in doc.getElementsByTagName('entry'):
1059 for e in doc.getElementsByTagName('entry'):
1056 s = e.getElementsByTagName('wc-status')
1060 s = e.getElementsByTagName('wc-status')
1057 if not s:
1061 if not s:
1058 continue
1062 continue
1059 item = s[0].getAttribute('item')
1063 item = s[0].getAttribute('item')
1060 props = s[0].getAttribute('props')
1064 props = s[0].getAttribute('props')
1061 path = e.getAttribute('path')
1065 path = e.getAttribute('path')
1062 if item == 'external':
1066 if item == 'external':
1063 externals.append(path)
1067 externals.append(path)
1064 elif item == 'missing':
1068 elif item == 'missing':
1065 missing.append(path)
1069 missing.append(path)
1066 if (item not in ('', 'normal', 'unversioned', 'external')
1070 if (item not in ('', 'normal', 'unversioned', 'external')
1067 or props not in ('', 'none', 'normal')):
1071 or props not in ('', 'none', 'normal')):
1068 changes.append(path)
1072 changes.append(path)
1069 for path in changes:
1073 for path in changes:
1070 for ext in externals:
1074 for ext in externals:
1071 if path == ext or path.startswith(ext + os.sep):
1075 if path == ext or path.startswith(ext + os.sep):
1072 return True, True, bool(missing)
1076 return True, True, bool(missing)
1073 return bool(changes), False, bool(missing)
1077 return bool(changes), False, bool(missing)
1074
1078
1075 def dirty(self, ignoreupdate=False):
1079 def dirty(self, ignoreupdate=False):
1076 if not self._wcchanged()[0]:
1080 if not self._wcchanged()[0]:
1077 if self._state[1] in self._wcrevs() or ignoreupdate:
1081 if self._state[1] in self._wcrevs() or ignoreupdate:
1078 return False
1082 return False
1079 return True
1083 return True
1080
1084
1081 def basestate(self):
1085 def basestate(self):
1082 lastrev, rev = self._wcrevs()
1086 lastrev, rev = self._wcrevs()
1083 if lastrev != rev:
1087 if lastrev != rev:
1084 # Last committed rev is not the same than rev. We would
1088 # Last committed rev is not the same than rev. We would
1085 # like to take lastrev but we do not know if the subrepo
1089 # like to take lastrev but we do not know if the subrepo
1086 # URL exists at lastrev. Test it and fallback to rev it
1090 # URL exists at lastrev. Test it and fallback to rev it
1087 # is not there.
1091 # is not there.
1088 try:
1092 try:
1089 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
1093 self._svncommand(['list', '%s@%s' % (self._state[0], lastrev)])
1090 return lastrev
1094 return lastrev
1091 except error.Abort:
1095 except error.Abort:
1092 pass
1096 pass
1093 return rev
1097 return rev
1094
1098
1095 @annotatesubrepoerror
1099 @annotatesubrepoerror
1096 def commit(self, text, user, date):
1100 def commit(self, text, user, date):
1097 # user and date are out of our hands since svn is centralized
1101 # user and date are out of our hands since svn is centralized
1098 changed, extchanged, missing = self._wcchanged()
1102 changed, extchanged, missing = self._wcchanged()
1099 if not changed:
1103 if not changed:
1100 return self.basestate()
1104 return self.basestate()
1101 if extchanged:
1105 if extchanged:
1102 # Do not try to commit externals
1106 # Do not try to commit externals
1103 raise util.Abort(_('cannot commit svn externals'))
1107 raise util.Abort(_('cannot commit svn externals'))
1104 if missing:
1108 if missing:
1105 # svn can commit with missing entries but aborting like hg
1109 # svn can commit with missing entries but aborting like hg
1106 # seems a better approach.
1110 # seems a better approach.
1107 raise util.Abort(_('cannot commit missing svn entries'))
1111 raise util.Abort(_('cannot commit missing svn entries'))
1108 commitinfo, err = self._svncommand(['commit', '-m', text])
1112 commitinfo, err = self._svncommand(['commit', '-m', text])
1109 self.ui.status(commitinfo)
1113 self.ui.status(commitinfo)
1110 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
1114 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
1111 if not newrev:
1115 if not newrev:
1112 if not commitinfo.strip():
1116 if not commitinfo.strip():
1113 # Sometimes, our definition of "changed" differs from
1117 # Sometimes, our definition of "changed" differs from
1114 # svn one. For instance, svn ignores missing files
1118 # svn one. For instance, svn ignores missing files
1115 # when committing. If there are only missing files, no
1119 # when committing. If there are only missing files, no
1116 # commit is made, no output and no error code.
1120 # commit is made, no output and no error code.
1117 raise util.Abort(_('failed to commit svn changes'))
1121 raise util.Abort(_('failed to commit svn changes'))
1118 raise util.Abort(commitinfo.splitlines()[-1])
1122 raise util.Abort(commitinfo.splitlines()[-1])
1119 newrev = newrev.groups()[0]
1123 newrev = newrev.groups()[0]
1120 self.ui.status(self._svncommand(['update', '-r', newrev])[0])
1124 self.ui.status(self._svncommand(['update', '-r', newrev])[0])
1121 return newrev
1125 return newrev
1122
1126
1123 @annotatesubrepoerror
1127 @annotatesubrepoerror
1124 def remove(self):
1128 def remove(self):
1125 if self.dirty():
1129 if self.dirty():
1126 self.ui.warn(_('not removing repo %s because '
1130 self.ui.warn(_('not removing repo %s because '
1127 'it has changes.\n') % self._path)
1131 'it has changes.\n') % self._path)
1128 return
1132 return
1129 self.ui.note(_('removing subrepo %s\n') % self._path)
1133 self.ui.note(_('removing subrepo %s\n') % self._path)
1130
1134
1131 self.wvfs.rmtree(forcibly=True)
1135 self.wvfs.rmtree(forcibly=True)
1132 try:
1136 try:
1133 self._ctx.repo().wvfs.removedirs(os.path.dirname(self._path))
1137 self._ctx.repo().wvfs.removedirs(os.path.dirname(self._path))
1134 except OSError:
1138 except OSError:
1135 pass
1139 pass
1136
1140
1137 @annotatesubrepoerror
1141 @annotatesubrepoerror
1138 def get(self, state, overwrite=False):
1142 def get(self, state, overwrite=False):
1139 if overwrite:
1143 if overwrite:
1140 self._svncommand(['revert', '--recursive'])
1144 self._svncommand(['revert', '--recursive'])
1141 args = ['checkout']
1145 args = ['checkout']
1142 if self._svnversion >= (1, 5):
1146 if self._svnversion >= (1, 5):
1143 args.append('--force')
1147 args.append('--force')
1144 # The revision must be specified at the end of the URL to properly
1148 # The revision must be specified at the end of the URL to properly
1145 # update to a directory which has since been deleted and recreated.
1149 # update to a directory which has since been deleted and recreated.
1146 args.append('%s@%s' % (state[0], state[1]))
1150 args.append('%s@%s' % (state[0], state[1]))
1147 status, err = self._svncommand(args, failok=True)
1151 status, err = self._svncommand(args, failok=True)
1148 _sanitize(self.ui, self.wvfs, '.svn')
1152 _sanitize(self.ui, self.wvfs, '.svn')
1149 if not re.search('Checked out revision [0-9]+.', status):
1153 if not re.search('Checked out revision [0-9]+.', status):
1150 if ('is already a working copy for a different URL' in err
1154 if ('is already a working copy for a different URL' in err
1151 and (self._wcchanged()[:2] == (False, False))):
1155 and (self._wcchanged()[:2] == (False, False))):
1152 # obstructed but clean working copy, so just blow it away.
1156 # obstructed but clean working copy, so just blow it away.
1153 self.remove()
1157 self.remove()
1154 self.get(state, overwrite=False)
1158 self.get(state, overwrite=False)
1155 return
1159 return
1156 raise util.Abort((status or err).splitlines()[-1])
1160 raise util.Abort((status or err).splitlines()[-1])
1157 self.ui.status(status)
1161 self.ui.status(status)
1158
1162
1159 @annotatesubrepoerror
1163 @annotatesubrepoerror
1160 def merge(self, state):
1164 def merge(self, state):
1161 old = self._state[1]
1165 old = self._state[1]
1162 new = state[1]
1166 new = state[1]
1163 wcrev = self._wcrev()
1167 wcrev = self._wcrev()
1164 if new != wcrev:
1168 if new != wcrev:
1165 dirty = old == wcrev or self._wcchanged()[0]
1169 dirty = old == wcrev or self._wcchanged()[0]
1166 if _updateprompt(self.ui, self, dirty, wcrev, new):
1170 if _updateprompt(self.ui, self, dirty, wcrev, new):
1167 self.get(state, False)
1171 self.get(state, False)
1168
1172
1169 def push(self, opts):
1173 def push(self, opts):
1170 # push is a no-op for SVN
1174 # push is a no-op for SVN
1171 return True
1175 return True
1172
1176
1173 @annotatesubrepoerror
1177 @annotatesubrepoerror
1174 def files(self):
1178 def files(self):
1175 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1179 output = self._svncommand(['list', '--recursive', '--xml'])[0]
1176 doc = xml.dom.minidom.parseString(output)
1180 doc = xml.dom.minidom.parseString(output)
1177 paths = []
1181 paths = []
1178 for e in doc.getElementsByTagName('entry'):
1182 for e in doc.getElementsByTagName('entry'):
1179 kind = str(e.getAttribute('kind'))
1183 kind = str(e.getAttribute('kind'))
1180 if kind != 'file':
1184 if kind != 'file':
1181 continue
1185 continue
1182 name = ''.join(c.data for c
1186 name = ''.join(c.data for c
1183 in e.getElementsByTagName('name')[0].childNodes
1187 in e.getElementsByTagName('name')[0].childNodes
1184 if c.nodeType == c.TEXT_NODE)
1188 if c.nodeType == c.TEXT_NODE)
1185 paths.append(name.encode('utf-8'))
1189 paths.append(name.encode('utf-8'))
1186 return paths
1190 return paths
1187
1191
1188 def filedata(self, name):
1192 def filedata(self, name):
1189 return self._svncommand(['cat'], name)[0]
1193 return self._svncommand(['cat'], name)[0]
1190
1194
1191
1195
1192 class gitsubrepo(abstractsubrepo):
1196 class gitsubrepo(abstractsubrepo):
1193 def __init__(self, ctx, path, state):
1197 def __init__(self, ctx, path, state):
1194 super(gitsubrepo, self).__init__(ctx, path)
1198 super(gitsubrepo, self).__init__(ctx, path)
1195 self._state = state
1199 self._state = state
1196 self._abspath = ctx.repo().wjoin(path)
1200 self._abspath = ctx.repo().wjoin(path)
1197 self._subparent = ctx.repo()
1201 self._subparent = ctx.repo()
1198 self._ensuregit()
1202 self._ensuregit()
1199
1203
1200 def _ensuregit(self):
1204 def _ensuregit(self):
1201 try:
1205 try:
1202 self._gitexecutable = 'git'
1206 self._gitexecutable = 'git'
1203 out, err = self._gitnodir(['--version'])
1207 out, err = self._gitnodir(['--version'])
1204 except OSError, e:
1208 except OSError, e:
1205 if e.errno != 2 or os.name != 'nt':
1209 if e.errno != 2 or os.name != 'nt':
1206 raise
1210 raise
1207 self._gitexecutable = 'git.cmd'
1211 self._gitexecutable = 'git.cmd'
1208 out, err = self._gitnodir(['--version'])
1212 out, err = self._gitnodir(['--version'])
1209 versionstatus = self._checkversion(out)
1213 versionstatus = self._checkversion(out)
1210 if versionstatus == 'unknown':
1214 if versionstatus == 'unknown':
1211 self.ui.warn(_('cannot retrieve git version\n'))
1215 self.ui.warn(_('cannot retrieve git version\n'))
1212 elif versionstatus == 'abort':
1216 elif versionstatus == 'abort':
1213 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1217 raise util.Abort(_('git subrepo requires at least 1.6.0 or later'))
1214 elif versionstatus == 'warning':
1218 elif versionstatus == 'warning':
1215 self.ui.warn(_('git subrepo requires at least 1.6.0 or later\n'))
1219 self.ui.warn(_('git subrepo requires at least 1.6.0 or later\n'))
1216
1220
1217 @staticmethod
1221 @staticmethod
1218 def _gitversion(out):
1222 def _gitversion(out):
1219 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
1223 m = re.search(r'^git version (\d+)\.(\d+)\.(\d+)', out)
1220 if m:
1224 if m:
1221 return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
1225 return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
1222
1226
1223 m = re.search(r'^git version (\d+)\.(\d+)', out)
1227 m = re.search(r'^git version (\d+)\.(\d+)', out)
1224 if m:
1228 if m:
1225 return (int(m.group(1)), int(m.group(2)), 0)
1229 return (int(m.group(1)), int(m.group(2)), 0)
1226
1230
1227 return -1
1231 return -1
1228
1232
1229 @staticmethod
1233 @staticmethod
1230 def _checkversion(out):
1234 def _checkversion(out):
1231 '''ensure git version is new enough
1235 '''ensure git version is new enough
1232
1236
1233 >>> _checkversion = gitsubrepo._checkversion
1237 >>> _checkversion = gitsubrepo._checkversion
1234 >>> _checkversion('git version 1.6.0')
1238 >>> _checkversion('git version 1.6.0')
1235 'ok'
1239 'ok'
1236 >>> _checkversion('git version 1.8.5')
1240 >>> _checkversion('git version 1.8.5')
1237 'ok'
1241 'ok'
1238 >>> _checkversion('git version 1.4.0')
1242 >>> _checkversion('git version 1.4.0')
1239 'abort'
1243 'abort'
1240 >>> _checkversion('git version 1.5.0')
1244 >>> _checkversion('git version 1.5.0')
1241 'warning'
1245 'warning'
1242 >>> _checkversion('git version 1.9-rc0')
1246 >>> _checkversion('git version 1.9-rc0')
1243 'ok'
1247 'ok'
1244 >>> _checkversion('git version 1.9.0.265.g81cdec2')
1248 >>> _checkversion('git version 1.9.0.265.g81cdec2')
1245 'ok'
1249 'ok'
1246 >>> _checkversion('git version 1.9.0.GIT')
1250 >>> _checkversion('git version 1.9.0.GIT')
1247 'ok'
1251 'ok'
1248 >>> _checkversion('git version 12345')
1252 >>> _checkversion('git version 12345')
1249 'unknown'
1253 'unknown'
1250 >>> _checkversion('no')
1254 >>> _checkversion('no')
1251 'unknown'
1255 'unknown'
1252 '''
1256 '''
1253 version = gitsubrepo._gitversion(out)
1257 version = gitsubrepo._gitversion(out)
1254 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1258 # git 1.4.0 can't work at all, but 1.5.X can in at least some cases,
1255 # despite the docstring comment. For now, error on 1.4.0, warn on
1259 # despite the docstring comment. For now, error on 1.4.0, warn on
1256 # 1.5.0 but attempt to continue.
1260 # 1.5.0 but attempt to continue.
1257 if version == -1:
1261 if version == -1:
1258 return 'unknown'
1262 return 'unknown'
1259 if version < (1, 5, 0):
1263 if version < (1, 5, 0):
1260 return 'abort'
1264 return 'abort'
1261 elif version < (1, 6, 0):
1265 elif version < (1, 6, 0):
1262 return 'warning'
1266 return 'warning'
1263 return 'ok'
1267 return 'ok'
1264
1268
1265 def _gitcommand(self, commands, env=None, stream=False):
1269 def _gitcommand(self, commands, env=None, stream=False):
1266 return self._gitdir(commands, env=env, stream=stream)[0]
1270 return self._gitdir(commands, env=env, stream=stream)[0]
1267
1271
1268 def _gitdir(self, commands, env=None, stream=False):
1272 def _gitdir(self, commands, env=None, stream=False):
1269 return self._gitnodir(commands, env=env, stream=stream,
1273 return self._gitnodir(commands, env=env, stream=stream,
1270 cwd=self._abspath)
1274 cwd=self._abspath)
1271
1275
1272 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1276 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
1273 """Calls the git command
1277 """Calls the git command
1274
1278
1275 The methods tries to call the git command. versions prior to 1.6.0
1279 The methods tries to call the git command. versions prior to 1.6.0
1276 are not supported and very probably fail.
1280 are not supported and very probably fail.
1277 """
1281 """
1278 self.ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1282 self.ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
1279 # unless ui.quiet is set, print git's stderr,
1283 # unless ui.quiet is set, print git's stderr,
1280 # which is mostly progress and useful info
1284 # which is mostly progress and useful info
1281 errpipe = None
1285 errpipe = None
1282 if self.ui.quiet:
1286 if self.ui.quiet:
1283 errpipe = open(os.devnull, 'w')
1287 errpipe = open(os.devnull, 'w')
1284 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1288 p = subprocess.Popen([self._gitexecutable] + commands, bufsize=-1,
1285 cwd=cwd, env=env, close_fds=util.closefds,
1289 cwd=cwd, env=env, close_fds=util.closefds,
1286 stdout=subprocess.PIPE, stderr=errpipe)
1290 stdout=subprocess.PIPE, stderr=errpipe)
1287 if stream:
1291 if stream:
1288 return p.stdout, None
1292 return p.stdout, None
1289
1293
1290 retdata = p.stdout.read().strip()
1294 retdata = p.stdout.read().strip()
1291 # wait for the child to exit to avoid race condition.
1295 # wait for the child to exit to avoid race condition.
1292 p.wait()
1296 p.wait()
1293
1297
1294 if p.returncode != 0 and p.returncode != 1:
1298 if p.returncode != 0 and p.returncode != 1:
1295 # there are certain error codes that are ok
1299 # there are certain error codes that are ok
1296 command = commands[0]
1300 command = commands[0]
1297 if command in ('cat-file', 'symbolic-ref'):
1301 if command in ('cat-file', 'symbolic-ref'):
1298 return retdata, p.returncode
1302 return retdata, p.returncode
1299 # for all others, abort
1303 # for all others, abort
1300 raise util.Abort('git %s error %d in %s' %
1304 raise util.Abort('git %s error %d in %s' %
1301 (command, p.returncode, self._relpath))
1305 (command, p.returncode, self._relpath))
1302
1306
1303 return retdata, p.returncode
1307 return retdata, p.returncode
1304
1308
1305 def _gitmissing(self):
1309 def _gitmissing(self):
1306 return not self.wvfs.exists('.git')
1310 return not self.wvfs.exists('.git')
1307
1311
1308 def _gitstate(self):
1312 def _gitstate(self):
1309 return self._gitcommand(['rev-parse', 'HEAD'])
1313 return self._gitcommand(['rev-parse', 'HEAD'])
1310
1314
1311 def _gitcurrentbranch(self):
1315 def _gitcurrentbranch(self):
1312 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1316 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
1313 if err:
1317 if err:
1314 current = None
1318 current = None
1315 return current
1319 return current
1316
1320
1317 def _gitremote(self, remote):
1321 def _gitremote(self, remote):
1318 out = self._gitcommand(['remote', 'show', '-n', remote])
1322 out = self._gitcommand(['remote', 'show', '-n', remote])
1319 line = out.split('\n')[1]
1323 line = out.split('\n')[1]
1320 i = line.index('URL: ') + len('URL: ')
1324 i = line.index('URL: ') + len('URL: ')
1321 return line[i:]
1325 return line[i:]
1322
1326
1323 def _githavelocally(self, revision):
1327 def _githavelocally(self, revision):
1324 out, code = self._gitdir(['cat-file', '-e', revision])
1328 out, code = self._gitdir(['cat-file', '-e', revision])
1325 return code == 0
1329 return code == 0
1326
1330
1327 def _gitisancestor(self, r1, r2):
1331 def _gitisancestor(self, r1, r2):
1328 base = self._gitcommand(['merge-base', r1, r2])
1332 base = self._gitcommand(['merge-base', r1, r2])
1329 return base == r1
1333 return base == r1
1330
1334
1331 def _gitisbare(self):
1335 def _gitisbare(self):
1332 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1336 return self._gitcommand(['config', '--bool', 'core.bare']) == 'true'
1333
1337
1334 def _gitupdatestat(self):
1338 def _gitupdatestat(self):
1335 """This must be run before git diff-index.
1339 """This must be run before git diff-index.
1336 diff-index only looks at changes to file stat;
1340 diff-index only looks at changes to file stat;
1337 this command looks at file contents and updates the stat."""
1341 this command looks at file contents and updates the stat."""
1338 self._gitcommand(['update-index', '-q', '--refresh'])
1342 self._gitcommand(['update-index', '-q', '--refresh'])
1339
1343
1340 def _gitbranchmap(self):
1344 def _gitbranchmap(self):
1341 '''returns 2 things:
1345 '''returns 2 things:
1342 a map from git branch to revision
1346 a map from git branch to revision
1343 a map from revision to branches'''
1347 a map from revision to branches'''
1344 branch2rev = {}
1348 branch2rev = {}
1345 rev2branch = {}
1349 rev2branch = {}
1346
1350
1347 out = self._gitcommand(['for-each-ref', '--format',
1351 out = self._gitcommand(['for-each-ref', '--format',
1348 '%(objectname) %(refname)'])
1352 '%(objectname) %(refname)'])
1349 for line in out.split('\n'):
1353 for line in out.split('\n'):
1350 revision, ref = line.split(' ')
1354 revision, ref = line.split(' ')
1351 if (not ref.startswith('refs/heads/') and
1355 if (not ref.startswith('refs/heads/') and
1352 not ref.startswith('refs/remotes/')):
1356 not ref.startswith('refs/remotes/')):
1353 continue
1357 continue
1354 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1358 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
1355 continue # ignore remote/HEAD redirects
1359 continue # ignore remote/HEAD redirects
1356 branch2rev[ref] = revision
1360 branch2rev[ref] = revision
1357 rev2branch.setdefault(revision, []).append(ref)
1361 rev2branch.setdefault(revision, []).append(ref)
1358 return branch2rev, rev2branch
1362 return branch2rev, rev2branch
1359
1363
1360 def _gittracking(self, branches):
1364 def _gittracking(self, branches):
1361 'return map of remote branch to local tracking branch'
1365 'return map of remote branch to local tracking branch'
1362 # assumes no more than one local tracking branch for each remote
1366 # assumes no more than one local tracking branch for each remote
1363 tracking = {}
1367 tracking = {}
1364 for b in branches:
1368 for b in branches:
1365 if b.startswith('refs/remotes/'):
1369 if b.startswith('refs/remotes/'):
1366 continue
1370 continue
1367 bname = b.split('/', 2)[2]
1371 bname = b.split('/', 2)[2]
1368 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1372 remote = self._gitcommand(['config', 'branch.%s.remote' % bname])
1369 if remote:
1373 if remote:
1370 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1374 ref = self._gitcommand(['config', 'branch.%s.merge' % bname])
1371 tracking['refs/remotes/%s/%s' %
1375 tracking['refs/remotes/%s/%s' %
1372 (remote, ref.split('/', 2)[2])] = b
1376 (remote, ref.split('/', 2)[2])] = b
1373 return tracking
1377 return tracking
1374
1378
1375 def _abssource(self, source):
1379 def _abssource(self, source):
1376 if '://' not in source:
1380 if '://' not in source:
1377 # recognize the scp syntax as an absolute source
1381 # recognize the scp syntax as an absolute source
1378 colon = source.find(':')
1382 colon = source.find(':')
1379 if colon != -1 and '/' not in source[:colon]:
1383 if colon != -1 and '/' not in source[:colon]:
1380 return source
1384 return source
1381 self._subsource = source
1385 self._subsource = source
1382 return _abssource(self)
1386 return _abssource(self)
1383
1387
1384 def _fetch(self, source, revision):
1388 def _fetch(self, source, revision):
1385 if self._gitmissing():
1389 if self._gitmissing():
1386 source = self._abssource(source)
1390 source = self._abssource(source)
1387 self.ui.status(_('cloning subrepo %s from %s\n') %
1391 self.ui.status(_('cloning subrepo %s from %s\n') %
1388 (self._relpath, source))
1392 (self._relpath, source))
1389 self._gitnodir(['clone', source, self._abspath])
1393 self._gitnodir(['clone', source, self._abspath])
1390 if self._githavelocally(revision):
1394 if self._githavelocally(revision):
1391 return
1395 return
1392 self.ui.status(_('pulling subrepo %s from %s\n') %
1396 self.ui.status(_('pulling subrepo %s from %s\n') %
1393 (self._relpath, self._gitremote('origin')))
1397 (self._relpath, self._gitremote('origin')))
1394 # try only origin: the originally cloned repo
1398 # try only origin: the originally cloned repo
1395 self._gitcommand(['fetch'])
1399 self._gitcommand(['fetch'])
1396 if not self._githavelocally(revision):
1400 if not self._githavelocally(revision):
1397 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1401 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
1398 (revision, self._relpath))
1402 (revision, self._relpath))
1399
1403
1400 @annotatesubrepoerror
1404 @annotatesubrepoerror
1401 def dirty(self, ignoreupdate=False):
1405 def dirty(self, ignoreupdate=False):
1402 if self._gitmissing():
1406 if self._gitmissing():
1403 return self._state[1] != ''
1407 return self._state[1] != ''
1404 if self._gitisbare():
1408 if self._gitisbare():
1405 return True
1409 return True
1406 if not ignoreupdate and self._state[1] != self._gitstate():
1410 if not ignoreupdate and self._state[1] != self._gitstate():
1407 # different version checked out
1411 # different version checked out
1408 return True
1412 return True
1409 # check for staged changes or modified files; ignore untracked files
1413 # check for staged changes or modified files; ignore untracked files
1410 self._gitupdatestat()
1414 self._gitupdatestat()
1411 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1415 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1412 return code == 1
1416 return code == 1
1413
1417
1414 def basestate(self):
1418 def basestate(self):
1415 return self._gitstate()
1419 return self._gitstate()
1416
1420
1417 @annotatesubrepoerror
1421 @annotatesubrepoerror
1418 def get(self, state, overwrite=False):
1422 def get(self, state, overwrite=False):
1419 source, revision, kind = state
1423 source, revision, kind = state
1420 if not revision:
1424 if not revision:
1421 self.remove()
1425 self.remove()
1422 return
1426 return
1423 self._fetch(source, revision)
1427 self._fetch(source, revision)
1424 # if the repo was set to be bare, unbare it
1428 # if the repo was set to be bare, unbare it
1425 if self._gitisbare():
1429 if self._gitisbare():
1426 self._gitcommand(['config', 'core.bare', 'false'])
1430 self._gitcommand(['config', 'core.bare', 'false'])
1427 if self._gitstate() == revision:
1431 if self._gitstate() == revision:
1428 self._gitcommand(['reset', '--hard', 'HEAD'])
1432 self._gitcommand(['reset', '--hard', 'HEAD'])
1429 return
1433 return
1430 elif self._gitstate() == revision:
1434 elif self._gitstate() == revision:
1431 if overwrite:
1435 if overwrite:
1432 # first reset the index to unmark new files for commit, because
1436 # first reset the index to unmark new files for commit, because
1433 # reset --hard will otherwise throw away files added for commit,
1437 # reset --hard will otherwise throw away files added for commit,
1434 # not just unmark them.
1438 # not just unmark them.
1435 self._gitcommand(['reset', 'HEAD'])
1439 self._gitcommand(['reset', 'HEAD'])
1436 self._gitcommand(['reset', '--hard', 'HEAD'])
1440 self._gitcommand(['reset', '--hard', 'HEAD'])
1437 return
1441 return
1438 branch2rev, rev2branch = self._gitbranchmap()
1442 branch2rev, rev2branch = self._gitbranchmap()
1439
1443
1440 def checkout(args):
1444 def checkout(args):
1441 cmd = ['checkout']
1445 cmd = ['checkout']
1442 if overwrite:
1446 if overwrite:
1443 # first reset the index to unmark new files for commit, because
1447 # first reset the index to unmark new files for commit, because
1444 # the -f option will otherwise throw away files added for
1448 # the -f option will otherwise throw away files added for
1445 # commit, not just unmark them.
1449 # commit, not just unmark them.
1446 self._gitcommand(['reset', 'HEAD'])
1450 self._gitcommand(['reset', 'HEAD'])
1447 cmd.append('-f')
1451 cmd.append('-f')
1448 self._gitcommand(cmd + args)
1452 self._gitcommand(cmd + args)
1449 _sanitize(self.ui, self.wvfs, '.git')
1453 _sanitize(self.ui, self.wvfs, '.git')
1450
1454
1451 def rawcheckout():
1455 def rawcheckout():
1452 # no branch to checkout, check it out with no branch
1456 # no branch to checkout, check it out with no branch
1453 self.ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1457 self.ui.warn(_('checking out detached HEAD in subrepo %s\n') %
1454 self._relpath)
1458 self._relpath)
1455 self.ui.warn(_('check out a git branch if you intend '
1459 self.ui.warn(_('check out a git branch if you intend '
1456 'to make changes\n'))
1460 'to make changes\n'))
1457 checkout(['-q', revision])
1461 checkout(['-q', revision])
1458
1462
1459 if revision not in rev2branch:
1463 if revision not in rev2branch:
1460 rawcheckout()
1464 rawcheckout()
1461 return
1465 return
1462 branches = rev2branch[revision]
1466 branches = rev2branch[revision]
1463 firstlocalbranch = None
1467 firstlocalbranch = None
1464 for b in branches:
1468 for b in branches:
1465 if b == 'refs/heads/master':
1469 if b == 'refs/heads/master':
1466 # master trumps all other branches
1470 # master trumps all other branches
1467 checkout(['refs/heads/master'])
1471 checkout(['refs/heads/master'])
1468 return
1472 return
1469 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1473 if not firstlocalbranch and not b.startswith('refs/remotes/'):
1470 firstlocalbranch = b
1474 firstlocalbranch = b
1471 if firstlocalbranch:
1475 if firstlocalbranch:
1472 checkout([firstlocalbranch])
1476 checkout([firstlocalbranch])
1473 return
1477 return
1474
1478
1475 tracking = self._gittracking(branch2rev.keys())
1479 tracking = self._gittracking(branch2rev.keys())
1476 # choose a remote branch already tracked if possible
1480 # choose a remote branch already tracked if possible
1477 remote = branches[0]
1481 remote = branches[0]
1478 if remote not in tracking:
1482 if remote not in tracking:
1479 for b in branches:
1483 for b in branches:
1480 if b in tracking:
1484 if b in tracking:
1481 remote = b
1485 remote = b
1482 break
1486 break
1483
1487
1484 if remote not in tracking:
1488 if remote not in tracking:
1485 # create a new local tracking branch
1489 # create a new local tracking branch
1486 local = remote.split('/', 3)[3]
1490 local = remote.split('/', 3)[3]
1487 checkout(['-b', local, remote])
1491 checkout(['-b', local, remote])
1488 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1492 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
1489 # When updating to a tracked remote branch,
1493 # When updating to a tracked remote branch,
1490 # if the local tracking branch is downstream of it,
1494 # if the local tracking branch is downstream of it,
1491 # a normal `git pull` would have performed a "fast-forward merge"
1495 # a normal `git pull` would have performed a "fast-forward merge"
1492 # which is equivalent to updating the local branch to the remote.
1496 # which is equivalent to updating the local branch to the remote.
1493 # Since we are only looking at branching at update, we need to
1497 # Since we are only looking at branching at update, we need to
1494 # detect this situation and perform this action lazily.
1498 # detect this situation and perform this action lazily.
1495 if tracking[remote] != self._gitcurrentbranch():
1499 if tracking[remote] != self._gitcurrentbranch():
1496 checkout([tracking[remote]])
1500 checkout([tracking[remote]])
1497 self._gitcommand(['merge', '--ff', remote])
1501 self._gitcommand(['merge', '--ff', remote])
1498 _sanitize(self.ui, self.wvfs, '.git')
1502 _sanitize(self.ui, self.wvfs, '.git')
1499 else:
1503 else:
1500 # a real merge would be required, just checkout the revision
1504 # a real merge would be required, just checkout the revision
1501 rawcheckout()
1505 rawcheckout()
1502
1506
1503 @annotatesubrepoerror
1507 @annotatesubrepoerror
1504 def commit(self, text, user, date):
1508 def commit(self, text, user, date):
1505 if self._gitmissing():
1509 if self._gitmissing():
1506 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1510 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1507 cmd = ['commit', '-a', '-m', text]
1511 cmd = ['commit', '-a', '-m', text]
1508 env = os.environ.copy()
1512 env = os.environ.copy()
1509 if user:
1513 if user:
1510 cmd += ['--author', user]
1514 cmd += ['--author', user]
1511 if date:
1515 if date:
1512 # git's date parser silently ignores when seconds < 1e9
1516 # git's date parser silently ignores when seconds < 1e9
1513 # convert to ISO8601
1517 # convert to ISO8601
1514 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1518 env['GIT_AUTHOR_DATE'] = util.datestr(date,
1515 '%Y-%m-%dT%H:%M:%S %1%2')
1519 '%Y-%m-%dT%H:%M:%S %1%2')
1516 self._gitcommand(cmd, env=env)
1520 self._gitcommand(cmd, env=env)
1517 # make sure commit works otherwise HEAD might not exist under certain
1521 # make sure commit works otherwise HEAD might not exist under certain
1518 # circumstances
1522 # circumstances
1519 return self._gitstate()
1523 return self._gitstate()
1520
1524
1521 @annotatesubrepoerror
1525 @annotatesubrepoerror
1522 def merge(self, state):
1526 def merge(self, state):
1523 source, revision, kind = state
1527 source, revision, kind = state
1524 self._fetch(source, revision)
1528 self._fetch(source, revision)
1525 base = self._gitcommand(['merge-base', revision, self._state[1]])
1529 base = self._gitcommand(['merge-base', revision, self._state[1]])
1526 self._gitupdatestat()
1530 self._gitupdatestat()
1527 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1531 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
1528
1532
1529 def mergefunc():
1533 def mergefunc():
1530 if base == revision:
1534 if base == revision:
1531 self.get(state) # fast forward merge
1535 self.get(state) # fast forward merge
1532 elif base != self._state[1]:
1536 elif base != self._state[1]:
1533 self._gitcommand(['merge', '--no-commit', revision])
1537 self._gitcommand(['merge', '--no-commit', revision])
1534 _sanitize(self.ui, self.wvfs, '.git')
1538 _sanitize(self.ui, self.wvfs, '.git')
1535
1539
1536 if self.dirty():
1540 if self.dirty():
1537 if self._gitstate() != revision:
1541 if self._gitstate() != revision:
1538 dirty = self._gitstate() == self._state[1] or code != 0
1542 dirty = self._gitstate() == self._state[1] or code != 0
1539 if _updateprompt(self.ui, self, dirty,
1543 if _updateprompt(self.ui, self, dirty,
1540 self._state[1][:7], revision[:7]):
1544 self._state[1][:7], revision[:7]):
1541 mergefunc()
1545 mergefunc()
1542 else:
1546 else:
1543 mergefunc()
1547 mergefunc()
1544
1548
1545 @annotatesubrepoerror
1549 @annotatesubrepoerror
1546 def push(self, opts):
1550 def push(self, opts):
1547 force = opts.get('force')
1551 force = opts.get('force')
1548
1552
1549 if not self._state[1]:
1553 if not self._state[1]:
1550 return True
1554 return True
1551 if self._gitmissing():
1555 if self._gitmissing():
1552 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1556 raise util.Abort(_("subrepo %s is missing") % self._relpath)
1553 # if a branch in origin contains the revision, nothing to do
1557 # if a branch in origin contains the revision, nothing to do
1554 branch2rev, rev2branch = self._gitbranchmap()
1558 branch2rev, rev2branch = self._gitbranchmap()
1555 if self._state[1] in rev2branch:
1559 if self._state[1] in rev2branch:
1556 for b in rev2branch[self._state[1]]:
1560 for b in rev2branch[self._state[1]]:
1557 if b.startswith('refs/remotes/origin/'):
1561 if b.startswith('refs/remotes/origin/'):
1558 return True
1562 return True
1559 for b, revision in branch2rev.iteritems():
1563 for b, revision in branch2rev.iteritems():
1560 if b.startswith('refs/remotes/origin/'):
1564 if b.startswith('refs/remotes/origin/'):
1561 if self._gitisancestor(self._state[1], revision):
1565 if self._gitisancestor(self._state[1], revision):
1562 return True
1566 return True
1563 # otherwise, try to push the currently checked out branch
1567 # otherwise, try to push the currently checked out branch
1564 cmd = ['push']
1568 cmd = ['push']
1565 if force:
1569 if force:
1566 cmd.append('--force')
1570 cmd.append('--force')
1567
1571
1568 current = self._gitcurrentbranch()
1572 current = self._gitcurrentbranch()
1569 if current:
1573 if current:
1570 # determine if the current branch is even useful
1574 # determine if the current branch is even useful
1571 if not self._gitisancestor(self._state[1], current):
1575 if not self._gitisancestor(self._state[1], current):
1572 self.ui.warn(_('unrelated git branch checked out '
1576 self.ui.warn(_('unrelated git branch checked out '
1573 'in subrepo %s\n') % self._relpath)
1577 'in subrepo %s\n') % self._relpath)
1574 return False
1578 return False
1575 self.ui.status(_('pushing branch %s of subrepo %s\n') %
1579 self.ui.status(_('pushing branch %s of subrepo %s\n') %
1576 (current.split('/', 2)[2], self._relpath))
1580 (current.split('/', 2)[2], self._relpath))
1577 ret = self._gitdir(cmd + ['origin', current])
1581 ret = self._gitdir(cmd + ['origin', current])
1578 return ret[1] == 0
1582 return ret[1] == 0
1579 else:
1583 else:
1580 self.ui.warn(_('no branch checked out in subrepo %s\n'
1584 self.ui.warn(_('no branch checked out in subrepo %s\n'
1581 'cannot push revision %s\n') %
1585 'cannot push revision %s\n') %
1582 (self._relpath, self._state[1]))
1586 (self._relpath, self._state[1]))
1583 return False
1587 return False
1584
1588
1585 @annotatesubrepoerror
1589 @annotatesubrepoerror
1586 def add(self, ui, match, prefix, explicitonly, **opts):
1590 def add(self, ui, match, prefix, explicitonly, **opts):
1587 if self._gitmissing():
1591 if self._gitmissing():
1588 return []
1592 return []
1589
1593
1590 (modified, added, removed,
1594 (modified, added, removed,
1591 deleted, unknown, ignored, clean) = self.status(None, unknown=True,
1595 deleted, unknown, ignored, clean) = self.status(None, unknown=True,
1592 clean=True)
1596 clean=True)
1593
1597
1594 tracked = set()
1598 tracked = set()
1595 # dirstates 'amn' warn, 'r' is added again
1599 # dirstates 'amn' warn, 'r' is added again
1596 for l in (modified, added, deleted, clean):
1600 for l in (modified, added, deleted, clean):
1597 tracked.update(l)
1601 tracked.update(l)
1598
1602
1599 # Unknown files not of interest will be rejected by the matcher
1603 # Unknown files not of interest will be rejected by the matcher
1600 files = unknown
1604 files = unknown
1601 files.extend(match.files())
1605 files.extend(match.files())
1602
1606
1603 rejected = []
1607 rejected = []
1604
1608
1605 files = [f for f in sorted(set(files)) if match(f)]
1609 files = [f for f in sorted(set(files)) if match(f)]
1606 for f in files:
1610 for f in files:
1607 exact = match.exact(f)
1611 exact = match.exact(f)
1608 command = ["add"]
1612 command = ["add"]
1609 if exact:
1613 if exact:
1610 command.append("-f") #should be added, even if ignored
1614 command.append("-f") #should be added, even if ignored
1611 if ui.verbose or not exact:
1615 if ui.verbose or not exact:
1612 ui.status(_('adding %s\n') % match.rel(f))
1616 ui.status(_('adding %s\n') % match.rel(f))
1613
1617
1614 if f in tracked: # hg prints 'adding' even if already tracked
1618 if f in tracked: # hg prints 'adding' even if already tracked
1615 if exact:
1619 if exact:
1616 rejected.append(f)
1620 rejected.append(f)
1617 continue
1621 continue
1618 if not opts.get('dry_run'):
1622 if not opts.get('dry_run'):
1619 self._gitcommand(command + [f])
1623 self._gitcommand(command + [f])
1620
1624
1621 for f in rejected:
1625 for f in rejected:
1622 ui.warn(_("%s already tracked!\n") % match.abs(f))
1626 ui.warn(_("%s already tracked!\n") % match.abs(f))
1623
1627
1624 return rejected
1628 return rejected
1625
1629
1626 @annotatesubrepoerror
1630 @annotatesubrepoerror
1627 def remove(self):
1631 def remove(self):
1628 if self._gitmissing():
1632 if self._gitmissing():
1629 return
1633 return
1630 if self.dirty():
1634 if self.dirty():
1631 self.ui.warn(_('not removing repo %s because '
1635 self.ui.warn(_('not removing repo %s because '
1632 'it has changes.\n') % self._relpath)
1636 'it has changes.\n') % self._relpath)
1633 return
1637 return
1634 # we can't fully delete the repository as it may contain
1638 # we can't fully delete the repository as it may contain
1635 # local-only history
1639 # local-only history
1636 self.ui.note(_('removing subrepo %s\n') % self._relpath)
1640 self.ui.note(_('removing subrepo %s\n') % self._relpath)
1637 self._gitcommand(['config', 'core.bare', 'true'])
1641 self._gitcommand(['config', 'core.bare', 'true'])
1638 for f, kind in self.wvfs.readdir():
1642 for f, kind in self.wvfs.readdir():
1639 if f == '.git':
1643 if f == '.git':
1640 continue
1644 continue
1641 if kind == stat.S_IFDIR:
1645 if kind == stat.S_IFDIR:
1642 self.wvfs.rmtree(f)
1646 self.wvfs.rmtree(f)
1643 else:
1647 else:
1644 self.wvfs.unlink(f)
1648 self.wvfs.unlink(f)
1645
1649
1646 def archive(self, archiver, prefix, match=None):
1650 def archive(self, archiver, prefix, match=None):
1647 total = 0
1651 total = 0
1648 source, revision = self._state
1652 source, revision = self._state
1649 if not revision:
1653 if not revision:
1650 return total
1654 return total
1651 self._fetch(source, revision)
1655 self._fetch(source, revision)
1652
1656
1653 # Parse git's native archive command.
1657 # Parse git's native archive command.
1654 # This should be much faster than manually traversing the trees
1658 # This should be much faster than manually traversing the trees
1655 # and objects with many subprocess calls.
1659 # and objects with many subprocess calls.
1656 tarstream = self._gitcommand(['archive', revision], stream=True)
1660 tarstream = self._gitcommand(['archive', revision], stream=True)
1657 tar = tarfile.open(fileobj=tarstream, mode='r|')
1661 tar = tarfile.open(fileobj=tarstream, mode='r|')
1658 relpath = subrelpath(self)
1662 relpath = subrelpath(self)
1659 self.ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1663 self.ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
1660 for i, info in enumerate(tar):
1664 for i, info in enumerate(tar):
1661 if info.isdir():
1665 if info.isdir():
1662 continue
1666 continue
1663 if match and not match(info.name):
1667 if match and not match(info.name):
1664 continue
1668 continue
1665 if info.issym():
1669 if info.issym():
1666 data = info.linkname
1670 data = info.linkname
1667 else:
1671 else:
1668 data = tar.extractfile(info).read()
1672 data = tar.extractfile(info).read()
1669 archiver.addfile(self.wvfs.reljoin(prefix, self._path, info.name),
1673 archiver.addfile(self.wvfs.reljoin(prefix, self._path, info.name),
1670 info.mode, info.issym(), data)
1674 info.mode, info.issym(), data)
1671 total += 1
1675 total += 1
1672 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
1676 self.ui.progress(_('archiving (%s)') % relpath, i + 1,
1673 unit=_('files'))
1677 unit=_('files'))
1674 self.ui.progress(_('archiving (%s)') % relpath, None)
1678 self.ui.progress(_('archiving (%s)') % relpath, None)
1675 return total
1679 return total
1676
1680
1677
1681
1678 @annotatesubrepoerror
1682 @annotatesubrepoerror
1679 def cat(self, match, prefix, **opts):
1683 def cat(self, match, prefix, **opts):
1680 rev = self._state[1]
1684 rev = self._state[1]
1681 if match.anypats():
1685 if match.anypats():
1682 return 1 #No support for include/exclude yet
1686 return 1 #No support for include/exclude yet
1683
1687
1684 if not match.files():
1688 if not match.files():
1685 return 1
1689 return 1
1686
1690
1687 for f in match.files():
1691 for f in match.files():
1688 output = self._gitcommand(["show", "%s:%s" % (rev, f)])
1692 output = self._gitcommand(["show", "%s:%s" % (rev, f)])
1689 fp = cmdutil.makefileobj(self._subparent, opts.get('output'),
1693 fp = cmdutil.makefileobj(self._subparent, opts.get('output'),
1690 self._ctx.node(),
1694 self._ctx.node(),
1691 pathname=self.wvfs.reljoin(prefix, f))
1695 pathname=self.wvfs.reljoin(prefix, f))
1692 fp.write(output)
1696 fp.write(output)
1693 fp.close()
1697 fp.close()
1694 return 0
1698 return 0
1695
1699
1696
1700
1697 @annotatesubrepoerror
1701 @annotatesubrepoerror
1698 def status(self, rev2, **opts):
1702 def status(self, rev2, **opts):
1699 rev1 = self._state[1]
1703 rev1 = self._state[1]
1700 if self._gitmissing() or not rev1:
1704 if self._gitmissing() or not rev1:
1701 # if the repo is missing, return no results
1705 # if the repo is missing, return no results
1702 return scmutil.status([], [], [], [], [], [], [])
1706 return scmutil.status([], [], [], [], [], [], [])
1703 modified, added, removed = [], [], []
1707 modified, added, removed = [], [], []
1704 self._gitupdatestat()
1708 self._gitupdatestat()
1705 if rev2:
1709 if rev2:
1706 command = ['diff-tree', rev1, rev2]
1710 command = ['diff-tree', rev1, rev2]
1707 else:
1711 else:
1708 command = ['diff-index', rev1]
1712 command = ['diff-index', rev1]
1709 out = self._gitcommand(command)
1713 out = self._gitcommand(command)
1710 for line in out.split('\n'):
1714 for line in out.split('\n'):
1711 tab = line.find('\t')
1715 tab = line.find('\t')
1712 if tab == -1:
1716 if tab == -1:
1713 continue
1717 continue
1714 status, f = line[tab - 1], line[tab + 1:]
1718 status, f = line[tab - 1], line[tab + 1:]
1715 if status == 'M':
1719 if status == 'M':
1716 modified.append(f)
1720 modified.append(f)
1717 elif status == 'A':
1721 elif status == 'A':
1718 added.append(f)
1722 added.append(f)
1719 elif status == 'D':
1723 elif status == 'D':
1720 removed.append(f)
1724 removed.append(f)
1721
1725
1722 deleted, unknown, ignored, clean = [], [], [], []
1726 deleted, unknown, ignored, clean = [], [], [], []
1723
1727
1724 command = ['status', '--porcelain', '-z']
1728 command = ['status', '--porcelain', '-z']
1725 if opts.get('unknown'):
1729 if opts.get('unknown'):
1726 command += ['--untracked-files=all']
1730 command += ['--untracked-files=all']
1727 if opts.get('ignored'):
1731 if opts.get('ignored'):
1728 command += ['--ignored']
1732 command += ['--ignored']
1729 out = self._gitcommand(command)
1733 out = self._gitcommand(command)
1730
1734
1731 changedfiles = set()
1735 changedfiles = set()
1732 changedfiles.update(modified)
1736 changedfiles.update(modified)
1733 changedfiles.update(added)
1737 changedfiles.update(added)
1734 changedfiles.update(removed)
1738 changedfiles.update(removed)
1735 for line in out.split('\0'):
1739 for line in out.split('\0'):
1736 if not line:
1740 if not line:
1737 continue
1741 continue
1738 st = line[0:2]
1742 st = line[0:2]
1739 #moves and copies show 2 files on one line
1743 #moves and copies show 2 files on one line
1740 if line.find('\0') >= 0:
1744 if line.find('\0') >= 0:
1741 filename1, filename2 = line[3:].split('\0')
1745 filename1, filename2 = line[3:].split('\0')
1742 else:
1746 else:
1743 filename1 = line[3:]
1747 filename1 = line[3:]
1744 filename2 = None
1748 filename2 = None
1745
1749
1746 changedfiles.add(filename1)
1750 changedfiles.add(filename1)
1747 if filename2:
1751 if filename2:
1748 changedfiles.add(filename2)
1752 changedfiles.add(filename2)
1749
1753
1750 if st == '??':
1754 if st == '??':
1751 unknown.append(filename1)
1755 unknown.append(filename1)
1752 elif st == '!!':
1756 elif st == '!!':
1753 ignored.append(filename1)
1757 ignored.append(filename1)
1754
1758
1755 if opts.get('clean'):
1759 if opts.get('clean'):
1756 out = self._gitcommand(['ls-files'])
1760 out = self._gitcommand(['ls-files'])
1757 for f in out.split('\n'):
1761 for f in out.split('\n'):
1758 if not f in changedfiles:
1762 if not f in changedfiles:
1759 clean.append(f)
1763 clean.append(f)
1760
1764
1761 return scmutil.status(modified, added, removed, deleted,
1765 return scmutil.status(modified, added, removed, deleted,
1762 unknown, ignored, clean)
1766 unknown, ignored, clean)
1763
1767
1764 @annotatesubrepoerror
1768 @annotatesubrepoerror
1765 def diff(self, ui, diffopts, node2, match, prefix, **opts):
1769 def diff(self, ui, diffopts, node2, match, prefix, **opts):
1766 node1 = self._state[1]
1770 node1 = self._state[1]
1767 cmd = ['diff']
1771 cmd = ['diff']
1768 if opts['stat']:
1772 if opts['stat']:
1769 cmd.append('--stat')
1773 cmd.append('--stat')
1770 else:
1774 else:
1771 # for Git, this also implies '-p'
1775 # for Git, this also implies '-p'
1772 cmd.append('-U%d' % diffopts.context)
1776 cmd.append('-U%d' % diffopts.context)
1773
1777
1774 gitprefix = self.wvfs.reljoin(prefix, self._path)
1778 gitprefix = self.wvfs.reljoin(prefix, self._path)
1775
1779
1776 if diffopts.noprefix:
1780 if diffopts.noprefix:
1777 cmd.extend(['--src-prefix=%s/' % gitprefix,
1781 cmd.extend(['--src-prefix=%s/' % gitprefix,
1778 '--dst-prefix=%s/' % gitprefix])
1782 '--dst-prefix=%s/' % gitprefix])
1779 else:
1783 else:
1780 cmd.extend(['--src-prefix=a/%s/' % gitprefix,
1784 cmd.extend(['--src-prefix=a/%s/' % gitprefix,
1781 '--dst-prefix=b/%s/' % gitprefix])
1785 '--dst-prefix=b/%s/' % gitprefix])
1782
1786
1783 if diffopts.ignorews:
1787 if diffopts.ignorews:
1784 cmd.append('--ignore-all-space')
1788 cmd.append('--ignore-all-space')
1785 if diffopts.ignorewsamount:
1789 if diffopts.ignorewsamount:
1786 cmd.append('--ignore-space-change')
1790 cmd.append('--ignore-space-change')
1787 if self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4) \
1791 if self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4) \
1788 and diffopts.ignoreblanklines:
1792 and diffopts.ignoreblanklines:
1789 cmd.append('--ignore-blank-lines')
1793 cmd.append('--ignore-blank-lines')
1790
1794
1791 cmd.append(node1)
1795 cmd.append(node1)
1792 if node2:
1796 if node2:
1793 cmd.append(node2)
1797 cmd.append(node2)
1794
1798
1795 output = ""
1799 output = ""
1796 if match.always():
1800 if match.always():
1797 output += self._gitcommand(cmd) + '\n'
1801 output += self._gitcommand(cmd) + '\n'
1798 else:
1802 else:
1799 st = self.status(node2)[:3]
1803 st = self.status(node2)[:3]
1800 files = [f for sublist in st for f in sublist]
1804 files = [f for sublist in st for f in sublist]
1801 for f in files:
1805 for f in files:
1802 if match(f):
1806 if match(f):
1803 output += self._gitcommand(cmd + ['--', f]) + '\n'
1807 output += self._gitcommand(cmd + ['--', f]) + '\n'
1804
1808
1805 if output.strip():
1809 if output.strip():
1806 ui.write(output)
1810 ui.write(output)
1807
1811
1808 @annotatesubrepoerror
1812 @annotatesubrepoerror
1809 def revert(self, substate, *pats, **opts):
1813 def revert(self, substate, *pats, **opts):
1810 self.ui.status(_('reverting subrepo %s\n') % substate[0])
1814 self.ui.status(_('reverting subrepo %s\n') % substate[0])
1811 if not opts.get('no_backup'):
1815 if not opts.get('no_backup'):
1812 status = self.status(None)
1816 status = self.status(None)
1813 names = status.modified
1817 names = status.modified
1814 for name in names:
1818 for name in names:
1815 bakname = "%s.orig" % name
1819 bakname = "%s.orig" % name
1816 self.ui.note(_('saving current version of %s as %s\n') %
1820 self.ui.note(_('saving current version of %s as %s\n') %
1817 (name, bakname))
1821 (name, bakname))
1818 self.wvfs.rename(name, bakname)
1822 self.wvfs.rename(name, bakname)
1819
1823
1820 if not opts.get('dry_run'):
1824 if not opts.get('dry_run'):
1821 self.get(substate, overwrite=True)
1825 self.get(substate, overwrite=True)
1822 return []
1826 return []
1823
1827
1824 def shortid(self, revid):
1828 def shortid(self, revid):
1825 return revid[:7]
1829 return revid[:7]
1826
1830
1827 types = {
1831 types = {
1828 'hg': hgsubrepo,
1832 'hg': hgsubrepo,
1829 'svn': svnsubrepo,
1833 'svn': svnsubrepo,
1830 'git': gitsubrepo,
1834 'git': gitsubrepo,
1831 }
1835 }
@@ -1,1677 +1,1695 b''
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
1 Let commit recurse into subrepos by default to match pre-2.0 behavior:
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
4 $ echo "commitsubrepos = Yes" >> $HGRCPATH
5
5
6 $ hg init t
6 $ hg init t
7 $ cd t
7 $ cd t
8
8
9 first revision, no sub
9 first revision, no sub
10
10
11 $ echo a > a
11 $ echo a > a
12 $ hg ci -Am0
12 $ hg ci -Am0
13 adding a
13 adding a
14
14
15 add first sub
15 add first sub
16
16
17 $ echo s = s > .hgsub
17 $ echo s = s > .hgsub
18 $ hg add .hgsub
18 $ hg add .hgsub
19 $ hg init s
19 $ hg init s
20 $ echo a > s/a
20 $ echo a > s/a
21
21
22 Issue2232: committing a subrepo without .hgsub
22 Issue2232: committing a subrepo without .hgsub
23
23
24 $ hg ci -mbad s
24 $ hg ci -mbad s
25 abort: can't commit subrepos without .hgsub
25 abort: can't commit subrepos without .hgsub
26 [255]
26 [255]
27
27
28 $ hg -R s add s/a
28 $ hg -R s add s/a
29 $ hg files -S
29 $ hg files -S
30 .hgsub
30 .hgsub
31 a
31 a
32 s/a (glob)
32 s/a (glob)
33
33
34 $ hg -R s ci -Ams0
34 $ hg -R s ci -Ams0
35 $ hg sum
35 $ hg sum
36 parent: 0:f7b1eb17ad24 tip
36 parent: 0:f7b1eb17ad24 tip
37 0
37 0
38 branch: default
38 branch: default
39 commit: 1 added, 1 subrepos
39 commit: 1 added, 1 subrepos
40 update: (current)
40 update: (current)
41 $ hg ci -m1
41 $ hg ci -m1
42
42
43 test handling .hgsubstate "added" explicitly.
43 test handling .hgsubstate "added" explicitly.
44
44
45 $ hg parents --template '{node}\n{files}\n'
45 $ hg parents --template '{node}\n{files}\n'
46 7cf8cfea66e410e8e3336508dfeec07b3192de51
46 7cf8cfea66e410e8e3336508dfeec07b3192de51
47 .hgsub .hgsubstate
47 .hgsub .hgsubstate
48 $ hg rollback -q
48 $ hg rollback -q
49 $ hg add .hgsubstate
49 $ hg add .hgsubstate
50 $ hg ci -m1
50 $ hg ci -m1
51 $ hg parents --template '{node}\n{files}\n'
51 $ hg parents --template '{node}\n{files}\n'
52 7cf8cfea66e410e8e3336508dfeec07b3192de51
52 7cf8cfea66e410e8e3336508dfeec07b3192de51
53 .hgsub .hgsubstate
53 .hgsub .hgsubstate
54
54
55 Revert subrepo and test subrepo fileset keyword:
55 Revert subrepo and test subrepo fileset keyword:
56
56
57 $ echo b > s/a
57 $ echo b > s/a
58 $ hg revert --dry-run "set:subrepo('glob:s*')"
58 $ hg revert --dry-run "set:subrepo('glob:s*')"
59 reverting subrepo s
59 reverting subrepo s
60 reverting s/a (glob)
60 reverting s/a (glob)
61 $ cat s/a
61 $ cat s/a
62 b
62 b
63 $ hg revert "set:subrepo('glob:s*')"
63 $ hg revert "set:subrepo('glob:s*')"
64 reverting subrepo s
64 reverting subrepo s
65 reverting s/a (glob)
65 reverting s/a (glob)
66 $ cat s/a
66 $ cat s/a
67 a
67 a
68 $ rm s/a.orig
68 $ rm s/a.orig
69
69
70 Revert subrepo with no backup. The "reverting s/a" line is gone since
70 Revert subrepo with no backup. The "reverting s/a" line is gone since
71 we're really running 'hg update' in the subrepo:
71 we're really running 'hg update' in the subrepo:
72
72
73 $ echo b > s/a
73 $ echo b > s/a
74 $ hg revert --no-backup s
74 $ hg revert --no-backup s
75 reverting subrepo s
75 reverting subrepo s
76
76
77 Issue2022: update -C
77 Issue2022: update -C
78
78
79 $ echo b > s/a
79 $ echo b > s/a
80 $ hg sum
80 $ hg sum
81 parent: 1:7cf8cfea66e4 tip
81 parent: 1:7cf8cfea66e4 tip
82 1
82 1
83 branch: default
83 branch: default
84 commit: 1 subrepos
84 commit: 1 subrepos
85 update: (current)
85 update: (current)
86 $ hg co -C 1
86 $ hg co -C 1
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 $ hg sum
88 $ hg sum
89 parent: 1:7cf8cfea66e4 tip
89 parent: 1:7cf8cfea66e4 tip
90 1
90 1
91 branch: default
91 branch: default
92 commit: (clean)
92 commit: (clean)
93 update: (current)
93 update: (current)
94
94
95 commands that require a clean repo should respect subrepos
95 commands that require a clean repo should respect subrepos
96
96
97 $ echo b >> s/a
97 $ echo b >> s/a
98 $ hg backout tip
98 $ hg backout tip
99 abort: uncommitted changes in subrepository 's'
99 abort: uncommitted changes in subrepository 's'
100 [255]
100 [255]
101 $ hg revert -C -R s s/a
101 $ hg revert -C -R s s/a
102
102
103 add sub sub
103 add sub sub
104
104
105 $ echo ss = ss > s/.hgsub
105 $ echo ss = ss > s/.hgsub
106 $ hg init s/ss
106 $ hg init s/ss
107 $ echo a > s/ss/a
107 $ echo a > s/ss/a
108 $ hg -R s add s/.hgsub
108 $ hg -R s add s/.hgsub
109 $ hg -R s/ss add s/ss/a
109 $ hg -R s/ss add s/ss/a
110 $ hg sum
110 $ hg sum
111 parent: 1:7cf8cfea66e4 tip
111 parent: 1:7cf8cfea66e4 tip
112 1
112 1
113 branch: default
113 branch: default
114 commit: 1 subrepos
114 commit: 1 subrepos
115 update: (current)
115 update: (current)
116 $ hg ci -m2
116 $ hg ci -m2
117 committing subrepository s
117 committing subrepository s
118 committing subrepository s/ss (glob)
118 committing subrepository s/ss (glob)
119 $ hg sum
119 $ hg sum
120 parent: 2:df30734270ae tip
120 parent: 2:df30734270ae tip
121 2
121 2
122 branch: default
122 branch: default
123 commit: (clean)
123 commit: (clean)
124 update: (current)
124 update: (current)
125
125
126 test handling .hgsubstate "modified" explicitly.
126 test handling .hgsubstate "modified" explicitly.
127
127
128 $ hg parents --template '{node}\n{files}\n'
128 $ hg parents --template '{node}\n{files}\n'
129 df30734270ae757feb35e643b7018e818e78a9aa
129 df30734270ae757feb35e643b7018e818e78a9aa
130 .hgsubstate
130 .hgsubstate
131 $ hg rollback -q
131 $ hg rollback -q
132 $ hg status -A .hgsubstate
132 $ hg status -A .hgsubstate
133 M .hgsubstate
133 M .hgsubstate
134 $ hg ci -m2
134 $ hg ci -m2
135 $ hg parents --template '{node}\n{files}\n'
135 $ hg parents --template '{node}\n{files}\n'
136 df30734270ae757feb35e643b7018e818e78a9aa
136 df30734270ae757feb35e643b7018e818e78a9aa
137 .hgsubstate
137 .hgsubstate
138
138
139 bump sub rev (and check it is ignored by ui.commitsubrepos)
139 bump sub rev (and check it is ignored by ui.commitsubrepos)
140
140
141 $ echo b > s/a
141 $ echo b > s/a
142 $ hg -R s ci -ms1
142 $ hg -R s ci -ms1
143 $ hg --config ui.commitsubrepos=no ci -m3
143 $ hg --config ui.commitsubrepos=no ci -m3
144
144
145 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
145 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
146
146
147 $ echo c > s/a
147 $ echo c > s/a
148 $ hg --config ui.commitsubrepos=no ci -m4
148 $ hg --config ui.commitsubrepos=no ci -m4
149 abort: uncommitted changes in subrepository 's'
149 abort: uncommitted changes in subrepository 's'
150 (use --subrepos for recursive commit)
150 (use --subrepos for recursive commit)
151 [255]
151 [255]
152 $ hg id
152 $ hg id
153 f6affe3fbfaa+ tip
153 f6affe3fbfaa+ tip
154 $ hg -R s ci -mc
154 $ hg -R s ci -mc
155 $ hg id
155 $ hg id
156 f6affe3fbfaa+ tip
156 f6affe3fbfaa+ tip
157 $ echo d > s/a
157 $ echo d > s/a
158 $ hg ci -m4
158 $ hg ci -m4
159 committing subrepository s
159 committing subrepository s
160 $ hg tip -R s
160 $ hg tip -R s
161 changeset: 4:02dcf1d70411
161 changeset: 4:02dcf1d70411
162 tag: tip
162 tag: tip
163 user: test
163 user: test
164 date: Thu Jan 01 00:00:00 1970 +0000
164 date: Thu Jan 01 00:00:00 1970 +0000
165 summary: 4
165 summary: 4
166
166
167
167
168 check caching
168 check caching
169
169
170 $ hg co 0
170 $ hg co 0
171 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
171 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
172 $ hg debugsub
172 $ hg debugsub
173
173
174 restore
174 restore
175
175
176 $ hg co
176 $ hg co
177 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
177 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 $ hg debugsub
178 $ hg debugsub
179 path s
179 path s
180 source s
180 source s
181 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
181 revision 02dcf1d704118aee3ee306ccfa1910850d5b05ef
182
182
183 new branch for merge tests
183 new branch for merge tests
184
184
185 $ hg co 1
185 $ hg co 1
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ echo t = t >> .hgsub
187 $ echo t = t >> .hgsub
188 $ hg init t
188 $ hg init t
189 $ echo t > t/t
189 $ echo t > t/t
190 $ hg -R t add t
190 $ hg -R t add t
191 adding t/t (glob)
191 adding t/t (glob)
192
192
193 5
193 5
194
194
195 $ hg ci -m5 # add sub
195 $ hg ci -m5 # add sub
196 committing subrepository t
196 committing subrepository t
197 created new head
197 created new head
198 $ echo t2 > t/t
198 $ echo t2 > t/t
199
199
200 6
200 6
201
201
202 $ hg st -R s
202 $ hg st -R s
203 $ hg ci -m6 # change sub
203 $ hg ci -m6 # change sub
204 committing subrepository t
204 committing subrepository t
205 $ hg debugsub
205 $ hg debugsub
206 path s
206 path s
207 source s
207 source s
208 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
208 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
209 path t
209 path t
210 source t
210 source t
211 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
211 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
212 $ echo t3 > t/t
212 $ echo t3 > t/t
213
213
214 7
214 7
215
215
216 $ hg ci -m7 # change sub again for conflict test
216 $ hg ci -m7 # change sub again for conflict test
217 committing subrepository t
217 committing subrepository t
218 $ hg rm .hgsub
218 $ hg rm .hgsub
219
219
220 8
220 8
221
221
222 $ hg ci -m8 # remove sub
222 $ hg ci -m8 # remove sub
223
223
224 test handling .hgsubstate "removed" explicitly.
224 test handling .hgsubstate "removed" explicitly.
225
225
226 $ hg parents --template '{node}\n{files}\n'
226 $ hg parents --template '{node}\n{files}\n'
227 96615c1dad2dc8e3796d7332c77ce69156f7b78e
227 96615c1dad2dc8e3796d7332c77ce69156f7b78e
228 .hgsub .hgsubstate
228 .hgsub .hgsubstate
229 $ hg rollback -q
229 $ hg rollback -q
230 $ hg remove .hgsubstate
230 $ hg remove .hgsubstate
231 $ hg ci -m8
231 $ hg ci -m8
232 $ hg parents --template '{node}\n{files}\n'
232 $ hg parents --template '{node}\n{files}\n'
233 96615c1dad2dc8e3796d7332c77ce69156f7b78e
233 96615c1dad2dc8e3796d7332c77ce69156f7b78e
234 .hgsub .hgsubstate
234 .hgsub .hgsubstate
235
235
236 merge tests
236 merge tests
237
237
238 $ hg co -C 3
238 $ hg co -C 3
239 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
240 $ hg merge 5 # test adding
240 $ hg merge 5 # test adding
241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
241 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
242 (branch merge, don't forget to commit)
242 (branch merge, don't forget to commit)
243 $ hg debugsub
243 $ hg debugsub
244 path s
244 path s
245 source s
245 source s
246 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
246 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
247 path t
247 path t
248 source t
248 source t
249 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
249 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
250 $ hg ci -m9
250 $ hg ci -m9
251 created new head
251 created new head
252 $ hg merge 6 --debug # test change
252 $ hg merge 6 --debug # test change
253 searching for copies back to rev 2
253 searching for copies back to rev 2
254 resolving manifests
254 resolving manifests
255 branchmerge: True, force: False, partial: False
255 branchmerge: True, force: False, partial: False
256 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
256 ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
257 .hgsubstate: versions differ -> m
257 .hgsubstate: versions differ -> m
258 updating: .hgsubstate 1/1 files (100.00%)
258 updating: .hgsubstate 1/1 files (100.00%)
259 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
259 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
260 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
260 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
261 getting subrepo t
261 getting subrepo t
262 resolving manifests
262 resolving manifests
263 branchmerge: False, force: False, partial: False
263 branchmerge: False, force: False, partial: False
264 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
264 ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
265 t: remote is newer -> g
265 t: remote is newer -> g
266 getting t
266 getting t
267 updating: t 1/1 files (100.00%)
267 updating: t 1/1 files (100.00%)
268 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
268 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
269 (branch merge, don't forget to commit)
269 (branch merge, don't forget to commit)
270 $ hg debugsub
270 $ hg debugsub
271 path s
271 path s
272 source s
272 source s
273 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
273 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
274 path t
274 path t
275 source t
275 source t
276 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
276 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
277 $ echo conflict > t/t
277 $ echo conflict > t/t
278 $ hg ci -m10
278 $ hg ci -m10
279 committing subrepository t
279 committing subrepository t
280 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
280 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
281 searching for copies back to rev 2
281 searching for copies back to rev 2
282 resolving manifests
282 resolving manifests
283 branchmerge: True, force: False, partial: False
283 branchmerge: True, force: False, partial: False
284 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
284 ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
285 .hgsubstate: versions differ -> m
285 .hgsubstate: versions differ -> m
286 updating: .hgsubstate 1/1 files (100.00%)
286 updating: .hgsubstate 1/1 files (100.00%)
287 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
287 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
288 subrepo t: both sides changed
288 subrepo t: both sides changed
289 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
289 subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
290 (M)erge, keep (l)ocal or keep (r)emote? m
290 (M)erge, keep (l)ocal or keep (r)emote? m
291 merging subrepo t
291 merging subrepo t
292 searching for copies back to rev 2
292 searching for copies back to rev 2
293 resolving manifests
293 resolving manifests
294 branchmerge: True, force: False, partial: False
294 branchmerge: True, force: False, partial: False
295 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
295 ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
296 preserving t for resolve of t
296 preserving t for resolve of t
297 t: versions differ -> m
297 t: versions differ -> m
298 updating: t 1/1 files (100.00%)
298 updating: t 1/1 files (100.00%)
299 picked tool 'internal:merge' for t (binary False symlink False)
299 picked tool 'internal:merge' for t (binary False symlink False)
300 merging t
300 merging t
301 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
301 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
302 warning: conflicts during merge.
302 warning: conflicts during merge.
303 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
303 merging t incomplete! (edit conflicts, then use 'hg resolve --mark')
304 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
304 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
305 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
305 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
306 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
306 subrepo t: merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
307 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
307 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 (branch merge, don't forget to commit)
308 (branch merge, don't forget to commit)
309
309
310 should conflict
310 should conflict
311
311
312 $ cat t/t
312 $ cat t/t
313 <<<<<<< local: 20a0db6fbf6c - test: 10
313 <<<<<<< local: 20a0db6fbf6c - test: 10
314 conflict
314 conflict
315 =======
315 =======
316 t3
316 t3
317 >>>>>>> other: 7af322bc1198 - test: 7
317 >>>>>>> other: 7af322bc1198 - test: 7
318
318
319 11: remove subrepo t
319 11: remove subrepo t
320
320
321 $ hg co -C 5
321 $ hg co -C 5
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 $ hg revert -r 4 .hgsub # remove t
323 $ hg revert -r 4 .hgsub # remove t
324 $ hg ci -m11
324 $ hg ci -m11
325 created new head
325 created new head
326 $ hg debugsub
326 $ hg debugsub
327 path s
327 path s
328 source s
328 source s
329 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
329 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
330
330
331 local removed, remote changed, keep changed
331 local removed, remote changed, keep changed
332
332
333 $ hg merge 6
333 $ hg merge 6
334 remote changed subrepository t which local removed
334 remote changed subrepository t which local removed
335 use (c)hanged version or (d)elete? c
335 use (c)hanged version or (d)elete? c
336 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 (branch merge, don't forget to commit)
337 (branch merge, don't forget to commit)
338 BROKEN: should include subrepo t
338 BROKEN: should include subrepo t
339 $ hg debugsub
339 $ hg debugsub
340 path s
340 path s
341 source s
341 source s
342 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
342 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
343 $ cat .hgsubstate
343 $ cat .hgsubstate
344 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
344 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
345 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
345 6747d179aa9a688023c4b0cad32e4c92bb7f34ad t
346 $ hg ci -m 'local removed, remote changed, keep changed'
346 $ hg ci -m 'local removed, remote changed, keep changed'
347 BROKEN: should include subrepo t
347 BROKEN: should include subrepo t
348 $ hg debugsub
348 $ hg debugsub
349 path s
349 path s
350 source s
350 source s
351 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
351 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
352 BROKEN: should include subrepo t
352 BROKEN: should include subrepo t
353 $ cat .hgsubstate
353 $ cat .hgsubstate
354 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
354 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
355 $ cat t/t
355 $ cat t/t
356 t2
356 t2
357
357
358 local removed, remote changed, keep removed
358 local removed, remote changed, keep removed
359
359
360 $ hg co -C 11
360 $ hg co -C 11
361 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
361 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
362 $ hg merge --config ui.interactive=true 6 <<EOF
362 $ hg merge --config ui.interactive=true 6 <<EOF
363 > d
363 > d
364 > EOF
364 > EOF
365 remote changed subrepository t which local removed
365 remote changed subrepository t which local removed
366 use (c)hanged version or (d)elete? d
366 use (c)hanged version or (d)elete? d
367 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 (branch merge, don't forget to commit)
368 (branch merge, don't forget to commit)
369 $ hg debugsub
369 $ hg debugsub
370 path s
370 path s
371 source s
371 source s
372 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
372 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
373 $ cat .hgsubstate
373 $ cat .hgsubstate
374 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
374 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
375 $ hg ci -m 'local removed, remote changed, keep removed'
375 $ hg ci -m 'local removed, remote changed, keep removed'
376 created new head
376 created new head
377 $ hg debugsub
377 $ hg debugsub
378 path s
378 path s
379 source s
379 source s
380 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
380 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
381 $ cat .hgsubstate
381 $ cat .hgsubstate
382 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
382 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
383
383
384 local changed, remote removed, keep changed
384 local changed, remote removed, keep changed
385
385
386 $ hg co -C 6
386 $ hg co -C 6
387 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
387 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
388 $ hg merge 11
388 $ hg merge 11
389 local changed subrepository t which remote removed
389 local changed subrepository t which remote removed
390 use (c)hanged version or (d)elete? c
390 use (c)hanged version or (d)elete? c
391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 (branch merge, don't forget to commit)
392 (branch merge, don't forget to commit)
393 BROKEN: should include subrepo t
393 BROKEN: should include subrepo t
394 $ hg debugsub
394 $ hg debugsub
395 path s
395 path s
396 source s
396 source s
397 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
397 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
398 BROKEN: should include subrepo t
398 BROKEN: should include subrepo t
399 $ cat .hgsubstate
399 $ cat .hgsubstate
400 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
400 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
401 $ hg ci -m 'local changed, remote removed, keep changed'
401 $ hg ci -m 'local changed, remote removed, keep changed'
402 created new head
402 created new head
403 BROKEN: should include subrepo t
403 BROKEN: should include subrepo t
404 $ hg debugsub
404 $ hg debugsub
405 path s
405 path s
406 source s
406 source s
407 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
407 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
408 BROKEN: should include subrepo t
408 BROKEN: should include subrepo t
409 $ cat .hgsubstate
409 $ cat .hgsubstate
410 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
410 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
411 $ cat t/t
411 $ cat t/t
412 t2
412 t2
413
413
414 local changed, remote removed, keep removed
414 local changed, remote removed, keep removed
415
415
416 $ hg co -C 6
416 $ hg co -C 6
417 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
417 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
418 $ hg merge --config ui.interactive=true 11 <<EOF
418 $ hg merge --config ui.interactive=true 11 <<EOF
419 > d
419 > d
420 > EOF
420 > EOF
421 local changed subrepository t which remote removed
421 local changed subrepository t which remote removed
422 use (c)hanged version or (d)elete? d
422 use (c)hanged version or (d)elete? d
423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
424 (branch merge, don't forget to commit)
424 (branch merge, don't forget to commit)
425 $ hg debugsub
425 $ hg debugsub
426 path s
426 path s
427 source s
427 source s
428 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
428 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
429 $ cat .hgsubstate
429 $ cat .hgsubstate
430 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
430 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
431 $ hg ci -m 'local changed, remote removed, keep removed'
431 $ hg ci -m 'local changed, remote removed, keep removed'
432 created new head
432 created new head
433 $ hg debugsub
433 $ hg debugsub
434 path s
434 path s
435 source s
435 source s
436 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
436 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
437 $ cat .hgsubstate
437 $ cat .hgsubstate
438 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
438 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
439
439
440 clean up to avoid having to fix up the tests below
440 clean up to avoid having to fix up the tests below
441
441
442 $ hg co -C 10
442 $ hg co -C 10
443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
443 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
444 $ cat >> $HGRCPATH <<EOF
444 $ cat >> $HGRCPATH <<EOF
445 > [extensions]
445 > [extensions]
446 > strip=
446 > strip=
447 > EOF
447 > EOF
448 $ hg strip -r 11:15
448 $ hg strip -r 11:15
449 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
449 saved backup bundle to $TESTTMP/t/.hg/strip-backup/*-backup.hg (glob)
450
450
451 clone
451 clone
452
452
453 $ cd ..
453 $ cd ..
454 $ hg clone t tc
454 $ hg clone t tc
455 updating to branch default
455 updating to branch default
456 cloning subrepo s from $TESTTMP/t/s
456 cloning subrepo s from $TESTTMP/t/s
457 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
457 cloning subrepo s/ss from $TESTTMP/t/s/ss (glob)
458 cloning subrepo t from $TESTTMP/t/t
458 cloning subrepo t from $TESTTMP/t/t
459 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
459 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
460 $ cd tc
460 $ cd tc
461 $ hg debugsub
461 $ hg debugsub
462 path s
462 path s
463 source s
463 source s
464 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
464 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
465 path t
465 path t
466 source t
466 source t
467 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
467 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
468
468
469 push
469 push
470
470
471 $ echo bah > t/t
471 $ echo bah > t/t
472 $ hg ci -m11
472 $ hg ci -m11
473 committing subrepository t
473 committing subrepository t
474 $ hg push
474 $ hg push
475 pushing to $TESTTMP/t (glob)
475 pushing to $TESTTMP/t (glob)
476 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
476 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
477 no changes made to subrepo s since last push to $TESTTMP/t/s
477 no changes made to subrepo s since last push to $TESTTMP/t/s
478 pushing subrepo t to $TESTTMP/t/t
478 pushing subrepo t to $TESTTMP/t/t
479 searching for changes
479 searching for changes
480 adding changesets
480 adding changesets
481 adding manifests
481 adding manifests
482 adding file changes
482 adding file changes
483 added 1 changesets with 1 changes to 1 files
483 added 1 changesets with 1 changes to 1 files
484 searching for changes
484 searching for changes
485 adding changesets
485 adding changesets
486 adding manifests
486 adding manifests
487 adding file changes
487 adding file changes
488 added 1 changesets with 1 changes to 1 files
488 added 1 changesets with 1 changes to 1 files
489
489
490 push -f
490 push -f
491
491
492 $ echo bah > s/a
492 $ echo bah > s/a
493 $ hg ci -m12
493 $ hg ci -m12
494 committing subrepository s
494 committing subrepository s
495 $ hg push
495 $ hg push
496 pushing to $TESTTMP/t (glob)
496 pushing to $TESTTMP/t (glob)
497 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
497 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
498 pushing subrepo s to $TESTTMP/t/s
498 pushing subrepo s to $TESTTMP/t/s
499 searching for changes
499 searching for changes
500 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
500 abort: push creates new remote head 12a213df6fa9! (in subrepo s)
501 (merge or see "hg help push" for details about pushing new heads)
501 (merge or see "hg help push" for details about pushing new heads)
502 [255]
502 [255]
503 $ hg push -f
503 $ hg push -f
504 pushing to $TESTTMP/t (glob)
504 pushing to $TESTTMP/t (glob)
505 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
505 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
506 searching for changes
506 searching for changes
507 no changes found
507 no changes found
508 pushing subrepo s to $TESTTMP/t/s
508 pushing subrepo s to $TESTTMP/t/s
509 searching for changes
509 searching for changes
510 adding changesets
510 adding changesets
511 adding manifests
511 adding manifests
512 adding file changes
512 adding file changes
513 added 1 changesets with 1 changes to 1 files (+1 heads)
513 added 1 changesets with 1 changes to 1 files (+1 heads)
514 pushing subrepo t to $TESTTMP/t/t
514 pushing subrepo t to $TESTTMP/t/t
515 searching for changes
515 searching for changes
516 no changes found
516 no changes found
517 searching for changes
517 searching for changes
518 adding changesets
518 adding changesets
519 adding manifests
519 adding manifests
520 adding file changes
520 adding file changes
521 added 1 changesets with 1 changes to 1 files
521 added 1 changesets with 1 changes to 1 files
522
522
523 check that unmodified subrepos are not pushed
523 check that unmodified subrepos are not pushed
524
524
525 $ hg clone . ../tcc
525 $ hg clone . ../tcc
526 updating to branch default
526 updating to branch default
527 cloning subrepo s from $TESTTMP/tc/s
527 cloning subrepo s from $TESTTMP/tc/s
528 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
528 cloning subrepo s/ss from $TESTTMP/tc/s/ss (glob)
529 cloning subrepo t from $TESTTMP/tc/t
529 cloning subrepo t from $TESTTMP/tc/t
530 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
531
531
532 the subrepos on the new clone have nothing to push to its source
532 the subrepos on the new clone have nothing to push to its source
533
533
534 $ hg push -R ../tcc .
534 $ hg push -R ../tcc .
535 pushing to .
535 pushing to .
536 no changes made to subrepo s/ss since last push to s/ss (glob)
536 no changes made to subrepo s/ss since last push to s/ss (glob)
537 no changes made to subrepo s since last push to s
537 no changes made to subrepo s since last push to s
538 no changes made to subrepo t since last push to t
538 no changes made to subrepo t since last push to t
539 searching for changes
539 searching for changes
540 no changes found
540 no changes found
541 [1]
541 [1]
542
542
543 the subrepos on the source do not have a clean store versus the clone target
543 the subrepos on the source do not have a clean store versus the clone target
544 because they were never explicitly pushed to the source
544 because they were never explicitly pushed to the source
545
545
546 $ hg push ../tcc
546 $ hg push ../tcc
547 pushing to ../tcc
547 pushing to ../tcc
548 pushing subrepo s/ss to ../tcc/s/ss (glob)
548 pushing subrepo s/ss to ../tcc/s/ss (glob)
549 searching for changes
549 searching for changes
550 no changes found
550 no changes found
551 pushing subrepo s to ../tcc/s
551 pushing subrepo s to ../tcc/s
552 searching for changes
552 searching for changes
553 no changes found
553 no changes found
554 pushing subrepo t to ../tcc/t
554 pushing subrepo t to ../tcc/t
555 searching for changes
555 searching for changes
556 no changes found
556 no changes found
557 searching for changes
557 searching for changes
558 no changes found
558 no changes found
559 [1]
559 [1]
560
560
561 after push their stores become clean
561 after push their stores become clean
562
562
563 $ hg push ../tcc
563 $ hg push ../tcc
564 pushing to ../tcc
564 pushing to ../tcc
565 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
565 no changes made to subrepo s/ss since last push to ../tcc/s/ss (glob)
566 no changes made to subrepo s since last push to ../tcc/s
566 no changes made to subrepo s since last push to ../tcc/s
567 no changes made to subrepo t since last push to ../tcc/t
567 no changes made to subrepo t since last push to ../tcc/t
568 searching for changes
568 searching for changes
569 no changes found
569 no changes found
570 [1]
570 [1]
571
571
572 updating a subrepo to a different revision or changing
572 updating a subrepo to a different revision or changing
573 its working directory does not make its store dirty
573 its working directory does not make its store dirty
574
574
575 $ hg -R s update '.^'
575 $ hg -R s update '.^'
576 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
576 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
577 $ hg push
577 $ hg push
578 pushing to $TESTTMP/t (glob)
578 pushing to $TESTTMP/t (glob)
579 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
579 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
580 no changes made to subrepo s since last push to $TESTTMP/t/s
580 no changes made to subrepo s since last push to $TESTTMP/t/s
581 no changes made to subrepo t since last push to $TESTTMP/t/t
581 no changes made to subrepo t since last push to $TESTTMP/t/t
582 searching for changes
582 searching for changes
583 no changes found
583 no changes found
584 [1]
584 [1]
585 $ echo foo >> s/a
585 $ echo foo >> s/a
586 $ hg push
586 $ hg push
587 pushing to $TESTTMP/t (glob)
587 pushing to $TESTTMP/t (glob)
588 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
588 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
589 no changes made to subrepo s since last push to $TESTTMP/t/s
589 no changes made to subrepo s since last push to $TESTTMP/t/s
590 no changes made to subrepo t since last push to $TESTTMP/t/t
590 no changes made to subrepo t since last push to $TESTTMP/t/t
591 searching for changes
591 searching for changes
592 no changes found
592 no changes found
593 [1]
593 [1]
594 $ hg -R s update -C tip
594 $ hg -R s update -C tip
595 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
595 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
596
596
597 committing into a subrepo makes its store (but not its parent's store) dirty
597 committing into a subrepo makes its store (but not its parent's store) dirty
598
598
599 $ echo foo >> s/ss/a
599 $ echo foo >> s/ss/a
600 $ hg -R s/ss commit -m 'test dirty store detection'
600 $ hg -R s/ss commit -m 'test dirty store detection'
601
601
602 $ hg out -S -r `hg log -r tip -T "{node|short}"`
602 $ hg out -S -r `hg log -r tip -T "{node|short}"`
603 comparing with $TESTTMP/t (glob)
603 comparing with $TESTTMP/t (glob)
604 searching for changes
604 searching for changes
605 no changes found
605 no changes found
606 comparing with $TESTTMP/t/s
606 comparing with $TESTTMP/t/s
607 searching for changes
607 searching for changes
608 no changes found
608 no changes found
609 comparing with $TESTTMP/t/s/ss
609 comparing with $TESTTMP/t/s/ss
610 searching for changes
610 searching for changes
611 changeset: 1:79ea5566a333
611 changeset: 1:79ea5566a333
612 tag: tip
612 tag: tip
613 user: test
613 user: test
614 date: Thu Jan 01 00:00:00 1970 +0000
614 date: Thu Jan 01 00:00:00 1970 +0000
615 summary: test dirty store detection
615 summary: test dirty store detection
616
616
617 comparing with $TESTTMP/t/t
617 comparing with $TESTTMP/t/t
618 searching for changes
618 searching for changes
619 no changes found
619 no changes found
620
620
621 $ hg push
621 $ hg push
622 pushing to $TESTTMP/t (glob)
622 pushing to $TESTTMP/t (glob)
623 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
623 pushing subrepo s/ss to $TESTTMP/t/s/ss (glob)
624 searching for changes
624 searching for changes
625 adding changesets
625 adding changesets
626 adding manifests
626 adding manifests
627 adding file changes
627 adding file changes
628 added 1 changesets with 1 changes to 1 files
628 added 1 changesets with 1 changes to 1 files
629 no changes made to subrepo s since last push to $TESTTMP/t/s
629 no changes made to subrepo s since last push to $TESTTMP/t/s
630 no changes made to subrepo t since last push to $TESTTMP/t/t
630 no changes made to subrepo t since last push to $TESTTMP/t/t
631 searching for changes
631 searching for changes
632 no changes found
632 no changes found
633 [1]
633 [1]
634
634
635 a subrepo store may be clean versus one repo but not versus another
635 a subrepo store may be clean versus one repo but not versus another
636
636
637 $ hg push
637 $ hg push
638 pushing to $TESTTMP/t (glob)
638 pushing to $TESTTMP/t (glob)
639 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
639 no changes made to subrepo s/ss since last push to $TESTTMP/t/s/ss (glob)
640 no changes made to subrepo s since last push to $TESTTMP/t/s
640 no changes made to subrepo s since last push to $TESTTMP/t/s
641 no changes made to subrepo t since last push to $TESTTMP/t/t
641 no changes made to subrepo t since last push to $TESTTMP/t/t
642 searching for changes
642 searching for changes
643 no changes found
643 no changes found
644 [1]
644 [1]
645 $ hg push ../tcc
645 $ hg push ../tcc
646 pushing to ../tcc
646 pushing to ../tcc
647 pushing subrepo s/ss to ../tcc/s/ss (glob)
647 pushing subrepo s/ss to ../tcc/s/ss (glob)
648 searching for changes
648 searching for changes
649 adding changesets
649 adding changesets
650 adding manifests
650 adding manifests
651 adding file changes
651 adding file changes
652 added 1 changesets with 1 changes to 1 files
652 added 1 changesets with 1 changes to 1 files
653 no changes made to subrepo s since last push to ../tcc/s
653 no changes made to subrepo s since last push to ../tcc/s
654 no changes made to subrepo t since last push to ../tcc/t
654 no changes made to subrepo t since last push to ../tcc/t
655 searching for changes
655 searching for changes
656 no changes found
656 no changes found
657 [1]
657 [1]
658
658
659 update
659 update
660
660
661 $ cd ../t
661 $ cd ../t
662 $ hg up -C # discard our earlier merge
662 $ hg up -C # discard our earlier merge
663 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
663 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
664 $ echo blah > t/t
664 $ echo blah > t/t
665 $ hg ci -m13
665 $ hg ci -m13
666 committing subrepository t
666 committing subrepository t
667
667
668 backout calls revert internally with minimal opts, which should not raise
668 backout calls revert internally with minimal opts, which should not raise
669 KeyError
669 KeyError
670
670
671 $ hg backout ".^"
671 $ hg backout ".^"
672 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
672 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
673 changeset c373c8102e68 backed out, don't forget to commit.
673 changeset c373c8102e68 backed out, don't forget to commit.
674
674
675 $ hg up -C # discard changes
675 $ hg up -C # discard changes
676 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
676 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
677
677
678 pull
678 pull
679
679
680 $ cd ../tc
680 $ cd ../tc
681 $ hg pull
681 $ hg pull
682 pulling from $TESTTMP/t (glob)
682 pulling from $TESTTMP/t (glob)
683 searching for changes
683 searching for changes
684 adding changesets
684 adding changesets
685 adding manifests
685 adding manifests
686 adding file changes
686 adding file changes
687 added 1 changesets with 1 changes to 1 files
687 added 1 changesets with 1 changes to 1 files
688 (run 'hg update' to get a working copy)
688 (run 'hg update' to get a working copy)
689
689
690 should pull t
690 should pull t
691
691
692 $ hg incoming -S -r `hg log -r tip -T "{node|short}"`
693 comparing with $TESTTMP/t (glob)
694 no changes found
695 comparing with $TESTTMP/t/s
696 searching for changes
697 no changes found
698 comparing with $TESTTMP/t/s/ss
699 searching for changes
700 no changes found
701 comparing with $TESTTMP/t/t
702 searching for changes
703 changeset: 5:52c0adc0515a
704 tag: tip
705 user: test
706 date: Thu Jan 01 00:00:00 1970 +0000
707 summary: 13
708
709
692 $ hg up
710 $ hg up
693 pulling subrepo t from $TESTTMP/t/t
711 pulling subrepo t from $TESTTMP/t/t
694 searching for changes
712 searching for changes
695 adding changesets
713 adding changesets
696 adding manifests
714 adding manifests
697 adding file changes
715 adding file changes
698 added 1 changesets with 1 changes to 1 files
716 added 1 changesets with 1 changes to 1 files
699 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
717 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
700 $ cat t/t
718 $ cat t/t
701 blah
719 blah
702
720
703 bogus subrepo path aborts
721 bogus subrepo path aborts
704
722
705 $ echo 'bogus=[boguspath' >> .hgsub
723 $ echo 'bogus=[boguspath' >> .hgsub
706 $ hg ci -m 'bogus subrepo path'
724 $ hg ci -m 'bogus subrepo path'
707 abort: missing ] in subrepo source
725 abort: missing ] in subrepo source
708 [255]
726 [255]
709
727
710 Issue1986: merge aborts when trying to merge a subrepo that
728 Issue1986: merge aborts when trying to merge a subrepo that
711 shouldn't need merging
729 shouldn't need merging
712
730
713 # subrepo layout
731 # subrepo layout
714 #
732 #
715 # o 5 br
733 # o 5 br
716 # /|
734 # /|
717 # o | 4 default
735 # o | 4 default
718 # | |
736 # | |
719 # | o 3 br
737 # | o 3 br
720 # |/|
738 # |/|
721 # o | 2 default
739 # o | 2 default
722 # | |
740 # | |
723 # | o 1 br
741 # | o 1 br
724 # |/
742 # |/
725 # o 0 default
743 # o 0 default
726
744
727 $ cd ..
745 $ cd ..
728 $ rm -rf sub
746 $ rm -rf sub
729 $ hg init main
747 $ hg init main
730 $ cd main
748 $ cd main
731 $ hg init s
749 $ hg init s
732 $ cd s
750 $ cd s
733 $ echo a > a
751 $ echo a > a
734 $ hg ci -Am1
752 $ hg ci -Am1
735 adding a
753 adding a
736 $ hg branch br
754 $ hg branch br
737 marked working directory as branch br
755 marked working directory as branch br
738 (branches are permanent and global, did you want a bookmark?)
756 (branches are permanent and global, did you want a bookmark?)
739 $ echo a >> a
757 $ echo a >> a
740 $ hg ci -m1
758 $ hg ci -m1
741 $ hg up default
759 $ hg up default
742 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
743 $ echo b > b
761 $ echo b > b
744 $ hg ci -Am1
762 $ hg ci -Am1
745 adding b
763 adding b
746 $ hg up br
764 $ hg up br
747 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
765 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
748 $ hg merge tip
766 $ hg merge tip
749 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
767 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
750 (branch merge, don't forget to commit)
768 (branch merge, don't forget to commit)
751 $ hg ci -m1
769 $ hg ci -m1
752 $ hg up 2
770 $ hg up 2
753 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
771 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
754 $ echo c > c
772 $ echo c > c
755 $ hg ci -Am1
773 $ hg ci -Am1
756 adding c
774 adding c
757 $ hg up 3
775 $ hg up 3
758 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
776 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
759 $ hg merge 4
777 $ hg merge 4
760 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
778 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
761 (branch merge, don't forget to commit)
779 (branch merge, don't forget to commit)
762 $ hg ci -m1
780 $ hg ci -m1
763
781
764 # main repo layout:
782 # main repo layout:
765 #
783 #
766 # * <-- try to merge default into br again
784 # * <-- try to merge default into br again
767 # .`|
785 # .`|
768 # . o 5 br --> substate = 5
786 # . o 5 br --> substate = 5
769 # . |
787 # . |
770 # o | 4 default --> substate = 4
788 # o | 4 default --> substate = 4
771 # | |
789 # | |
772 # | o 3 br --> substate = 2
790 # | o 3 br --> substate = 2
773 # |/|
791 # |/|
774 # o | 2 default --> substate = 2
792 # o | 2 default --> substate = 2
775 # | |
793 # | |
776 # | o 1 br --> substate = 3
794 # | o 1 br --> substate = 3
777 # |/
795 # |/
778 # o 0 default --> substate = 2
796 # o 0 default --> substate = 2
779
797
780 $ cd ..
798 $ cd ..
781 $ echo 's = s' > .hgsub
799 $ echo 's = s' > .hgsub
782 $ hg -R s up 2
800 $ hg -R s up 2
783 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
801 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
784 $ hg ci -Am1
802 $ hg ci -Am1
785 adding .hgsub
803 adding .hgsub
786 $ hg branch br
804 $ hg branch br
787 marked working directory as branch br
805 marked working directory as branch br
788 (branches are permanent and global, did you want a bookmark?)
806 (branches are permanent and global, did you want a bookmark?)
789 $ echo b > b
807 $ echo b > b
790 $ hg -R s up 3
808 $ hg -R s up 3
791 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
809 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
792 $ hg ci -Am1
810 $ hg ci -Am1
793 adding b
811 adding b
794 $ hg up default
812 $ hg up default
795 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
813 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
796 $ echo c > c
814 $ echo c > c
797 $ hg ci -Am1
815 $ hg ci -Am1
798 adding c
816 adding c
799 $ hg up 1
817 $ hg up 1
800 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
818 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
801 $ hg merge 2
819 $ hg merge 2
802 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
820 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
803 (branch merge, don't forget to commit)
821 (branch merge, don't forget to commit)
804 $ hg ci -m1
822 $ hg ci -m1
805 $ hg up 2
823 $ hg up 2
806 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
824 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
807 $ hg -R s up 4
825 $ hg -R s up 4
808 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
826 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
809 $ echo d > d
827 $ echo d > d
810 $ hg ci -Am1
828 $ hg ci -Am1
811 adding d
829 adding d
812 $ hg up 3
830 $ hg up 3
813 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
831 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
814 $ hg -R s up 5
832 $ hg -R s up 5
815 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
833 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
816 $ echo e > e
834 $ echo e > e
817 $ hg ci -Am1
835 $ hg ci -Am1
818 adding e
836 adding e
819
837
820 $ hg up 5
838 $ hg up 5
821 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
839 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
822 $ hg merge 4 # try to merge default into br again
840 $ hg merge 4 # try to merge default into br again
823 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
841 subrepository s diverged (local revision: f8f13b33206e, remote revision: a3f9062a4f88)
824 (M)erge, keep (l)ocal or keep (r)emote? m
842 (M)erge, keep (l)ocal or keep (r)emote? m
825 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
843 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
826 (branch merge, don't forget to commit)
844 (branch merge, don't forget to commit)
827 $ cd ..
845 $ cd ..
828
846
829 test subrepo delete from .hgsubstate
847 test subrepo delete from .hgsubstate
830
848
831 $ hg init testdelete
849 $ hg init testdelete
832 $ mkdir testdelete/nested testdelete/nested2
850 $ mkdir testdelete/nested testdelete/nested2
833 $ hg init testdelete/nested
851 $ hg init testdelete/nested
834 $ hg init testdelete/nested2
852 $ hg init testdelete/nested2
835 $ echo test > testdelete/nested/foo
853 $ echo test > testdelete/nested/foo
836 $ echo test > testdelete/nested2/foo
854 $ echo test > testdelete/nested2/foo
837 $ hg -R testdelete/nested add
855 $ hg -R testdelete/nested add
838 adding testdelete/nested/foo (glob)
856 adding testdelete/nested/foo (glob)
839 $ hg -R testdelete/nested2 add
857 $ hg -R testdelete/nested2 add
840 adding testdelete/nested2/foo (glob)
858 adding testdelete/nested2/foo (glob)
841 $ hg -R testdelete/nested ci -m test
859 $ hg -R testdelete/nested ci -m test
842 $ hg -R testdelete/nested2 ci -m test
860 $ hg -R testdelete/nested2 ci -m test
843 $ echo nested = nested > testdelete/.hgsub
861 $ echo nested = nested > testdelete/.hgsub
844 $ echo nested2 = nested2 >> testdelete/.hgsub
862 $ echo nested2 = nested2 >> testdelete/.hgsub
845 $ hg -R testdelete add
863 $ hg -R testdelete add
846 adding testdelete/.hgsub (glob)
864 adding testdelete/.hgsub (glob)
847 $ hg -R testdelete ci -m "nested 1 & 2 added"
865 $ hg -R testdelete ci -m "nested 1 & 2 added"
848 $ echo nested = nested > testdelete/.hgsub
866 $ echo nested = nested > testdelete/.hgsub
849 $ hg -R testdelete ci -m "nested 2 deleted"
867 $ hg -R testdelete ci -m "nested 2 deleted"
850 $ cat testdelete/.hgsubstate
868 $ cat testdelete/.hgsubstate
851 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
869 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
852 $ hg -R testdelete remove testdelete/.hgsub
870 $ hg -R testdelete remove testdelete/.hgsub
853 $ hg -R testdelete ci -m ".hgsub deleted"
871 $ hg -R testdelete ci -m ".hgsub deleted"
854 $ cat testdelete/.hgsubstate
872 $ cat testdelete/.hgsubstate
855 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
873 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
856
874
857 test repository cloning
875 test repository cloning
858
876
859 $ mkdir mercurial mercurial2
877 $ mkdir mercurial mercurial2
860 $ hg init nested_absolute
878 $ hg init nested_absolute
861 $ echo test > nested_absolute/foo
879 $ echo test > nested_absolute/foo
862 $ hg -R nested_absolute add
880 $ hg -R nested_absolute add
863 adding nested_absolute/foo (glob)
881 adding nested_absolute/foo (glob)
864 $ hg -R nested_absolute ci -mtest
882 $ hg -R nested_absolute ci -mtest
865 $ cd mercurial
883 $ cd mercurial
866 $ hg init nested_relative
884 $ hg init nested_relative
867 $ echo test2 > nested_relative/foo2
885 $ echo test2 > nested_relative/foo2
868 $ hg -R nested_relative add
886 $ hg -R nested_relative add
869 adding nested_relative/foo2 (glob)
887 adding nested_relative/foo2 (glob)
870 $ hg -R nested_relative ci -mtest2
888 $ hg -R nested_relative ci -mtest2
871 $ hg init main
889 $ hg init main
872 $ echo "nested_relative = ../nested_relative" > main/.hgsub
890 $ echo "nested_relative = ../nested_relative" > main/.hgsub
873 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
891 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
874 $ hg -R main add
892 $ hg -R main add
875 adding main/.hgsub (glob)
893 adding main/.hgsub (glob)
876 $ hg -R main ci -m "add subrepos"
894 $ hg -R main ci -m "add subrepos"
877 $ cd ..
895 $ cd ..
878 $ hg clone mercurial/main mercurial2/main
896 $ hg clone mercurial/main mercurial2/main
879 updating to branch default
897 updating to branch default
880 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
898 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
881 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
899 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
882 > mercurial2/main/nested_relative/.hg/hgrc
900 > mercurial2/main/nested_relative/.hg/hgrc
883 [paths]
901 [paths]
884 default = $TESTTMP/mercurial/nested_absolute
902 default = $TESTTMP/mercurial/nested_absolute
885 [paths]
903 [paths]
886 default = $TESTTMP/mercurial/nested_relative
904 default = $TESTTMP/mercurial/nested_relative
887 $ rm -rf mercurial mercurial2
905 $ rm -rf mercurial mercurial2
888
906
889 Issue1977: multirepo push should fail if subrepo push fails
907 Issue1977: multirepo push should fail if subrepo push fails
890
908
891 $ hg init repo
909 $ hg init repo
892 $ hg init repo/s
910 $ hg init repo/s
893 $ echo a > repo/s/a
911 $ echo a > repo/s/a
894 $ hg -R repo/s ci -Am0
912 $ hg -R repo/s ci -Am0
895 adding a
913 adding a
896 $ echo s = s > repo/.hgsub
914 $ echo s = s > repo/.hgsub
897 $ hg -R repo ci -Am1
915 $ hg -R repo ci -Am1
898 adding .hgsub
916 adding .hgsub
899 $ hg clone repo repo2
917 $ hg clone repo repo2
900 updating to branch default
918 updating to branch default
901 cloning subrepo s from $TESTTMP/repo/s
919 cloning subrepo s from $TESTTMP/repo/s
902 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
920 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
903 $ hg -q -R repo2 pull -u
921 $ hg -q -R repo2 pull -u
904 $ echo 1 > repo2/s/a
922 $ echo 1 > repo2/s/a
905 $ hg -R repo2/s ci -m2
923 $ hg -R repo2/s ci -m2
906 $ hg -q -R repo2/s push
924 $ hg -q -R repo2/s push
907 $ hg -R repo2/s up -C 0
925 $ hg -R repo2/s up -C 0
908 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
926 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
909 $ echo 2 > repo2/s/b
927 $ echo 2 > repo2/s/b
910 $ hg -R repo2/s ci -m3 -A
928 $ hg -R repo2/s ci -m3 -A
911 adding b
929 adding b
912 created new head
930 created new head
913 $ hg -R repo2 ci -m3
931 $ hg -R repo2 ci -m3
914 $ hg -q -R repo2 push
932 $ hg -q -R repo2 push
915 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
933 abort: push creates new remote head cc505f09a8b2! (in subrepo s)
916 (merge or see "hg help push" for details about pushing new heads)
934 (merge or see "hg help push" for details about pushing new heads)
917 [255]
935 [255]
918 $ hg -R repo update
936 $ hg -R repo update
919 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
937 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
920
938
921 test if untracked file is not overwritten
939 test if untracked file is not overwritten
922
940
923 $ echo issue3276_ok > repo/s/b
941 $ echo issue3276_ok > repo/s/b
924 $ hg -R repo2 push -f -q
942 $ hg -R repo2 push -f -q
925 $ touch -t 200001010000 repo/.hgsubstate
943 $ touch -t 200001010000 repo/.hgsubstate
926 $ hg -R repo status --config debug.dirstate.delaywrite=2 repo/.hgsubstate
944 $ hg -R repo status --config debug.dirstate.delaywrite=2 repo/.hgsubstate
927 $ hg -R repo update
945 $ hg -R repo update
928 b: untracked file differs
946 b: untracked file differs
929 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
947 abort: untracked files in working directory differ from files in requested revision (in subrepo s)
930 [255]
948 [255]
931
949
932 $ cat repo/s/b
950 $ cat repo/s/b
933 issue3276_ok
951 issue3276_ok
934 $ rm repo/s/b
952 $ rm repo/s/b
935 $ touch -t 200001010000 repo/.hgsubstate
953 $ touch -t 200001010000 repo/.hgsubstate
936 $ hg -R repo revert --all
954 $ hg -R repo revert --all
937 reverting repo/.hgsubstate (glob)
955 reverting repo/.hgsubstate (glob)
938 reverting subrepo s
956 reverting subrepo s
939 $ hg -R repo update
957 $ hg -R repo update
940 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
958 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
941 $ cat repo/s/b
959 $ cat repo/s/b
942 2
960 2
943 $ rm -rf repo2 repo
961 $ rm -rf repo2 repo
944
962
945
963
946 Issue1852 subrepos with relative paths always push/pull relative to default
964 Issue1852 subrepos with relative paths always push/pull relative to default
947
965
948 Prepare a repo with subrepo
966 Prepare a repo with subrepo
949
967
950 $ hg init issue1852a
968 $ hg init issue1852a
951 $ cd issue1852a
969 $ cd issue1852a
952 $ hg init sub/repo
970 $ hg init sub/repo
953 $ echo test > sub/repo/foo
971 $ echo test > sub/repo/foo
954 $ hg -R sub/repo add sub/repo/foo
972 $ hg -R sub/repo add sub/repo/foo
955 $ echo sub/repo = sub/repo > .hgsub
973 $ echo sub/repo = sub/repo > .hgsub
956 $ hg add .hgsub
974 $ hg add .hgsub
957 $ hg ci -mtest
975 $ hg ci -mtest
958 committing subrepository sub/repo (glob)
976 committing subrepository sub/repo (glob)
959 $ echo test >> sub/repo/foo
977 $ echo test >> sub/repo/foo
960 $ hg ci -mtest
978 $ hg ci -mtest
961 committing subrepository sub/repo (glob)
979 committing subrepository sub/repo (glob)
962 $ hg cat sub/repo/foo
980 $ hg cat sub/repo/foo
963 test
981 test
964 test
982 test
965 $ mkdir -p tmp/sub/repo
983 $ mkdir -p tmp/sub/repo
966 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
984 $ hg cat -r 0 --output tmp/%p_p sub/repo/foo
967 $ cat tmp/sub/repo/foo_p
985 $ cat tmp/sub/repo/foo_p
968 test
986 test
969 $ mv sub/repo sub_
987 $ mv sub/repo sub_
970 $ hg cat sub/repo/baz
988 $ hg cat sub/repo/baz
971 skipping missing subrepository: sub/repo
989 skipping missing subrepository: sub/repo
972 [1]
990 [1]
973 $ rm -rf sub/repo
991 $ rm -rf sub/repo
974 $ mv sub_ sub/repo
992 $ mv sub_ sub/repo
975 $ cd ..
993 $ cd ..
976
994
977 Create repo without default path, pull top repo, and see what happens on update
995 Create repo without default path, pull top repo, and see what happens on update
978
996
979 $ hg init issue1852b
997 $ hg init issue1852b
980 $ hg -R issue1852b pull issue1852a
998 $ hg -R issue1852b pull issue1852a
981 pulling from issue1852a
999 pulling from issue1852a
982 requesting all changes
1000 requesting all changes
983 adding changesets
1001 adding changesets
984 adding manifests
1002 adding manifests
985 adding file changes
1003 adding file changes
986 added 2 changesets with 3 changes to 2 files
1004 added 2 changesets with 3 changes to 2 files
987 (run 'hg update' to get a working copy)
1005 (run 'hg update' to get a working copy)
988 $ hg -R issue1852b update
1006 $ hg -R issue1852b update
989 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
1007 abort: default path for subrepository not found (in subrepo sub/repo) (glob)
990 [255]
1008 [255]
991
1009
992 Ensure a full traceback, not just the SubrepoAbort part
1010 Ensure a full traceback, not just the SubrepoAbort part
993
1011
994 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise util\.Abort'
1012 $ hg -R issue1852b update --traceback 2>&1 | grep 'raise util\.Abort'
995 raise util.Abort(_("default path for subrepository not found"))
1013 raise util.Abort(_("default path for subrepository not found"))
996
1014
997 Pull -u now doesn't help
1015 Pull -u now doesn't help
998
1016
999 $ hg -R issue1852b pull -u issue1852a
1017 $ hg -R issue1852b pull -u issue1852a
1000 pulling from issue1852a
1018 pulling from issue1852a
1001 searching for changes
1019 searching for changes
1002 no changes found
1020 no changes found
1003
1021
1004 Try the same, but with pull -u
1022 Try the same, but with pull -u
1005
1023
1006 $ hg init issue1852c
1024 $ hg init issue1852c
1007 $ hg -R issue1852c pull -r0 -u issue1852a
1025 $ hg -R issue1852c pull -r0 -u issue1852a
1008 pulling from issue1852a
1026 pulling from issue1852a
1009 adding changesets
1027 adding changesets
1010 adding manifests
1028 adding manifests
1011 adding file changes
1029 adding file changes
1012 added 1 changesets with 2 changes to 2 files
1030 added 1 changesets with 2 changes to 2 files
1013 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
1031 cloning subrepo sub/repo from issue1852a/sub/repo (glob)
1014 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1032 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1015
1033
1016 Try to push from the other side
1034 Try to push from the other side
1017
1035
1018 $ hg -R issue1852a push `pwd`/issue1852c
1036 $ hg -R issue1852a push `pwd`/issue1852c
1019 pushing to $TESTTMP/issue1852c (glob)
1037 pushing to $TESTTMP/issue1852c (glob)
1020 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
1038 pushing subrepo sub/repo to $TESTTMP/issue1852c/sub/repo (glob)
1021 searching for changes
1039 searching for changes
1022 no changes found
1040 no changes found
1023 searching for changes
1041 searching for changes
1024 adding changesets
1042 adding changesets
1025 adding manifests
1043 adding manifests
1026 adding file changes
1044 adding file changes
1027 added 1 changesets with 1 changes to 1 files
1045 added 1 changesets with 1 changes to 1 files
1028
1046
1029 Incoming and outgoing should not use the default path:
1047 Incoming and outgoing should not use the default path:
1030
1048
1031 $ hg clone -q issue1852a issue1852d
1049 $ hg clone -q issue1852a issue1852d
1032 $ hg -R issue1852d outgoing --subrepos issue1852c
1050 $ hg -R issue1852d outgoing --subrepos issue1852c
1033 comparing with issue1852c
1051 comparing with issue1852c
1034 searching for changes
1052 searching for changes
1035 no changes found
1053 no changes found
1036 comparing with issue1852c/sub/repo
1054 comparing with issue1852c/sub/repo
1037 searching for changes
1055 searching for changes
1038 no changes found
1056 no changes found
1039 [1]
1057 [1]
1040 $ hg -R issue1852d incoming --subrepos issue1852c
1058 $ hg -R issue1852d incoming --subrepos issue1852c
1041 comparing with issue1852c
1059 comparing with issue1852c
1042 searching for changes
1060 searching for changes
1043 no changes found
1061 no changes found
1044 comparing with issue1852c/sub/repo
1062 comparing with issue1852c/sub/repo
1045 searching for changes
1063 searching for changes
1046 no changes found
1064 no changes found
1047 [1]
1065 [1]
1048
1066
1049 Check that merge of a new subrepo doesn't write the uncommitted state to
1067 Check that merge of a new subrepo doesn't write the uncommitted state to
1050 .hgsubstate (issue4622)
1068 .hgsubstate (issue4622)
1051
1069
1052 $ hg init issue1852a/addedsub
1070 $ hg init issue1852a/addedsub
1053 $ echo zzz > issue1852a/addedsub/zz.txt
1071 $ echo zzz > issue1852a/addedsub/zz.txt
1054 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1072 $ hg -R issue1852a/addedsub ci -Aqm "initial ZZ"
1055
1073
1056 $ hg clone issue1852a/addedsub issue1852d/addedsub
1074 $ hg clone issue1852a/addedsub issue1852d/addedsub
1057 updating to branch default
1075 updating to branch default
1058 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1076 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1059
1077
1060 $ echo def > issue1852a/sub/repo/foo
1078 $ echo def > issue1852a/sub/repo/foo
1061 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1079 $ hg -R issue1852a ci -SAm 'tweaked subrepo'
1062 adding tmp/sub/repo/foo_p
1080 adding tmp/sub/repo/foo_p
1063 committing subrepository sub/repo (glob)
1081 committing subrepository sub/repo (glob)
1064
1082
1065 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1083 $ echo 'addedsub = addedsub' >> issue1852d/.hgsub
1066 $ echo xyz > issue1852d/sub/repo/foo
1084 $ echo xyz > issue1852d/sub/repo/foo
1067 $ hg -R issue1852d pull -u
1085 $ hg -R issue1852d pull -u
1068 pulling from $TESTTMP/issue1852a (glob)
1086 pulling from $TESTTMP/issue1852a (glob)
1069 searching for changes
1087 searching for changes
1070 adding changesets
1088 adding changesets
1071 adding manifests
1089 adding manifests
1072 adding file changes
1090 adding file changes
1073 added 1 changesets with 2 changes to 2 files
1091 added 1 changesets with 2 changes to 2 files
1074 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1092 subrepository sub/repo diverged (local revision: f42d5c7504a8, remote revision: 46cd4aac504c)
1075 (M)erge, keep (l)ocal or keep (r)emote? m
1093 (M)erge, keep (l)ocal or keep (r)emote? m
1076 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo (glob)
1094 pulling subrepo sub/repo from $TESTTMP/issue1852a/sub/repo (glob)
1077 searching for changes
1095 searching for changes
1078 adding changesets
1096 adding changesets
1079 adding manifests
1097 adding manifests
1080 adding file changes
1098 adding file changes
1081 added 1 changesets with 1 changes to 1 files
1099 added 1 changesets with 1 changes to 1 files
1082 subrepository sources for sub/repo differ (glob)
1100 subrepository sources for sub/repo differ (glob)
1083 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1101 use (l)ocal source (f42d5c7504a8) or (r)emote source (46cd4aac504c)? l
1084 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1102 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1085 $ cat issue1852d/.hgsubstate
1103 $ cat issue1852d/.hgsubstate
1086 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1104 f42d5c7504a811dda50f5cf3e5e16c3330b87172 sub/repo
1087
1105
1088 Check status of files when none of them belong to the first
1106 Check status of files when none of them belong to the first
1089 subrepository:
1107 subrepository:
1090
1108
1091 $ hg init subrepo-status
1109 $ hg init subrepo-status
1092 $ cd subrepo-status
1110 $ cd subrepo-status
1093 $ hg init subrepo-1
1111 $ hg init subrepo-1
1094 $ hg init subrepo-2
1112 $ hg init subrepo-2
1095 $ cd subrepo-2
1113 $ cd subrepo-2
1096 $ touch file
1114 $ touch file
1097 $ hg add file
1115 $ hg add file
1098 $ cd ..
1116 $ cd ..
1099 $ echo subrepo-1 = subrepo-1 > .hgsub
1117 $ echo subrepo-1 = subrepo-1 > .hgsub
1100 $ echo subrepo-2 = subrepo-2 >> .hgsub
1118 $ echo subrepo-2 = subrepo-2 >> .hgsub
1101 $ hg add .hgsub
1119 $ hg add .hgsub
1102 $ hg ci -m 'Added subrepos'
1120 $ hg ci -m 'Added subrepos'
1103 committing subrepository subrepo-2
1121 committing subrepository subrepo-2
1104 $ hg st subrepo-2/file
1122 $ hg st subrepo-2/file
1105
1123
1106 Check that share works with subrepo
1124 Check that share works with subrepo
1107 $ hg --config extensions.share= share . ../shared
1125 $ hg --config extensions.share= share . ../shared
1108 updating working directory
1126 updating working directory
1109 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1127 cloning subrepo subrepo-2 from $TESTTMP/subrepo-status/subrepo-2
1110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1128 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1111 $ test -f ../shared/subrepo-1/.hg/sharedpath
1129 $ test -f ../shared/subrepo-1/.hg/sharedpath
1112 [1]
1130 [1]
1113 $ hg -R ../shared in
1131 $ hg -R ../shared in
1114 abort: repository default not found!
1132 abort: repository default not found!
1115 [255]
1133 [255]
1116 $ hg -R ../shared/subrepo-2 showconfig paths
1134 $ hg -R ../shared/subrepo-2 showconfig paths
1117 paths.default=$TESTTMP/subrepo-status/subrepo-2
1135 paths.default=$TESTTMP/subrepo-status/subrepo-2
1118 $ hg -R ../shared/subrepo-1 sum --remote
1136 $ hg -R ../shared/subrepo-1 sum --remote
1119 parent: -1:000000000000 tip (empty repository)
1137 parent: -1:000000000000 tip (empty repository)
1120 branch: default
1138 branch: default
1121 commit: (clean)
1139 commit: (clean)
1122 update: (current)
1140 update: (current)
1123 remote: (synced)
1141 remote: (synced)
1124
1142
1125 Check hg update --clean
1143 Check hg update --clean
1126 $ cd $TESTTMP/t
1144 $ cd $TESTTMP/t
1127 $ rm -r t/t.orig
1145 $ rm -r t/t.orig
1128 $ hg status -S --all
1146 $ hg status -S --all
1129 C .hgsub
1147 C .hgsub
1130 C .hgsubstate
1148 C .hgsubstate
1131 C a
1149 C a
1132 C s/.hgsub
1150 C s/.hgsub
1133 C s/.hgsubstate
1151 C s/.hgsubstate
1134 C s/a
1152 C s/a
1135 C s/ss/a
1153 C s/ss/a
1136 C t/t
1154 C t/t
1137 $ echo c1 > s/a
1155 $ echo c1 > s/a
1138 $ cd s
1156 $ cd s
1139 $ echo c1 > b
1157 $ echo c1 > b
1140 $ echo c1 > c
1158 $ echo c1 > c
1141 $ hg add b
1159 $ hg add b
1142 $ cd ..
1160 $ cd ..
1143 $ hg status -S
1161 $ hg status -S
1144 M s/a
1162 M s/a
1145 A s/b
1163 A s/b
1146 ? s/c
1164 ? s/c
1147 $ hg update -C
1165 $ hg update -C
1148 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1166 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1149 $ hg status -S
1167 $ hg status -S
1150 ? s/b
1168 ? s/b
1151 ? s/c
1169 ? s/c
1152
1170
1153 Sticky subrepositories, no changes
1171 Sticky subrepositories, no changes
1154 $ cd $TESTTMP/t
1172 $ cd $TESTTMP/t
1155 $ hg id
1173 $ hg id
1156 925c17564ef8 tip
1174 925c17564ef8 tip
1157 $ hg -R s id
1175 $ hg -R s id
1158 12a213df6fa9 tip
1176 12a213df6fa9 tip
1159 $ hg -R t id
1177 $ hg -R t id
1160 52c0adc0515a tip
1178 52c0adc0515a tip
1161 $ hg update 11
1179 $ hg update 11
1162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1180 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1163 $ hg id
1181 $ hg id
1164 365661e5936a
1182 365661e5936a
1165 $ hg -R s id
1183 $ hg -R s id
1166 fc627a69481f
1184 fc627a69481f
1167 $ hg -R t id
1185 $ hg -R t id
1168 e95bcfa18a35
1186 e95bcfa18a35
1169
1187
1170 Sticky subrepositories, file changes
1188 Sticky subrepositories, file changes
1171 $ touch s/f1
1189 $ touch s/f1
1172 $ touch t/f1
1190 $ touch t/f1
1173 $ hg add -S s/f1
1191 $ hg add -S s/f1
1174 $ hg add -S t/f1
1192 $ hg add -S t/f1
1175 $ hg id
1193 $ hg id
1176 365661e5936a+
1194 365661e5936a+
1177 $ hg -R s id
1195 $ hg -R s id
1178 fc627a69481f+
1196 fc627a69481f+
1179 $ hg -R t id
1197 $ hg -R t id
1180 e95bcfa18a35+
1198 e95bcfa18a35+
1181 $ hg update tip
1199 $ hg update tip
1182 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1200 subrepository s diverged (local revision: fc627a69481f, remote revision: 12a213df6fa9)
1183 (M)erge, keep (l)ocal or keep (r)emote? m
1201 (M)erge, keep (l)ocal or keep (r)emote? m
1184 subrepository sources for s differ
1202 subrepository sources for s differ
1185 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1203 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)? l
1186 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1204 subrepository t diverged (local revision: e95bcfa18a35, remote revision: 52c0adc0515a)
1187 (M)erge, keep (l)ocal or keep (r)emote? m
1205 (M)erge, keep (l)ocal or keep (r)emote? m
1188 subrepository sources for t differ
1206 subrepository sources for t differ
1189 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1207 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)? l
1190 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1208 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1191 $ hg id
1209 $ hg id
1192 925c17564ef8+ tip
1210 925c17564ef8+ tip
1193 $ hg -R s id
1211 $ hg -R s id
1194 fc627a69481f+
1212 fc627a69481f+
1195 $ hg -R t id
1213 $ hg -R t id
1196 e95bcfa18a35+
1214 e95bcfa18a35+
1197 $ hg update --clean tip
1215 $ hg update --clean tip
1198 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1216 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1199
1217
1200 Sticky subrepository, revision updates
1218 Sticky subrepository, revision updates
1201 $ hg id
1219 $ hg id
1202 925c17564ef8 tip
1220 925c17564ef8 tip
1203 $ hg -R s id
1221 $ hg -R s id
1204 12a213df6fa9 tip
1222 12a213df6fa9 tip
1205 $ hg -R t id
1223 $ hg -R t id
1206 52c0adc0515a tip
1224 52c0adc0515a tip
1207 $ cd s
1225 $ cd s
1208 $ hg update -r -2
1226 $ hg update -r -2
1209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1210 $ cd ../t
1228 $ cd ../t
1211 $ hg update -r 2
1229 $ hg update -r 2
1212 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1230 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1213 $ cd ..
1231 $ cd ..
1214 $ hg update 10
1232 $ hg update 10
1215 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1233 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1216 (M)erge, keep (l)ocal or keep (r)emote? m
1234 (M)erge, keep (l)ocal or keep (r)emote? m
1217 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1235 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 20a0db6fbf6c)
1218 (M)erge, keep (l)ocal or keep (r)emote? m
1236 (M)erge, keep (l)ocal or keep (r)emote? m
1219 subrepository sources for t differ (in checked out version)
1237 subrepository sources for t differ (in checked out version)
1220 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1238 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)? l
1221 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1239 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1222 $ hg id
1240 $ hg id
1223 e45c8b14af55+
1241 e45c8b14af55+
1224 $ hg -R s id
1242 $ hg -R s id
1225 02dcf1d70411
1243 02dcf1d70411
1226 $ hg -R t id
1244 $ hg -R t id
1227 7af322bc1198
1245 7af322bc1198
1228
1246
1229 Sticky subrepository, file changes and revision updates
1247 Sticky subrepository, file changes and revision updates
1230 $ touch s/f1
1248 $ touch s/f1
1231 $ touch t/f1
1249 $ touch t/f1
1232 $ hg add -S s/f1
1250 $ hg add -S s/f1
1233 $ hg add -S t/f1
1251 $ hg add -S t/f1
1234 $ hg id
1252 $ hg id
1235 e45c8b14af55+
1253 e45c8b14af55+
1236 $ hg -R s id
1254 $ hg -R s id
1237 02dcf1d70411+
1255 02dcf1d70411+
1238 $ hg -R t id
1256 $ hg -R t id
1239 7af322bc1198+
1257 7af322bc1198+
1240 $ hg update tip
1258 $ hg update tip
1241 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1259 subrepository s diverged (local revision: 12a213df6fa9, remote revision: 12a213df6fa9)
1242 (M)erge, keep (l)ocal or keep (r)emote? m
1260 (M)erge, keep (l)ocal or keep (r)emote? m
1243 subrepository sources for s differ
1261 subrepository sources for s differ
1244 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1262 use (l)ocal source (02dcf1d70411) or (r)emote source (12a213df6fa9)? l
1245 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1263 subrepository t diverged (local revision: 52c0adc0515a, remote revision: 52c0adc0515a)
1246 (M)erge, keep (l)ocal or keep (r)emote? m
1264 (M)erge, keep (l)ocal or keep (r)emote? m
1247 subrepository sources for t differ
1265 subrepository sources for t differ
1248 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1266 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)? l
1249 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1267 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1250 $ hg id
1268 $ hg id
1251 925c17564ef8+ tip
1269 925c17564ef8+ tip
1252 $ hg -R s id
1270 $ hg -R s id
1253 02dcf1d70411+
1271 02dcf1d70411+
1254 $ hg -R t id
1272 $ hg -R t id
1255 7af322bc1198+
1273 7af322bc1198+
1256
1274
1257 Sticky repository, update --clean
1275 Sticky repository, update --clean
1258 $ hg update --clean tip
1276 $ hg update --clean tip
1259 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1277 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1260 $ hg id
1278 $ hg id
1261 925c17564ef8 tip
1279 925c17564ef8 tip
1262 $ hg -R s id
1280 $ hg -R s id
1263 12a213df6fa9 tip
1281 12a213df6fa9 tip
1264 $ hg -R t id
1282 $ hg -R t id
1265 52c0adc0515a tip
1283 52c0adc0515a tip
1266
1284
1267 Test subrepo already at intended revision:
1285 Test subrepo already at intended revision:
1268 $ cd s
1286 $ cd s
1269 $ hg update fc627a69481f
1287 $ hg update fc627a69481f
1270 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1288 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1271 $ cd ..
1289 $ cd ..
1272 $ hg update 11
1290 $ hg update 11
1273 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1291 subrepository s diverged (local revision: 12a213df6fa9, remote revision: fc627a69481f)
1274 (M)erge, keep (l)ocal or keep (r)emote? m
1292 (M)erge, keep (l)ocal or keep (r)emote? m
1275 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1293 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1276 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1294 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1277 $ hg id -n
1295 $ hg id -n
1278 11+
1296 11+
1279 $ hg -R s id
1297 $ hg -R s id
1280 fc627a69481f
1298 fc627a69481f
1281 $ hg -R t id
1299 $ hg -R t id
1282 e95bcfa18a35
1300 e95bcfa18a35
1283
1301
1284 Test that removing .hgsubstate doesn't break anything:
1302 Test that removing .hgsubstate doesn't break anything:
1285
1303
1286 $ hg rm -f .hgsubstate
1304 $ hg rm -f .hgsubstate
1287 $ hg ci -mrm
1305 $ hg ci -mrm
1288 nothing changed
1306 nothing changed
1289 [1]
1307 [1]
1290 $ hg log -vr tip
1308 $ hg log -vr tip
1291 changeset: 13:925c17564ef8
1309 changeset: 13:925c17564ef8
1292 tag: tip
1310 tag: tip
1293 user: test
1311 user: test
1294 date: Thu Jan 01 00:00:00 1970 +0000
1312 date: Thu Jan 01 00:00:00 1970 +0000
1295 files: .hgsubstate
1313 files: .hgsubstate
1296 description:
1314 description:
1297 13
1315 13
1298
1316
1299
1317
1300
1318
1301 Test that removing .hgsub removes .hgsubstate:
1319 Test that removing .hgsub removes .hgsubstate:
1302
1320
1303 $ hg rm .hgsub
1321 $ hg rm .hgsub
1304 $ hg ci -mrm2
1322 $ hg ci -mrm2
1305 created new head
1323 created new head
1306 $ hg log -vr tip
1324 $ hg log -vr tip
1307 changeset: 14:2400bccd50af
1325 changeset: 14:2400bccd50af
1308 tag: tip
1326 tag: tip
1309 parent: 11:365661e5936a
1327 parent: 11:365661e5936a
1310 user: test
1328 user: test
1311 date: Thu Jan 01 00:00:00 1970 +0000
1329 date: Thu Jan 01 00:00:00 1970 +0000
1312 files: .hgsub .hgsubstate
1330 files: .hgsub .hgsubstate
1313 description:
1331 description:
1314 rm2
1332 rm2
1315
1333
1316
1334
1317 Test issue3153: diff -S with deleted subrepos
1335 Test issue3153: diff -S with deleted subrepos
1318
1336
1319 $ hg diff --nodates -S -c .
1337 $ hg diff --nodates -S -c .
1320 diff -r 365661e5936a -r 2400bccd50af .hgsub
1338 diff -r 365661e5936a -r 2400bccd50af .hgsub
1321 --- a/.hgsub
1339 --- a/.hgsub
1322 +++ /dev/null
1340 +++ /dev/null
1323 @@ -1,2 +0,0 @@
1341 @@ -1,2 +0,0 @@
1324 -s = s
1342 -s = s
1325 -t = t
1343 -t = t
1326 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1344 diff -r 365661e5936a -r 2400bccd50af .hgsubstate
1327 --- a/.hgsubstate
1345 --- a/.hgsubstate
1328 +++ /dev/null
1346 +++ /dev/null
1329 @@ -1,2 +0,0 @@
1347 @@ -1,2 +0,0 @@
1330 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1348 -fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1331 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1349 -e95bcfa18a358dc4936da981ebf4147b4cad1362 t
1332
1350
1333 Test behavior of add for explicit path in subrepo:
1351 Test behavior of add for explicit path in subrepo:
1334 $ cd ..
1352 $ cd ..
1335 $ hg init explicit
1353 $ hg init explicit
1336 $ cd explicit
1354 $ cd explicit
1337 $ echo s = s > .hgsub
1355 $ echo s = s > .hgsub
1338 $ hg add .hgsub
1356 $ hg add .hgsub
1339 $ hg init s
1357 $ hg init s
1340 $ hg ci -m0
1358 $ hg ci -m0
1341 Adding with an explicit path in a subrepo adds the file
1359 Adding with an explicit path in a subrepo adds the file
1342 $ echo c1 > f1
1360 $ echo c1 > f1
1343 $ echo c2 > s/f2
1361 $ echo c2 > s/f2
1344 $ hg st -S
1362 $ hg st -S
1345 ? f1
1363 ? f1
1346 ? s/f2
1364 ? s/f2
1347 $ hg add s/f2
1365 $ hg add s/f2
1348 $ hg st -S
1366 $ hg st -S
1349 A s/f2
1367 A s/f2
1350 ? f1
1368 ? f1
1351 $ hg ci -R s -m0
1369 $ hg ci -R s -m0
1352 $ hg ci -Am1
1370 $ hg ci -Am1
1353 adding f1
1371 adding f1
1354 Adding with an explicit path in a subrepo with -S has the same behavior
1372 Adding with an explicit path in a subrepo with -S has the same behavior
1355 $ echo c3 > f3
1373 $ echo c3 > f3
1356 $ echo c4 > s/f4
1374 $ echo c4 > s/f4
1357 $ hg st -S
1375 $ hg st -S
1358 ? f3
1376 ? f3
1359 ? s/f4
1377 ? s/f4
1360 $ hg add -S s/f4
1378 $ hg add -S s/f4
1361 $ hg st -S
1379 $ hg st -S
1362 A s/f4
1380 A s/f4
1363 ? f3
1381 ? f3
1364 $ hg ci -R s -m1
1382 $ hg ci -R s -m1
1365 $ hg ci -Ama2
1383 $ hg ci -Ama2
1366 adding f3
1384 adding f3
1367 Adding without a path or pattern silently ignores subrepos
1385 Adding without a path or pattern silently ignores subrepos
1368 $ echo c5 > f5
1386 $ echo c5 > f5
1369 $ echo c6 > s/f6
1387 $ echo c6 > s/f6
1370 $ echo c7 > s/f7
1388 $ echo c7 > s/f7
1371 $ hg st -S
1389 $ hg st -S
1372 ? f5
1390 ? f5
1373 ? s/f6
1391 ? s/f6
1374 ? s/f7
1392 ? s/f7
1375 $ hg add
1393 $ hg add
1376 adding f5
1394 adding f5
1377 $ hg st -S
1395 $ hg st -S
1378 A f5
1396 A f5
1379 ? s/f6
1397 ? s/f6
1380 ? s/f7
1398 ? s/f7
1381 $ hg ci -R s -Am2
1399 $ hg ci -R s -Am2
1382 adding f6
1400 adding f6
1383 adding f7
1401 adding f7
1384 $ hg ci -m3
1402 $ hg ci -m3
1385 Adding without a path or pattern with -S also adds files in subrepos
1403 Adding without a path or pattern with -S also adds files in subrepos
1386 $ echo c8 > f8
1404 $ echo c8 > f8
1387 $ echo c9 > s/f9
1405 $ echo c9 > s/f9
1388 $ echo c10 > s/f10
1406 $ echo c10 > s/f10
1389 $ hg st -S
1407 $ hg st -S
1390 ? f8
1408 ? f8
1391 ? s/f10
1409 ? s/f10
1392 ? s/f9
1410 ? s/f9
1393 $ hg add -S
1411 $ hg add -S
1394 adding f8
1412 adding f8
1395 adding s/f10 (glob)
1413 adding s/f10 (glob)
1396 adding s/f9 (glob)
1414 adding s/f9 (glob)
1397 $ hg st -S
1415 $ hg st -S
1398 A f8
1416 A f8
1399 A s/f10
1417 A s/f10
1400 A s/f9
1418 A s/f9
1401 $ hg ci -R s -m3
1419 $ hg ci -R s -m3
1402 $ hg ci -m4
1420 $ hg ci -m4
1403 Adding with a pattern silently ignores subrepos
1421 Adding with a pattern silently ignores subrepos
1404 $ echo c11 > fm11
1422 $ echo c11 > fm11
1405 $ echo c12 > fn12
1423 $ echo c12 > fn12
1406 $ echo c13 > s/fm13
1424 $ echo c13 > s/fm13
1407 $ echo c14 > s/fn14
1425 $ echo c14 > s/fn14
1408 $ hg st -S
1426 $ hg st -S
1409 ? fm11
1427 ? fm11
1410 ? fn12
1428 ? fn12
1411 ? s/fm13
1429 ? s/fm13
1412 ? s/fn14
1430 ? s/fn14
1413 $ hg add 'glob:**fm*'
1431 $ hg add 'glob:**fm*'
1414 adding fm11
1432 adding fm11
1415 $ hg st -S
1433 $ hg st -S
1416 A fm11
1434 A fm11
1417 ? fn12
1435 ? fn12
1418 ? s/fm13
1436 ? s/fm13
1419 ? s/fn14
1437 ? s/fn14
1420 $ hg ci -R s -Am4
1438 $ hg ci -R s -Am4
1421 adding fm13
1439 adding fm13
1422 adding fn14
1440 adding fn14
1423 $ hg ci -Am5
1441 $ hg ci -Am5
1424 adding fn12
1442 adding fn12
1425 Adding with a pattern with -S also adds matches in subrepos
1443 Adding with a pattern with -S also adds matches in subrepos
1426 $ echo c15 > fm15
1444 $ echo c15 > fm15
1427 $ echo c16 > fn16
1445 $ echo c16 > fn16
1428 $ echo c17 > s/fm17
1446 $ echo c17 > s/fm17
1429 $ echo c18 > s/fn18
1447 $ echo c18 > s/fn18
1430 $ hg st -S
1448 $ hg st -S
1431 ? fm15
1449 ? fm15
1432 ? fn16
1450 ? fn16
1433 ? s/fm17
1451 ? s/fm17
1434 ? s/fn18
1452 ? s/fn18
1435 $ hg add -S 'glob:**fm*'
1453 $ hg add -S 'glob:**fm*'
1436 adding fm15
1454 adding fm15
1437 adding s/fm17 (glob)
1455 adding s/fm17 (glob)
1438 $ hg st -S
1456 $ hg st -S
1439 A fm15
1457 A fm15
1440 A s/fm17
1458 A s/fm17
1441 ? fn16
1459 ? fn16
1442 ? s/fn18
1460 ? s/fn18
1443 $ hg ci -R s -Am5
1461 $ hg ci -R s -Am5
1444 adding fn18
1462 adding fn18
1445 $ hg ci -Am6
1463 $ hg ci -Am6
1446 adding fn16
1464 adding fn16
1447
1465
1448 Test behavior of forget for explicit path in subrepo:
1466 Test behavior of forget for explicit path in subrepo:
1449 Forgetting an explicit path in a subrepo untracks the file
1467 Forgetting an explicit path in a subrepo untracks the file
1450 $ echo c19 > s/f19
1468 $ echo c19 > s/f19
1451 $ hg add s/f19
1469 $ hg add s/f19
1452 $ hg st -S
1470 $ hg st -S
1453 A s/f19
1471 A s/f19
1454 $ hg forget s/f19
1472 $ hg forget s/f19
1455 $ hg st -S
1473 $ hg st -S
1456 ? s/f19
1474 ? s/f19
1457 $ rm s/f19
1475 $ rm s/f19
1458 $ cd ..
1476 $ cd ..
1459
1477
1460 Courtesy phases synchronisation to publishing server does not block the push
1478 Courtesy phases synchronisation to publishing server does not block the push
1461 (issue3781)
1479 (issue3781)
1462
1480
1463 $ cp -r main issue3781
1481 $ cp -r main issue3781
1464 $ cp -r main issue3781-dest
1482 $ cp -r main issue3781-dest
1465 $ cd issue3781-dest/s
1483 $ cd issue3781-dest/s
1466 $ hg phase tip # show we have draft changeset
1484 $ hg phase tip # show we have draft changeset
1467 5: draft
1485 5: draft
1468 $ chmod a-w .hg/store/phaseroots # prevent phase push
1486 $ chmod a-w .hg/store/phaseroots # prevent phase push
1469 $ cd ../../issue3781
1487 $ cd ../../issue3781
1470 $ cat >> .hg/hgrc << EOF
1488 $ cat >> .hg/hgrc << EOF
1471 > [paths]
1489 > [paths]
1472 > default=../issue3781-dest/
1490 > default=../issue3781-dest/
1473 > EOF
1491 > EOF
1474 $ hg push
1492 $ hg push
1475 pushing to $TESTTMP/issue3781-dest (glob)
1493 pushing to $TESTTMP/issue3781-dest (glob)
1476 pushing subrepo s to $TESTTMP/issue3781-dest/s
1494 pushing subrepo s to $TESTTMP/issue3781-dest/s
1477 searching for changes
1495 searching for changes
1478 no changes found
1496 no changes found
1479 searching for changes
1497 searching for changes
1480 no changes found
1498 no changes found
1481 [1]
1499 [1]
1482 $ cd ..
1500 $ cd ..
1483
1501
1484 Test phase choice for newly created commit with "phases.subrepochecks"
1502 Test phase choice for newly created commit with "phases.subrepochecks"
1485 configuration
1503 configuration
1486
1504
1487 $ cd t
1505 $ cd t
1488 $ hg update -q -r 12
1506 $ hg update -q -r 12
1489
1507
1490 $ cat >> s/ss/.hg/hgrc <<EOF
1508 $ cat >> s/ss/.hg/hgrc <<EOF
1491 > [phases]
1509 > [phases]
1492 > new-commit = secret
1510 > new-commit = secret
1493 > EOF
1511 > EOF
1494 $ cat >> s/.hg/hgrc <<EOF
1512 $ cat >> s/.hg/hgrc <<EOF
1495 > [phases]
1513 > [phases]
1496 > new-commit = draft
1514 > new-commit = draft
1497 > EOF
1515 > EOF
1498 $ echo phasecheck1 >> s/ss/a
1516 $ echo phasecheck1 >> s/ss/a
1499 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1517 $ hg -R s commit -S --config phases.checksubrepos=abort -m phasecheck1
1500 committing subrepository ss
1518 committing subrepository ss
1501 transaction abort!
1519 transaction abort!
1502 rollback completed
1520 rollback completed
1503 abort: can't commit in draft phase conflicting secret from subrepository ss
1521 abort: can't commit in draft phase conflicting secret from subrepository ss
1504 [255]
1522 [255]
1505 $ echo phasecheck2 >> s/ss/a
1523 $ echo phasecheck2 >> s/ss/a
1506 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1524 $ hg -R s commit -S --config phases.checksubrepos=ignore -m phasecheck2
1507 committing subrepository ss
1525 committing subrepository ss
1508 $ hg -R s/ss phase tip
1526 $ hg -R s/ss phase tip
1509 3: secret
1527 3: secret
1510 $ hg -R s phase tip
1528 $ hg -R s phase tip
1511 6: draft
1529 6: draft
1512 $ echo phasecheck3 >> s/ss/a
1530 $ echo phasecheck3 >> s/ss/a
1513 $ hg -R s commit -S -m phasecheck3
1531 $ hg -R s commit -S -m phasecheck3
1514 committing subrepository ss
1532 committing subrepository ss
1515 warning: changes are committed in secret phase from subrepository ss
1533 warning: changes are committed in secret phase from subrepository ss
1516 $ hg -R s/ss phase tip
1534 $ hg -R s/ss phase tip
1517 4: secret
1535 4: secret
1518 $ hg -R s phase tip
1536 $ hg -R s phase tip
1519 7: secret
1537 7: secret
1520
1538
1521 $ cat >> t/.hg/hgrc <<EOF
1539 $ cat >> t/.hg/hgrc <<EOF
1522 > [phases]
1540 > [phases]
1523 > new-commit = draft
1541 > new-commit = draft
1524 > EOF
1542 > EOF
1525 $ cat >> .hg/hgrc <<EOF
1543 $ cat >> .hg/hgrc <<EOF
1526 > [phases]
1544 > [phases]
1527 > new-commit = public
1545 > new-commit = public
1528 > EOF
1546 > EOF
1529 $ echo phasecheck4 >> s/ss/a
1547 $ echo phasecheck4 >> s/ss/a
1530 $ echo phasecheck4 >> t/t
1548 $ echo phasecheck4 >> t/t
1531 $ hg commit -S -m phasecheck4
1549 $ hg commit -S -m phasecheck4
1532 committing subrepository s
1550 committing subrepository s
1533 committing subrepository s/ss (glob)
1551 committing subrepository s/ss (glob)
1534 warning: changes are committed in secret phase from subrepository ss
1552 warning: changes are committed in secret phase from subrepository ss
1535 committing subrepository t
1553 committing subrepository t
1536 warning: changes are committed in secret phase from subrepository s
1554 warning: changes are committed in secret phase from subrepository s
1537 created new head
1555 created new head
1538 $ hg -R s/ss phase tip
1556 $ hg -R s/ss phase tip
1539 5: secret
1557 5: secret
1540 $ hg -R s phase tip
1558 $ hg -R s phase tip
1541 8: secret
1559 8: secret
1542 $ hg -R t phase tip
1560 $ hg -R t phase tip
1543 6: draft
1561 6: draft
1544 $ hg phase tip
1562 $ hg phase tip
1545 15: secret
1563 15: secret
1546
1564
1547 $ cd ..
1565 $ cd ..
1548
1566
1549
1567
1550 Test that commit --secret works on both repo and subrepo (issue4182)
1568 Test that commit --secret works on both repo and subrepo (issue4182)
1551
1569
1552 $ cd main
1570 $ cd main
1553 $ echo secret >> b
1571 $ echo secret >> b
1554 $ echo secret >> s/b
1572 $ echo secret >> s/b
1555 $ hg commit --secret --subrepo -m "secret"
1573 $ hg commit --secret --subrepo -m "secret"
1556 committing subrepository s
1574 committing subrepository s
1557 $ hg phase -r .
1575 $ hg phase -r .
1558 6: secret
1576 6: secret
1559 $ cd s
1577 $ cd s
1560 $ hg phase -r .
1578 $ hg phase -r .
1561 6: secret
1579 6: secret
1562 $ cd ../../
1580 $ cd ../../
1563
1581
1564 Test "subrepos" template keyword
1582 Test "subrepos" template keyword
1565
1583
1566 $ cd t
1584 $ cd t
1567 $ hg update -q 15
1585 $ hg update -q 15
1568 $ cat > .hgsub <<EOF
1586 $ cat > .hgsub <<EOF
1569 > s = s
1587 > s = s
1570 > EOF
1588 > EOF
1571 $ hg commit -m "16"
1589 $ hg commit -m "16"
1572 warning: changes are committed in secret phase from subrepository s
1590 warning: changes are committed in secret phase from subrepository s
1573
1591
1574 (addition of ".hgsub" itself)
1592 (addition of ".hgsub" itself)
1575
1593
1576 $ hg diff --nodates -c 1 .hgsubstate
1594 $ hg diff --nodates -c 1 .hgsubstate
1577 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1595 diff -r f7b1eb17ad24 -r 7cf8cfea66e4 .hgsubstate
1578 --- /dev/null
1596 --- /dev/null
1579 +++ b/.hgsubstate
1597 +++ b/.hgsubstate
1580 @@ -0,0 +1,1 @@
1598 @@ -0,0 +1,1 @@
1581 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1599 +e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1582 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1600 $ hg log -r 1 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1583 f7b1eb17ad24 000000000000
1601 f7b1eb17ad24 000000000000
1584 s
1602 s
1585
1603
1586 (modification of existing entry)
1604 (modification of existing entry)
1587
1605
1588 $ hg diff --nodates -c 2 .hgsubstate
1606 $ hg diff --nodates -c 2 .hgsubstate
1589 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1607 diff -r 7cf8cfea66e4 -r df30734270ae .hgsubstate
1590 --- a/.hgsubstate
1608 --- a/.hgsubstate
1591 +++ b/.hgsubstate
1609 +++ b/.hgsubstate
1592 @@ -1,1 +1,1 @@
1610 @@ -1,1 +1,1 @@
1593 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1611 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1594 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1612 +dc73e2e6d2675eb2e41e33c205f4bdab4ea5111d s
1595 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1613 $ hg log -r 2 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1596 7cf8cfea66e4 000000000000
1614 7cf8cfea66e4 000000000000
1597 s
1615 s
1598
1616
1599 (addition of entry)
1617 (addition of entry)
1600
1618
1601 $ hg diff --nodates -c 5 .hgsubstate
1619 $ hg diff --nodates -c 5 .hgsubstate
1602 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1620 diff -r 7cf8cfea66e4 -r 1f14a2e2d3ec .hgsubstate
1603 --- a/.hgsubstate
1621 --- a/.hgsubstate
1604 +++ b/.hgsubstate
1622 +++ b/.hgsubstate
1605 @@ -1,1 +1,2 @@
1623 @@ -1,1 +1,2 @@
1606 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1624 e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1607 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1625 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1608 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1626 $ hg log -r 5 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1609 7cf8cfea66e4 000000000000
1627 7cf8cfea66e4 000000000000
1610 t
1628 t
1611
1629
1612 (removal of existing entry)
1630 (removal of existing entry)
1613
1631
1614 $ hg diff --nodates -c 16 .hgsubstate
1632 $ hg diff --nodates -c 16 .hgsubstate
1615 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1633 diff -r 8bec38d2bd0b -r f2f70bc3d3c9 .hgsubstate
1616 --- a/.hgsubstate
1634 --- a/.hgsubstate
1617 +++ b/.hgsubstate
1635 +++ b/.hgsubstate
1618 @@ -1,2 +1,1 @@
1636 @@ -1,2 +1,1 @@
1619 0731af8ca9423976d3743119d0865097c07bdc1b s
1637 0731af8ca9423976d3743119d0865097c07bdc1b s
1620 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1638 -e202dc79b04c88a636ea8913d9182a1346d9b3dc t
1621 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1639 $ hg log -r 16 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1622 8bec38d2bd0b 000000000000
1640 8bec38d2bd0b 000000000000
1623 t
1641 t
1624
1642
1625 (merging)
1643 (merging)
1626
1644
1627 $ hg diff --nodates -c 9 .hgsubstate
1645 $ hg diff --nodates -c 9 .hgsubstate
1628 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1646 diff -r f6affe3fbfaa -r f0d2028bf86d .hgsubstate
1629 --- a/.hgsubstate
1647 --- a/.hgsubstate
1630 +++ b/.hgsubstate
1648 +++ b/.hgsubstate
1631 @@ -1,1 +1,2 @@
1649 @@ -1,1 +1,2 @@
1632 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1650 fc627a69481fcbe5f1135069e8a3881c023e4cf5 s
1633 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1651 +60ca1237c19474e7a3978b0dc1ca4e6f36d51382 t
1634 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1652 $ hg log -r 9 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1635 f6affe3fbfaa 1f14a2e2d3ec
1653 f6affe3fbfaa 1f14a2e2d3ec
1636 t
1654 t
1637
1655
1638 (removal of ".hgsub" itself)
1656 (removal of ".hgsub" itself)
1639
1657
1640 $ hg diff --nodates -c 8 .hgsubstate
1658 $ hg diff --nodates -c 8 .hgsubstate
1641 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1659 diff -r f94576341bcf -r 96615c1dad2d .hgsubstate
1642 --- a/.hgsubstate
1660 --- a/.hgsubstate
1643 +++ /dev/null
1661 +++ /dev/null
1644 @@ -1,2 +0,0 @@
1662 @@ -1,2 +0,0 @@
1645 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1663 -e4ece1bf43360ddc8f6a96432201a37b7cd27ae4 s
1646 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1664 -7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4 t
1647 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1665 $ hg log -r 8 --template "{p1node|short} {p2node|short}\n{subrepos % '{subrepo}\n'}"
1648 f94576341bcf 000000000000
1666 f94576341bcf 000000000000
1649
1667
1650 Test that '[paths]' is configured correctly at subrepo creation
1668 Test that '[paths]' is configured correctly at subrepo creation
1651
1669
1652 $ cd $TESTTMP/tc
1670 $ cd $TESTTMP/tc
1653 $ cat > .hgsub <<EOF
1671 $ cat > .hgsub <<EOF
1654 > # to clear bogus subrepo path 'bogus=[boguspath'
1672 > # to clear bogus subrepo path 'bogus=[boguspath'
1655 > s = s
1673 > s = s
1656 > t = t
1674 > t = t
1657 > EOF
1675 > EOF
1658 $ hg update -q --clean null
1676 $ hg update -q --clean null
1659 $ rm -rf s t
1677 $ rm -rf s t
1660 $ cat >> .hg/hgrc <<EOF
1678 $ cat >> .hg/hgrc <<EOF
1661 > [paths]
1679 > [paths]
1662 > default-push = /foo/bar
1680 > default-push = /foo/bar
1663 > EOF
1681 > EOF
1664 $ hg update -q
1682 $ hg update -q
1665 $ cat s/.hg/hgrc
1683 $ cat s/.hg/hgrc
1666 [paths]
1684 [paths]
1667 default = $TESTTMP/t/s
1685 default = $TESTTMP/t/s
1668 default-push = /foo/bar/s
1686 default-push = /foo/bar/s
1669 $ cat s/ss/.hg/hgrc
1687 $ cat s/ss/.hg/hgrc
1670 [paths]
1688 [paths]
1671 default = $TESTTMP/t/s/ss
1689 default = $TESTTMP/t/s/ss
1672 default-push = /foo/bar/s/ss
1690 default-push = /foo/bar/s/ss
1673 $ cat t/.hg/hgrc
1691 $ cat t/.hg/hgrc
1674 [paths]
1692 [paths]
1675 default = $TESTTMP/t/t
1693 default = $TESTTMP/t/t
1676 default-push = /foo/bar/t
1694 default-push = /foo/bar/t
1677 $ cd ..
1695 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now