##// END OF EJS Templates
subrepos: prompt on conflicts on update with dirty subrepos...
Erik Zielke -
r13417:0748e18b default
parent child Browse files
Show More
@@ -1,961 +1,997 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 errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
8 import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
9 import stat, subprocess, tarfile
9 import stat, subprocess, tarfile
10 from i18n import _
10 from i18n import _
11 import config, util, node, error, cmdutil
11 import config, util, node, error, cmdutil
12 hg = None
12 hg = None
13
13
14 nullstate = ('', '', 'empty')
14 nullstate = ('', '', 'empty')
15
15
16 def state(ctx, ui):
16 def state(ctx, ui):
17 """return a state dict, mapping subrepo paths configured in .hgsub
17 """return a state dict, mapping subrepo paths configured in .hgsub
18 to tuple: (source from .hgsub, revision from .hgsubstate, kind
18 to tuple: (source from .hgsub, revision from .hgsubstate, kind
19 (key in types dict))
19 (key in types dict))
20 """
20 """
21 p = config.config()
21 p = config.config()
22 def read(f, sections=None, remap=None):
22 def read(f, sections=None, remap=None):
23 if f in ctx:
23 if f in ctx:
24 try:
24 try:
25 data = ctx[f].data()
25 data = ctx[f].data()
26 except IOError, err:
26 except IOError, err:
27 if err.errno != errno.ENOENT:
27 if err.errno != errno.ENOENT:
28 raise
28 raise
29 # handle missing subrepo spec files as removed
29 # handle missing subrepo spec files as removed
30 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
30 ui.warn(_("warning: subrepo spec file %s not found\n") % f)
31 return
31 return
32 p.parse(f, data, sections, remap, read)
32 p.parse(f, data, sections, remap, read)
33 else:
33 else:
34 raise util.Abort(_("subrepo spec file %s not found") % f)
34 raise util.Abort(_("subrepo spec file %s not found") % f)
35
35
36 if '.hgsub' in ctx:
36 if '.hgsub' in ctx:
37 read('.hgsub')
37 read('.hgsub')
38
38
39 for path, src in ui.configitems('subpaths'):
39 for path, src in ui.configitems('subpaths'):
40 p.set('subpaths', path, src, ui.configsource('subpaths', path))
40 p.set('subpaths', path, src, ui.configsource('subpaths', path))
41
41
42 rev = {}
42 rev = {}
43 if '.hgsubstate' in ctx:
43 if '.hgsubstate' in ctx:
44 try:
44 try:
45 for l in ctx['.hgsubstate'].data().splitlines():
45 for l in ctx['.hgsubstate'].data().splitlines():
46 revision, path = l.split(" ", 1)
46 revision, path = l.split(" ", 1)
47 rev[path] = revision
47 rev[path] = revision
48 except IOError, err:
48 except IOError, err:
49 if err.errno != errno.ENOENT:
49 if err.errno != errno.ENOENT:
50 raise
50 raise
51
51
52 state = {}
52 state = {}
53 for path, src in p[''].items():
53 for path, src in p[''].items():
54 kind = 'hg'
54 kind = 'hg'
55 if src.startswith('['):
55 if src.startswith('['):
56 if ']' not in src:
56 if ']' not in src:
57 raise util.Abort(_('missing ] in subrepo source'))
57 raise util.Abort(_('missing ] in subrepo source'))
58 kind, src = src.split(']', 1)
58 kind, src = src.split(']', 1)
59 kind = kind[1:]
59 kind = kind[1:]
60
60
61 for pattern, repl in p.items('subpaths'):
61 for pattern, repl in p.items('subpaths'):
62 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
62 # Turn r'C:\foo\bar' into r'C:\\foo\\bar' since re.sub
63 # does a string decode.
63 # does a string decode.
64 repl = repl.encode('string-escape')
64 repl = repl.encode('string-escape')
65 # However, we still want to allow back references to go
65 # However, we still want to allow back references to go
66 # through unharmed, so we turn r'\\1' into r'\1'. Again,
66 # through unharmed, so we turn r'\\1' into r'\1'. Again,
67 # extra escapes are needed because re.sub string decodes.
67 # extra escapes are needed because re.sub string decodes.
68 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
68 repl = re.sub(r'\\\\([0-9]+)', r'\\\1', repl)
69 try:
69 try:
70 src = re.sub(pattern, repl, src, 1)
70 src = re.sub(pattern, repl, src, 1)
71 except re.error, e:
71 except re.error, e:
72 raise util.Abort(_("bad subrepository pattern in %s: %s")
72 raise util.Abort(_("bad subrepository pattern in %s: %s")
73 % (p.source('subpaths', pattern), e))
73 % (p.source('subpaths', pattern), e))
74
74
75 state[path] = (src.strip(), rev.get(path, ''), kind)
75 state[path] = (src.strip(), rev.get(path, ''), kind)
76
76
77 return state
77 return state
78
78
79 def writestate(repo, state):
79 def writestate(repo, state):
80 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
80 """rewrite .hgsubstate in (outer) repo with these subrepo states"""
81 repo.wwrite('.hgsubstate',
81 repo.wwrite('.hgsubstate',
82 ''.join(['%s %s\n' % (state[s][1], s)
82 ''.join(['%s %s\n' % (state[s][1], s)
83 for s in sorted(state)]), '')
83 for s in sorted(state)]), '')
84
84
85 def submerge(repo, wctx, mctx, actx, overwrite):
85 def submerge(repo, wctx, mctx, actx, overwrite):
86 """delegated from merge.applyupdates: merging of .hgsubstate file
86 """delegated from merge.applyupdates: merging of .hgsubstate file
87 in working context, merging context and ancestor context"""
87 in working context, merging context and ancestor context"""
88 if mctx == actx: # backwards?
88 if mctx == actx: # backwards?
89 actx = wctx.p1()
89 actx = wctx.p1()
90 s1 = wctx.substate
90 s1 = wctx.substate
91 s2 = mctx.substate
91 s2 = mctx.substate
92 sa = actx.substate
92 sa = actx.substate
93 sm = {}
93 sm = {}
94
94
95 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
95 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
96
96
97 def debug(s, msg, r=""):
97 def debug(s, msg, r=""):
98 if r:
98 if r:
99 r = "%s:%s:%s" % r
99 r = "%s:%s:%s" % r
100 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
100 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
101
101
102 for s, l in s1.items():
102 for s, l in s1.items():
103 a = sa.get(s, nullstate)
103 a = sa.get(s, nullstate)
104 ld = l # local state with possible dirty flag for compares
104 ld = l # local state with possible dirty flag for compares
105 if wctx.sub(s).dirty():
105 if wctx.sub(s).dirty():
106 ld = (l[0], l[1] + "+")
106 ld = (l[0], l[1] + "+")
107 if wctx == actx: # overwrite
107 if wctx == actx: # overwrite
108 a = ld
108 a = ld
109
109
110 if s in s2:
110 if s in s2:
111 r = s2[s]
111 r = s2[s]
112 if ld == r or r == a: # no change or local is newer
112 if ld == r or r == a: # no change or local is newer
113 sm[s] = l
113 sm[s] = l
114 continue
114 continue
115 elif ld == a: # other side changed
115 elif ld == a: # other side changed
116 debug(s, "other changed, get", r)
116 debug(s, "other changed, get", r)
117 wctx.sub(s).get(r, overwrite)
117 wctx.sub(s).get(r, overwrite)
118 sm[s] = r
118 sm[s] = r
119 elif ld[0] != r[0]: # sources differ
119 elif ld[0] != r[0]: # sources differ
120 if repo.ui.promptchoice(
120 if repo.ui.promptchoice(
121 _(' subrepository sources for %s differ\n'
121 _(' subrepository sources for %s differ\n'
122 'use (l)ocal source (%s) or (r)emote source (%s)?')
122 'use (l)ocal source (%s) or (r)emote source (%s)?')
123 % (s, l[0], r[0]),
123 % (s, l[0], r[0]),
124 (_('&Local'), _('&Remote')), 0):
124 (_('&Local'), _('&Remote')), 0):
125 debug(s, "prompt changed, get", r)
125 debug(s, "prompt changed, get", r)
126 wctx.sub(s).get(r, overwrite)
126 wctx.sub(s).get(r, overwrite)
127 sm[s] = r
127 sm[s] = r
128 elif ld[1] == a[1]: # local side is unchanged
128 elif ld[1] == a[1]: # local side is unchanged
129 debug(s, "other side changed, get", r)
129 debug(s, "other side changed, get", r)
130 wctx.sub(s).get(r, overwrite)
130 wctx.sub(s).get(r, overwrite)
131 sm[s] = r
131 sm[s] = r
132 else:
132 else:
133 debug(s, "both sides changed, merge with", r)
133 debug(s, "both sides changed, merge with", r)
134 wctx.sub(s).merge(r)
134 wctx.sub(s).merge(r)
135 sm[s] = l
135 sm[s] = l
136 elif ld == a: # remote removed, local unchanged
136 elif ld == a: # remote removed, local unchanged
137 debug(s, "remote removed, remove")
137 debug(s, "remote removed, remove")
138 wctx.sub(s).remove()
138 wctx.sub(s).remove()
139 else:
139 else:
140 if repo.ui.promptchoice(
140 if repo.ui.promptchoice(
141 _(' local changed subrepository %s which remote removed\n'
141 _(' local changed subrepository %s which remote removed\n'
142 'use (c)hanged version or (d)elete?') % s,
142 'use (c)hanged version or (d)elete?') % s,
143 (_('&Changed'), _('&Delete')), 0):
143 (_('&Changed'), _('&Delete')), 0):
144 debug(s, "prompt remove")
144 debug(s, "prompt remove")
145 wctx.sub(s).remove()
145 wctx.sub(s).remove()
146
146
147 for s, r in s2.items():
147 for s, r in s2.items():
148 if s in s1:
148 if s in s1:
149 continue
149 continue
150 elif s not in sa:
150 elif s not in sa:
151 debug(s, "remote added, get", r)
151 debug(s, "remote added, get", r)
152 mctx.sub(s).get(r)
152 mctx.sub(s).get(r)
153 sm[s] = r
153 sm[s] = r
154 elif r != sa[s]:
154 elif r != sa[s]:
155 if repo.ui.promptchoice(
155 if repo.ui.promptchoice(
156 _(' remote changed subrepository %s which local removed\n'
156 _(' remote changed subrepository %s which local removed\n'
157 'use (c)hanged version or (d)elete?') % s,
157 'use (c)hanged version or (d)elete?') % s,
158 (_('&Changed'), _('&Delete')), 0) == 0:
158 (_('&Changed'), _('&Delete')), 0) == 0:
159 debug(s, "prompt recreate", r)
159 debug(s, "prompt recreate", r)
160 wctx.sub(s).get(r)
160 wctx.sub(s).get(r)
161 sm[s] = r
161 sm[s] = r
162
162
163 # record merged .hgsubstate
163 # record merged .hgsubstate
164 writestate(repo, sm)
164 writestate(repo, sm)
165
165
166 def _updateprompt(ui, sub, dirty, local, remote):
167 if dirty:
168 msg = (_(' subrepository sources for %s differ\n'
169 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
170 % (subrelpath(sub), local, remote))
171 else:
172 msg = (_(' subrepository sources for %s differ (in checked out version)\n'
173 'use (l)ocal source (%s) or (r)emote source (%s)?\n')
174 % (subrelpath(sub), local, remote))
175 return ui.promptchoice(msg, (_('&Local'), _('&Remote')), 0)
176
166 def reporelpath(repo):
177 def reporelpath(repo):
167 """return path to this (sub)repo as seen from outermost repo"""
178 """return path to this (sub)repo as seen from outermost repo"""
168 parent = repo
179 parent = repo
169 while hasattr(parent, '_subparent'):
180 while hasattr(parent, '_subparent'):
170 parent = parent._subparent
181 parent = parent._subparent
171 return repo.root[len(parent.root)+1:]
182 return repo.root[len(parent.root)+1:]
172
183
173 def subrelpath(sub):
184 def subrelpath(sub):
174 """return path to this subrepo as seen from outermost repo"""
185 """return path to this subrepo as seen from outermost repo"""
175 if hasattr(sub, '_relpath'):
186 if hasattr(sub, '_relpath'):
176 return sub._relpath
187 return sub._relpath
177 if not hasattr(sub, '_repo'):
188 if not hasattr(sub, '_repo'):
178 return sub._path
189 return sub._path
179 return reporelpath(sub._repo)
190 return reporelpath(sub._repo)
180
191
181 def _abssource(repo, push=False, abort=True):
192 def _abssource(repo, push=False, abort=True):
182 """return pull/push path of repo - either based on parent repo .hgsub info
193 """return pull/push path of repo - either based on parent repo .hgsub info
183 or on the top repo config. Abort or return None if no source found."""
194 or on the top repo config. Abort or return None if no source found."""
184 if hasattr(repo, '_subparent'):
195 if hasattr(repo, '_subparent'):
185 source = repo._subsource
196 source = repo._subsource
186 if source.startswith('/') or '://' in source:
197 if source.startswith('/') or '://' in source:
187 return source
198 return source
188 parent = _abssource(repo._subparent, push, abort=False)
199 parent = _abssource(repo._subparent, push, abort=False)
189 if parent:
200 if parent:
190 if '://' in parent:
201 if '://' in parent:
191 if parent[-1] == '/':
202 if parent[-1] == '/':
192 parent = parent[:-1]
203 parent = parent[:-1]
193 r = urlparse.urlparse(parent + '/' + source)
204 r = urlparse.urlparse(parent + '/' + source)
194 r = urlparse.urlunparse((r[0], r[1],
205 r = urlparse.urlunparse((r[0], r[1],
195 posixpath.normpath(r[2]),
206 posixpath.normpath(r[2]),
196 r[3], r[4], r[5]))
207 r[3], r[4], r[5]))
197 return r
208 return r
198 else: # plain file system path
209 else: # plain file system path
199 return posixpath.normpath(os.path.join(parent, repo._subsource))
210 return posixpath.normpath(os.path.join(parent, repo._subsource))
200 else: # recursion reached top repo
211 else: # recursion reached top repo
201 if hasattr(repo, '_subtoppath'):
212 if hasattr(repo, '_subtoppath'):
202 return repo._subtoppath
213 return repo._subtoppath
203 if push and repo.ui.config('paths', 'default-push'):
214 if push and repo.ui.config('paths', 'default-push'):
204 return repo.ui.config('paths', 'default-push')
215 return repo.ui.config('paths', 'default-push')
205 if repo.ui.config('paths', 'default'):
216 if repo.ui.config('paths', 'default'):
206 return repo.ui.config('paths', 'default')
217 return repo.ui.config('paths', 'default')
207 if abort:
218 if abort:
208 raise util.Abort(_("default path for subrepository %s not found") %
219 raise util.Abort(_("default path for subrepository %s not found") %
209 reporelpath(repo))
220 reporelpath(repo))
210
221
211 def itersubrepos(ctx1, ctx2):
222 def itersubrepos(ctx1, ctx2):
212 """find subrepos in ctx1 or ctx2"""
223 """find subrepos in ctx1 or ctx2"""
213 # Create a (subpath, ctx) mapping where we prefer subpaths from
224 # Create a (subpath, ctx) mapping where we prefer subpaths from
214 # ctx1. The subpaths from ctx2 are important when the .hgsub file
225 # ctx1. The subpaths from ctx2 are important when the .hgsub file
215 # has been modified (in ctx2) but not yet committed (in ctx1).
226 # has been modified (in ctx2) but not yet committed (in ctx1).
216 subpaths = dict.fromkeys(ctx2.substate, ctx2)
227 subpaths = dict.fromkeys(ctx2.substate, ctx2)
217 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
228 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
218 for subpath, ctx in sorted(subpaths.iteritems()):
229 for subpath, ctx in sorted(subpaths.iteritems()):
219 yield subpath, ctx.sub(subpath)
230 yield subpath, ctx.sub(subpath)
220
231
221 def subrepo(ctx, path):
232 def subrepo(ctx, path):
222 """return instance of the right subrepo class for subrepo in path"""
233 """return instance of the right subrepo class for subrepo in path"""
223 # subrepo inherently violates our import layering rules
234 # subrepo inherently violates our import layering rules
224 # because it wants to make repo objects from deep inside the stack
235 # because it wants to make repo objects from deep inside the stack
225 # so we manually delay the circular imports to not break
236 # so we manually delay the circular imports to not break
226 # scripts that don't use our demand-loading
237 # scripts that don't use our demand-loading
227 global hg
238 global hg
228 import hg as h
239 import hg as h
229 hg = h
240 hg = h
230
241
231 util.path_auditor(ctx._repo.root)(path)
242 util.path_auditor(ctx._repo.root)(path)
232 state = ctx.substate.get(path, nullstate)
243 state = ctx.substate.get(path, nullstate)
233 if state[2] not in types:
244 if state[2] not in types:
234 raise util.Abort(_('unknown subrepo type %s') % state[2])
245 raise util.Abort(_('unknown subrepo type %s') % state[2])
235 return types[state[2]](ctx, path, state[:2])
246 return types[state[2]](ctx, path, state[:2])
236
247
237 # subrepo classes need to implement the following abstract class:
248 # subrepo classes need to implement the following abstract class:
238
249
239 class abstractsubrepo(object):
250 class abstractsubrepo(object):
240
251
241 def dirty(self, ignoreupdate=False):
252 def dirty(self, ignoreupdate=False):
242 """returns true if the dirstate of the subrepo is dirty or does not
253 """returns true if the dirstate of the subrepo is dirty or does not
243 match current stored state. If ignoreupdate is true, only check
254 match current stored state. If ignoreupdate is true, only check
244 whether the subrepo has uncommitted changes in its dirstate.
255 whether the subrepo has uncommitted changes in its dirstate.
245 """
256 """
246 raise NotImplementedError
257 raise NotImplementedError
247
258
248 def checknested(self, path):
259 def checknested(self, path):
249 """check if path is a subrepository within this repository"""
260 """check if path is a subrepository within this repository"""
250 return False
261 return False
251
262
252 def commit(self, text, user, date):
263 def commit(self, text, user, date):
253 """commit the current changes to the subrepo with the given
264 """commit the current changes to the subrepo with the given
254 log message. Use given user and date if possible. Return the
265 log message. Use given user and date if possible. Return the
255 new state of the subrepo.
266 new state of the subrepo.
256 """
267 """
257 raise NotImplementedError
268 raise NotImplementedError
258
269
259 def remove(self):
270 def remove(self):
260 """remove the subrepo
271 """remove the subrepo
261
272
262 (should verify the dirstate is not dirty first)
273 (should verify the dirstate is not dirty first)
263 """
274 """
264 raise NotImplementedError
275 raise NotImplementedError
265
276
266 def get(self, state, overwrite=False):
277 def get(self, state, overwrite=False):
267 """run whatever commands are needed to put the subrepo into
278 """run whatever commands are needed to put the subrepo into
268 this state
279 this state
269 """
280 """
270 raise NotImplementedError
281 raise NotImplementedError
271
282
272 def merge(self, state):
283 def merge(self, state):
273 """merge currently-saved state with the new state."""
284 """merge currently-saved state with the new state."""
274 raise NotImplementedError
285 raise NotImplementedError
275
286
276 def push(self, force):
287 def push(self, force):
277 """perform whatever action is analogous to 'hg push'
288 """perform whatever action is analogous to 'hg push'
278
289
279 This may be a no-op on some systems.
290 This may be a no-op on some systems.
280 """
291 """
281 raise NotImplementedError
292 raise NotImplementedError
282
293
283 def add(self, ui, match, dryrun, prefix):
294 def add(self, ui, match, dryrun, prefix):
284 return []
295 return []
285
296
286 def status(self, rev2, **opts):
297 def status(self, rev2, **opts):
287 return [], [], [], [], [], [], []
298 return [], [], [], [], [], [], []
288
299
289 def diff(self, diffopts, node2, match, prefix, **opts):
300 def diff(self, diffopts, node2, match, prefix, **opts):
290 pass
301 pass
291
302
292 def outgoing(self, ui, dest, opts):
303 def outgoing(self, ui, dest, opts):
293 return 1
304 return 1
294
305
295 def incoming(self, ui, source, opts):
306 def incoming(self, ui, source, opts):
296 return 1
307 return 1
297
308
298 def files(self):
309 def files(self):
299 """return filename iterator"""
310 """return filename iterator"""
300 raise NotImplementedError
311 raise NotImplementedError
301
312
302 def filedata(self, name):
313 def filedata(self, name):
303 """return file data"""
314 """return file data"""
304 raise NotImplementedError
315 raise NotImplementedError
305
316
306 def fileflags(self, name):
317 def fileflags(self, name):
307 """return file flags"""
318 """return file flags"""
308 return ''
319 return ''
309
320
310 def archive(self, ui, archiver, prefix):
321 def archive(self, ui, archiver, prefix):
311 files = self.files()
322 files = self.files()
312 total = len(files)
323 total = len(files)
313 relpath = subrelpath(self)
324 relpath = subrelpath(self)
314 ui.progress(_('archiving (%s)') % relpath, 0,
325 ui.progress(_('archiving (%s)') % relpath, 0,
315 unit=_('files'), total=total)
326 unit=_('files'), total=total)
316 for i, name in enumerate(files):
327 for i, name in enumerate(files):
317 flags = self.fileflags(name)
328 flags = self.fileflags(name)
318 mode = 'x' in flags and 0755 or 0644
329 mode = 'x' in flags and 0755 or 0644
319 symlink = 'l' in flags
330 symlink = 'l' in flags
320 archiver.addfile(os.path.join(prefix, self._path, name),
331 archiver.addfile(os.path.join(prefix, self._path, name),
321 mode, symlink, self.filedata(name))
332 mode, symlink, self.filedata(name))
322 ui.progress(_('archiving (%s)') % relpath, i + 1,
333 ui.progress(_('archiving (%s)') % relpath, i + 1,
323 unit=_('files'), total=total)
334 unit=_('files'), total=total)
324 ui.progress(_('archiving (%s)') % relpath, None)
335 ui.progress(_('archiving (%s)') % relpath, None)
325
336
326
337
327 class hgsubrepo(abstractsubrepo):
338 class hgsubrepo(abstractsubrepo):
328 def __init__(self, ctx, path, state):
339 def __init__(self, ctx, path, state):
329 self._path = path
340 self._path = path
330 self._state = state
341 self._state = state
331 r = ctx._repo
342 r = ctx._repo
332 root = r.wjoin(path)
343 root = r.wjoin(path)
333 create = False
344 create = False
334 if not os.path.exists(os.path.join(root, '.hg')):
345 if not os.path.exists(os.path.join(root, '.hg')):
335 create = True
346 create = True
336 util.makedirs(root)
347 util.makedirs(root)
337 self._repo = hg.repository(r.ui, root, create=create)
348 self._repo = hg.repository(r.ui, root, create=create)
338 self._repo._subparent = r
349 self._repo._subparent = r
339 self._repo._subsource = state[0]
350 self._repo._subsource = state[0]
340
351
341 if create:
352 if create:
342 fp = self._repo.opener("hgrc", "w", text=True)
353 fp = self._repo.opener("hgrc", "w", text=True)
343 fp.write('[paths]\n')
354 fp.write('[paths]\n')
344
355
345 def addpathconfig(key, value):
356 def addpathconfig(key, value):
346 if value:
357 if value:
347 fp.write('%s = %s\n' % (key, value))
358 fp.write('%s = %s\n' % (key, value))
348 self._repo.ui.setconfig('paths', key, value)
359 self._repo.ui.setconfig('paths', key, value)
349
360
350 defpath = _abssource(self._repo, abort=False)
361 defpath = _abssource(self._repo, abort=False)
351 defpushpath = _abssource(self._repo, True, abort=False)
362 defpushpath = _abssource(self._repo, True, abort=False)
352 addpathconfig('default', defpath)
363 addpathconfig('default', defpath)
353 if defpath != defpushpath:
364 if defpath != defpushpath:
354 addpathconfig('default-push', defpushpath)
365 addpathconfig('default-push', defpushpath)
355 fp.close()
366 fp.close()
356
367
357 def add(self, ui, match, dryrun, prefix):
368 def add(self, ui, match, dryrun, prefix):
358 return cmdutil.add(ui, self._repo, match, dryrun, True,
369 return cmdutil.add(ui, self._repo, match, dryrun, True,
359 os.path.join(prefix, self._path))
370 os.path.join(prefix, self._path))
360
371
361 def status(self, rev2, **opts):
372 def status(self, rev2, **opts):
362 try:
373 try:
363 rev1 = self._state[1]
374 rev1 = self._state[1]
364 ctx1 = self._repo[rev1]
375 ctx1 = self._repo[rev1]
365 ctx2 = self._repo[rev2]
376 ctx2 = self._repo[rev2]
366 return self._repo.status(ctx1, ctx2, **opts)
377 return self._repo.status(ctx1, ctx2, **opts)
367 except error.RepoLookupError, inst:
378 except error.RepoLookupError, inst:
368 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
379 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
369 % (inst, subrelpath(self)))
380 % (inst, subrelpath(self)))
370 return [], [], [], [], [], [], []
381 return [], [], [], [], [], [], []
371
382
372 def diff(self, diffopts, node2, match, prefix, **opts):
383 def diff(self, diffopts, node2, match, prefix, **opts):
373 try:
384 try:
374 node1 = node.bin(self._state[1])
385 node1 = node.bin(self._state[1])
375 # We currently expect node2 to come from substate and be
386 # We currently expect node2 to come from substate and be
376 # in hex format
387 # in hex format
377 if node2 is not None:
388 if node2 is not None:
378 node2 = node.bin(node2)
389 node2 = node.bin(node2)
379 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
390 cmdutil.diffordiffstat(self._repo.ui, self._repo, diffopts,
380 node1, node2, match,
391 node1, node2, match,
381 prefix=os.path.join(prefix, self._path),
392 prefix=os.path.join(prefix, self._path),
382 listsubrepos=True, **opts)
393 listsubrepos=True, **opts)
383 except error.RepoLookupError, inst:
394 except error.RepoLookupError, inst:
384 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
395 self._repo.ui.warn(_('warning: error "%s" in subrepository "%s"\n')
385 % (inst, subrelpath(self)))
396 % (inst, subrelpath(self)))
386
397
387 def archive(self, ui, archiver, prefix):
398 def archive(self, ui, archiver, prefix):
388 abstractsubrepo.archive(self, ui, archiver, prefix)
399 abstractsubrepo.archive(self, ui, archiver, prefix)
389
400
390 rev = self._state[1]
401 rev = self._state[1]
391 ctx = self._repo[rev]
402 ctx = self._repo[rev]
392 for subpath in ctx.substate:
403 for subpath in ctx.substate:
393 s = subrepo(ctx, subpath)
404 s = subrepo(ctx, subpath)
394 s.archive(ui, archiver, os.path.join(prefix, self._path))
405 s.archive(ui, archiver, os.path.join(prefix, self._path))
395
406
396 def dirty(self, ignoreupdate=False):
407 def dirty(self, ignoreupdate=False):
397 r = self._state[1]
408 r = self._state[1]
398 if r == '' and not ignoreupdate: # no state recorded
409 if r == '' and not ignoreupdate: # no state recorded
399 return True
410 return True
400 w = self._repo[None]
411 w = self._repo[None]
401 if w.p1() != self._repo[r] and not ignoreupdate:
412 if w.p1() != self._repo[r] and not ignoreupdate:
402 # different version checked out
413 # different version checked out
403 return True
414 return True
404 return w.dirty() # working directory changed
415 return w.dirty() # working directory changed
405
416
406 def checknested(self, path):
417 def checknested(self, path):
407 return self._repo._checknested(self._repo.wjoin(path))
418 return self._repo._checknested(self._repo.wjoin(path))
408
419
409 def commit(self, text, user, date):
420 def commit(self, text, user, date):
410 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
421 self._repo.ui.debug("committing subrepo %s\n" % subrelpath(self))
411 n = self._repo.commit(text, user, date)
422 n = self._repo.commit(text, user, date)
412 if not n:
423 if not n:
413 return self._repo['.'].hex() # different version checked out
424 return self._repo['.'].hex() # different version checked out
414 return node.hex(n)
425 return node.hex(n)
415
426
416 def remove(self):
427 def remove(self):
417 # we can't fully delete the repository as it may contain
428 # we can't fully delete the repository as it may contain
418 # local-only history
429 # local-only history
419 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
430 self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
420 hg.clean(self._repo, node.nullid, False)
431 hg.clean(self._repo, node.nullid, False)
421
432
422 def _get(self, state):
433 def _get(self, state):
423 source, revision, kind = state
434 source, revision, kind = state
424 try:
435 try:
425 self._repo.lookup(revision)
436 self._repo.lookup(revision)
426 except error.RepoError:
437 except error.RepoError:
427 self._repo._subsource = source
438 self._repo._subsource = source
428 srcurl = _abssource(self._repo)
439 srcurl = _abssource(self._repo)
429 self._repo.ui.status(_('pulling subrepo %s from %s\n')
440 self._repo.ui.status(_('pulling subrepo %s from %s\n')
430 % (subrelpath(self), srcurl))
441 % (subrelpath(self), srcurl))
431 other = hg.repository(self._repo.ui, srcurl)
442 other = hg.repository(self._repo.ui, srcurl)
432 self._repo.pull(other)
443 self._repo.pull(other)
433
444
434 def get(self, state, overwrite=False):
445 def get(self, state, overwrite=False):
435 self._get(state)
446 self._get(state)
436 source, revision, kind = state
447 source, revision, kind = state
437 self._repo.ui.debug("getting subrepo %s\n" % self._path)
448 self._repo.ui.debug("getting subrepo %s\n" % self._path)
438 hg.clean(self._repo, revision, False)
449 hg.clean(self._repo, revision, False)
439
450
440 def merge(self, state):
451 def merge(self, state):
441 self._get(state)
452 self._get(state)
442 cur = self._repo['.']
453 cur = self._repo['.']
443 dst = self._repo[state[1]]
454 dst = self._repo[state[1]]
444 anc = dst.ancestor(cur)
455 anc = dst.ancestor(cur)
445 if anc == cur:
456
446 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
457 def mergefunc():
447 hg.update(self._repo, state[1])
458 if anc == cur:
448 elif anc == dst:
459 self._repo.ui.debug("updating subrepo %s\n" % subrelpath(self))
449 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
460 hg.update(self._repo, state[1])
461 elif anc == dst:
462 self._repo.ui.debug("skipping subrepo %s\n" % subrelpath(self))
463 else:
464 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
465 hg.merge(self._repo, state[1], remind=False)
466
467 wctx = self._repo[None]
468 if self.dirty():
469 if anc != dst:
470 if _updateprompt(self._repo.ui, self, wctx.dirty(), cur, dst):
471 mergefunc()
472 else:
473 mergefunc()
450 else:
474 else:
451 self._repo.ui.debug("merging subrepo %s\n" % subrelpath(self))
475 mergefunc()
452 hg.merge(self._repo, state[1], remind=False)
453
476
454 def push(self, force):
477 def push(self, force):
455 # push subrepos depth-first for coherent ordering
478 # push subrepos depth-first for coherent ordering
456 c = self._repo['']
479 c = self._repo['']
457 subs = c.substate # only repos that are committed
480 subs = c.substate # only repos that are committed
458 for s in sorted(subs):
481 for s in sorted(subs):
459 if not c.sub(s).push(force):
482 if not c.sub(s).push(force):
460 return False
483 return False
461
484
462 dsturl = _abssource(self._repo, True)
485 dsturl = _abssource(self._repo, True)
463 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
486 self._repo.ui.status(_('pushing subrepo %s to %s\n') %
464 (subrelpath(self), dsturl))
487 (subrelpath(self), dsturl))
465 other = hg.repository(self._repo.ui, dsturl)
488 other = hg.repository(self._repo.ui, dsturl)
466 return self._repo.push(other, force)
489 return self._repo.push(other, force)
467
490
468 def outgoing(self, ui, dest, opts):
491 def outgoing(self, ui, dest, opts):
469 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
492 return hg.outgoing(ui, self._repo, _abssource(self._repo, True), opts)
470
493
471 def incoming(self, ui, source, opts):
494 def incoming(self, ui, source, opts):
472 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
495 return hg.incoming(ui, self._repo, _abssource(self._repo, False), opts)
473
496
474 def files(self):
497 def files(self):
475 rev = self._state[1]
498 rev = self._state[1]
476 ctx = self._repo[rev]
499 ctx = self._repo[rev]
477 return ctx.manifest()
500 return ctx.manifest()
478
501
479 def filedata(self, name):
502 def filedata(self, name):
480 rev = self._state[1]
503 rev = self._state[1]
481 return self._repo[rev][name].data()
504 return self._repo[rev][name].data()
482
505
483 def fileflags(self, name):
506 def fileflags(self, name):
484 rev = self._state[1]
507 rev = self._state[1]
485 ctx = self._repo[rev]
508 ctx = self._repo[rev]
486 return ctx.flags(name)
509 return ctx.flags(name)
487
510
488
511
489 class svnsubrepo(abstractsubrepo):
512 class svnsubrepo(abstractsubrepo):
490 def __init__(self, ctx, path, state):
513 def __init__(self, ctx, path, state):
491 self._path = path
514 self._path = path
492 self._state = state
515 self._state = state
493 self._ctx = ctx
516 self._ctx = ctx
494 self._ui = ctx._repo.ui
517 self._ui = ctx._repo.ui
495
518
496 def _svncommand(self, commands, filename=''):
519 def _svncommand(self, commands, filename=''):
497 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
520 path = os.path.join(self._ctx._repo.origroot, self._path, filename)
498 cmd = ['svn'] + commands + [path]
521 cmd = ['svn'] + commands + [path]
499 env = dict(os.environ)
522 env = dict(os.environ)
500 # Avoid localized output, preserve current locale for everything else.
523 # Avoid localized output, preserve current locale for everything else.
501 env['LC_MESSAGES'] = 'C'
524 env['LC_MESSAGES'] = 'C'
502 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
525 p = subprocess.Popen(cmd, bufsize=-1, close_fds=util.closefds,
503 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
526 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
504 universal_newlines=True, env=env)
527 universal_newlines=True, env=env)
505 stdout, stderr = p.communicate()
528 stdout, stderr = p.communicate()
506 stderr = stderr.strip()
529 stderr = stderr.strip()
507 if stderr:
530 if stderr:
508 raise util.Abort(stderr)
531 raise util.Abort(stderr)
509 return stdout
532 return stdout
510
533
511 def _wcrevs(self):
534 def _wcrevs(self):
512 # Get the working directory revision as well as the last
535 # Get the working directory revision as well as the last
513 # commit revision so we can compare the subrepo state with
536 # commit revision so we can compare the subrepo state with
514 # both. We used to store the working directory one.
537 # both. We used to store the working directory one.
515 output = self._svncommand(['info', '--xml'])
538 output = self._svncommand(['info', '--xml'])
516 doc = xml.dom.minidom.parseString(output)
539 doc = xml.dom.minidom.parseString(output)
517 entries = doc.getElementsByTagName('entry')
540 entries = doc.getElementsByTagName('entry')
518 lastrev, rev = '0', '0'
541 lastrev, rev = '0', '0'
519 if entries:
542 if entries:
520 rev = str(entries[0].getAttribute('revision')) or '0'
543 rev = str(entries[0].getAttribute('revision')) or '0'
521 commits = entries[0].getElementsByTagName('commit')
544 commits = entries[0].getElementsByTagName('commit')
522 if commits:
545 if commits:
523 lastrev = str(commits[0].getAttribute('revision')) or '0'
546 lastrev = str(commits[0].getAttribute('revision')) or '0'
524 return (lastrev, rev)
547 return (lastrev, rev)
525
548
526 def _wcrev(self):
549 def _wcrev(self):
527 return self._wcrevs()[0]
550 return self._wcrevs()[0]
528
551
529 def _wcchanged(self):
552 def _wcchanged(self):
530 """Return (changes, extchanges) where changes is True
553 """Return (changes, extchanges) where changes is True
531 if the working directory was changed, and extchanges is
554 if the working directory was changed, and extchanges is
532 True if any of these changes concern an external entry.
555 True if any of these changes concern an external entry.
533 """
556 """
534 output = self._svncommand(['status', '--xml'])
557 output = self._svncommand(['status', '--xml'])
535 externals, changes = [], []
558 externals, changes = [], []
536 doc = xml.dom.minidom.parseString(output)
559 doc = xml.dom.minidom.parseString(output)
537 for e in doc.getElementsByTagName('entry'):
560 for e in doc.getElementsByTagName('entry'):
538 s = e.getElementsByTagName('wc-status')
561 s = e.getElementsByTagName('wc-status')
539 if not s:
562 if not s:
540 continue
563 continue
541 item = s[0].getAttribute('item')
564 item = s[0].getAttribute('item')
542 props = s[0].getAttribute('props')
565 props = s[0].getAttribute('props')
543 path = e.getAttribute('path')
566 path = e.getAttribute('path')
544 if item == 'external':
567 if item == 'external':
545 externals.append(path)
568 externals.append(path)
546 if (item not in ('', 'normal', 'unversioned', 'external')
569 if (item not in ('', 'normal', 'unversioned', 'external')
547 or props not in ('', 'none')):
570 or props not in ('', 'none')):
548 changes.append(path)
571 changes.append(path)
549 for path in changes:
572 for path in changes:
550 for ext in externals:
573 for ext in externals:
551 if path == ext or path.startswith(ext + os.sep):
574 if path == ext or path.startswith(ext + os.sep):
552 return True, True
575 return True, True
553 return bool(changes), False
576 return bool(changes), False
554
577
555 def dirty(self, ignoreupdate=False):
578 def dirty(self, ignoreupdate=False):
556 if not self._wcchanged()[0]:
579 if not self._wcchanged()[0]:
557 if self._state[1] in self._wcrevs() or ignoreupdate:
580 if self._state[1] in self._wcrevs() or ignoreupdate:
558 return False
581 return False
559 return True
582 return True
560
583
561 def commit(self, text, user, date):
584 def commit(self, text, user, date):
562 # user and date are out of our hands since svn is centralized
585 # user and date are out of our hands since svn is centralized
563 changed, extchanged = self._wcchanged()
586 changed, extchanged = self._wcchanged()
564 if not changed:
587 if not changed:
565 return self._wcrev()
588 return self._wcrev()
566 if extchanged:
589 if extchanged:
567 # Do not try to commit externals
590 # Do not try to commit externals
568 raise util.Abort(_('cannot commit svn externals'))
591 raise util.Abort(_('cannot commit svn externals'))
569 commitinfo = self._svncommand(['commit', '-m', text])
592 commitinfo = self._svncommand(['commit', '-m', text])
570 self._ui.status(commitinfo)
593 self._ui.status(commitinfo)
571 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
594 newrev = re.search('Committed revision ([0-9]+).', commitinfo)
572 if not newrev:
595 if not newrev:
573 raise util.Abort(commitinfo.splitlines()[-1])
596 raise util.Abort(commitinfo.splitlines()[-1])
574 newrev = newrev.groups()[0]
597 newrev = newrev.groups()[0]
575 self._ui.status(self._svncommand(['update', '-r', newrev]))
598 self._ui.status(self._svncommand(['update', '-r', newrev]))
576 return newrev
599 return newrev
577
600
578 def remove(self):
601 def remove(self):
579 if self.dirty():
602 if self.dirty():
580 self._ui.warn(_('not removing repo %s because '
603 self._ui.warn(_('not removing repo %s because '
581 'it has changes.\n' % self._path))
604 'it has changes.\n' % self._path))
582 return
605 return
583 self._ui.note(_('removing subrepo %s\n') % self._path)
606 self._ui.note(_('removing subrepo %s\n') % self._path)
584
607
585 def onerror(function, path, excinfo):
608 def onerror(function, path, excinfo):
586 if function is not os.remove:
609 if function is not os.remove:
587 raise
610 raise
588 # read-only files cannot be unlinked under Windows
611 # read-only files cannot be unlinked under Windows
589 s = os.stat(path)
612 s = os.stat(path)
590 if (s.st_mode & stat.S_IWRITE) != 0:
613 if (s.st_mode & stat.S_IWRITE) != 0:
591 raise
614 raise
592 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
615 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE)
593 os.remove(path)
616 os.remove(path)
594
617
595 path = self._ctx._repo.wjoin(self._path)
618 path = self._ctx._repo.wjoin(self._path)
596 shutil.rmtree(path, onerror=onerror)
619 shutil.rmtree(path, onerror=onerror)
597 try:
620 try:
598 os.removedirs(os.path.dirname(path))
621 os.removedirs(os.path.dirname(path))
599 except OSError:
622 except OSError:
600 pass
623 pass
601
624
602 def get(self, state, overwrite=False):
625 def get(self, state, overwrite=False):
603 if overwrite:
626 if overwrite:
604 self._svncommand(['revert', '--recursive'])
627 self._svncommand(['revert', '--recursive'])
605 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
628 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
606 if not re.search('Checked out revision [0-9]+.', status):
629 if not re.search('Checked out revision [0-9]+.', status):
607 raise util.Abort(status.splitlines()[-1])
630 raise util.Abort(status.splitlines()[-1])
608 self._ui.status(status)
631 self._ui.status(status)
609
632
610 def merge(self, state):
633 def merge(self, state):
611 old = int(self._state[1])
634 old = self._state[1]
612 new = int(state[1])
635 new = state[1]
613 if new > old:
636 if new != self._wcrev():
614 self.get(state)
637 dirty = old == self._wcrev() or self._wcchanged()[0]
638 if _updateprompt(self._ui, self, dirty, self._wcrev(), new):
639 self.get(state, False)
615
640
616 def push(self, force):
641 def push(self, force):
617 # push is a no-op for SVN
642 # push is a no-op for SVN
618 return True
643 return True
619
644
620 def files(self):
645 def files(self):
621 output = self._svncommand(['list'])
646 output = self._svncommand(['list'])
622 # This works because svn forbids \n in filenames.
647 # This works because svn forbids \n in filenames.
623 return output.splitlines()
648 return output.splitlines()
624
649
625 def filedata(self, name):
650 def filedata(self, name):
626 return self._svncommand(['cat'], name)
651 return self._svncommand(['cat'], name)
627
652
628
653
629 class gitsubrepo(abstractsubrepo):
654 class gitsubrepo(abstractsubrepo):
630 def __init__(self, ctx, path, state):
655 def __init__(self, ctx, path, state):
631 # TODO add git version check.
656 # TODO add git version check.
632 self._state = state
657 self._state = state
633 self._ctx = ctx
658 self._ctx = ctx
634 self._path = path
659 self._path = path
635 self._relpath = os.path.join(reporelpath(ctx._repo), path)
660 self._relpath = os.path.join(reporelpath(ctx._repo), path)
636 self._abspath = ctx._repo.wjoin(path)
661 self._abspath = ctx._repo.wjoin(path)
637 self._ui = ctx._repo.ui
662 self._ui = ctx._repo.ui
638
663
639 def _gitcommand(self, commands, env=None, stream=False):
664 def _gitcommand(self, commands, env=None, stream=False):
640 return self._gitdir(commands, env=env, stream=stream)[0]
665 return self._gitdir(commands, env=env, stream=stream)[0]
641
666
642 def _gitdir(self, commands, env=None, stream=False):
667 def _gitdir(self, commands, env=None, stream=False):
643 return self._gitnodir(commands, env=env, stream=stream,
668 return self._gitnodir(commands, env=env, stream=stream,
644 cwd=self._abspath)
669 cwd=self._abspath)
645
670
646 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
671 def _gitnodir(self, commands, env=None, stream=False, cwd=None):
647 """Calls the git command
672 """Calls the git command
648
673
649 The methods tries to call the git command. versions previor to 1.6.0
674 The methods tries to call the git command. versions previor to 1.6.0
650 are not supported and very probably fail.
675 are not supported and very probably fail.
651 """
676 """
652 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
677 self._ui.debug('%s: git %s\n' % (self._relpath, ' '.join(commands)))
653 # unless ui.quiet is set, print git's stderr,
678 # unless ui.quiet is set, print git's stderr,
654 # which is mostly progress and useful info
679 # which is mostly progress and useful info
655 errpipe = None
680 errpipe = None
656 if self._ui.quiet:
681 if self._ui.quiet:
657 errpipe = open(os.devnull, 'w')
682 errpipe = open(os.devnull, 'w')
658 p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
683 p = subprocess.Popen(['git'] + commands, bufsize=-1, cwd=cwd, env=env,
659 close_fds=util.closefds,
684 close_fds=util.closefds,
660 stdout=subprocess.PIPE, stderr=errpipe)
685 stdout=subprocess.PIPE, stderr=errpipe)
661 if stream:
686 if stream:
662 return p.stdout, None
687 return p.stdout, None
663
688
664 retdata = p.stdout.read().strip()
689 retdata = p.stdout.read().strip()
665 # wait for the child to exit to avoid race condition.
690 # wait for the child to exit to avoid race condition.
666 p.wait()
691 p.wait()
667
692
668 if p.returncode != 0 and p.returncode != 1:
693 if p.returncode != 0 and p.returncode != 1:
669 # there are certain error codes that are ok
694 # there are certain error codes that are ok
670 command = commands[0]
695 command = commands[0]
671 if command in ('cat-file', 'symbolic-ref'):
696 if command in ('cat-file', 'symbolic-ref'):
672 return retdata, p.returncode
697 return retdata, p.returncode
673 # for all others, abort
698 # for all others, abort
674 raise util.Abort('git %s error %d in %s' %
699 raise util.Abort('git %s error %d in %s' %
675 (command, p.returncode, self._relpath))
700 (command, p.returncode, self._relpath))
676
701
677 return retdata, p.returncode
702 return retdata, p.returncode
678
703
679 def _gitstate(self):
704 def _gitstate(self):
680 return self._gitcommand(['rev-parse', 'HEAD'])
705 return self._gitcommand(['rev-parse', 'HEAD'])
681
706
682 def _gitcurrentbranch(self):
707 def _gitcurrentbranch(self):
683 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
708 current, err = self._gitdir(['symbolic-ref', 'HEAD', '--quiet'])
684 if err:
709 if err:
685 current = None
710 current = None
686 return current
711 return current
687
712
688 def _githavelocally(self, revision):
713 def _githavelocally(self, revision):
689 out, code = self._gitdir(['cat-file', '-e', revision])
714 out, code = self._gitdir(['cat-file', '-e', revision])
690 return code == 0
715 return code == 0
691
716
692 def _gitisancestor(self, r1, r2):
717 def _gitisancestor(self, r1, r2):
693 base = self._gitcommand(['merge-base', r1, r2])
718 base = self._gitcommand(['merge-base', r1, r2])
694 return base == r1
719 return base == r1
695
720
696 def _gitbranchmap(self):
721 def _gitbranchmap(self):
697 '''returns 2 things:
722 '''returns 2 things:
698 a map from git branch to revision
723 a map from git branch to revision
699 a map from revision to branches'''
724 a map from revision to branches'''
700 branch2rev = {}
725 branch2rev = {}
701 rev2branch = {}
726 rev2branch = {}
702
727
703 out = self._gitcommand(['for-each-ref', '--format',
728 out = self._gitcommand(['for-each-ref', '--format',
704 '%(objectname) %(refname)'])
729 '%(objectname) %(refname)'])
705 for line in out.split('\n'):
730 for line in out.split('\n'):
706 revision, ref = line.split(' ')
731 revision, ref = line.split(' ')
707 if ref.startswith('refs/tags/'):
732 if ref.startswith('refs/tags/'):
708 continue
733 continue
709 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
734 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'):
710 continue # ignore remote/HEAD redirects
735 continue # ignore remote/HEAD redirects
711 branch2rev[ref] = revision
736 branch2rev[ref] = revision
712 rev2branch.setdefault(revision, []).append(ref)
737 rev2branch.setdefault(revision, []).append(ref)
713 return branch2rev, rev2branch
738 return branch2rev, rev2branch
714
739
715 def _gittracking(self, branches):
740 def _gittracking(self, branches):
716 'return map of remote branch to local tracking branch'
741 'return map of remote branch to local tracking branch'
717 # assumes no more than one local tracking branch for each remote
742 # assumes no more than one local tracking branch for each remote
718 tracking = {}
743 tracking = {}
719 for b in branches:
744 for b in branches:
720 if b.startswith('refs/remotes/'):
745 if b.startswith('refs/remotes/'):
721 continue
746 continue
722 remote = self._gitcommand(['config', 'branch.%s.remote' % b])
747 remote = self._gitcommand(['config', 'branch.%s.remote' % b])
723 if remote:
748 if remote:
724 ref = self._gitcommand(['config', 'branch.%s.merge' % b])
749 ref = self._gitcommand(['config', 'branch.%s.merge' % b])
725 tracking['refs/remotes/%s/%s' %
750 tracking['refs/remotes/%s/%s' %
726 (remote, ref.split('/', 2)[2])] = b
751 (remote, ref.split('/', 2)[2])] = b
727 return tracking
752 return tracking
728
753
729 def _fetch(self, source, revision):
754 def _fetch(self, source, revision):
730 if not os.path.exists(os.path.join(self._abspath, '.git')):
755 if not os.path.exists(os.path.join(self._abspath, '.git')):
731 self._ui.status(_('cloning subrepo %s\n') % self._relpath)
756 self._ui.status(_('cloning subrepo %s\n') % self._relpath)
732 self._gitnodir(['clone', source, self._abspath])
757 self._gitnodir(['clone', source, self._abspath])
733 if self._githavelocally(revision):
758 if self._githavelocally(revision):
734 return
759 return
735 self._ui.status(_('pulling subrepo %s\n') % self._relpath)
760 self._ui.status(_('pulling subrepo %s\n') % self._relpath)
736 # first try from origin
761 # first try from origin
737 self._gitcommand(['fetch'])
762 self._gitcommand(['fetch'])
738 if self._githavelocally(revision):
763 if self._githavelocally(revision):
739 return
764 return
740 # then try from known subrepo source
765 # then try from known subrepo source
741 self._gitcommand(['fetch', source])
766 self._gitcommand(['fetch', source])
742 if not self._githavelocally(revision):
767 if not self._githavelocally(revision):
743 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
768 raise util.Abort(_("revision %s does not exist in subrepo %s\n") %
744 (revision, self._relpath))
769 (revision, self._relpath))
745
770
746 def dirty(self, ignoreupdate=False):
771 def dirty(self, ignoreupdate=False):
747 if not ignoreupdate and self._state[1] != self._gitstate():
772 if not ignoreupdate and self._state[1] != self._gitstate():
748 # different version checked out
773 # different version checked out
749 return True
774 return True
750 # check for staged changes or modified files; ignore untracked files
775 # check for staged changes or modified files; ignore untracked files
751 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
776 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
752 return code == 1
777 return code == 1
753
778
754 def get(self, state, overwrite=False):
779 def get(self, state, overwrite=False):
755 source, revision, kind = state
780 source, revision, kind = state
756 self._fetch(source, revision)
781 self._fetch(source, revision)
757 # if the repo was set to be bare, unbare it
782 # if the repo was set to be bare, unbare it
758 if self._gitcommand(['config', '--bool', 'core.bare']) == 'true':
783 if self._gitcommand(['config', '--bool', 'core.bare']) == 'true':
759 self._gitcommand(['config', 'core.bare', 'false'])
784 self._gitcommand(['config', 'core.bare', 'false'])
760 if self._gitstate() == revision:
785 if self._gitstate() == revision:
761 self._gitcommand(['reset', '--hard', 'HEAD'])
786 self._gitcommand(['reset', '--hard', 'HEAD'])
762 return
787 return
763 elif self._gitstate() == revision:
788 elif self._gitstate() == revision:
764 if overwrite:
789 if overwrite:
765 # first reset the index to unmark new files for commit, because
790 # first reset the index to unmark new files for commit, because
766 # reset --hard will otherwise throw away files added for commit,
791 # reset --hard will otherwise throw away files added for commit,
767 # not just unmark them.
792 # not just unmark them.
768 self._gitcommand(['reset', 'HEAD'])
793 self._gitcommand(['reset', 'HEAD'])
769 self._gitcommand(['reset', '--hard', 'HEAD'])
794 self._gitcommand(['reset', '--hard', 'HEAD'])
770 return
795 return
771 branch2rev, rev2branch = self._gitbranchmap()
796 branch2rev, rev2branch = self._gitbranchmap()
772
797
773 def checkout(args):
798 def checkout(args):
774 cmd = ['checkout']
799 cmd = ['checkout']
775 if overwrite:
800 if overwrite:
776 # first reset the index to unmark new files for commit, because
801 # first reset the index to unmark new files for commit, because
777 # the -f option will otherwise throw away files added for
802 # the -f option will otherwise throw away files added for
778 # commit, not just unmark them.
803 # commit, not just unmark them.
779 self._gitcommand(['reset', 'HEAD'])
804 self._gitcommand(['reset', 'HEAD'])
780 cmd.append('-f')
805 cmd.append('-f')
781 self._gitcommand(cmd + args)
806 self._gitcommand(cmd + args)
782
807
783 def rawcheckout():
808 def rawcheckout():
784 # no branch to checkout, check it out with no branch
809 # no branch to checkout, check it out with no branch
785 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
810 self._ui.warn(_('checking out detached HEAD in subrepo %s\n') %
786 self._relpath)
811 self._relpath)
787 self._ui.warn(_('check out a git branch if you intend '
812 self._ui.warn(_('check out a git branch if you intend '
788 'to make changes\n'))
813 'to make changes\n'))
789 checkout(['-q', revision])
814 checkout(['-q', revision])
790
815
791 if revision not in rev2branch:
816 if revision not in rev2branch:
792 rawcheckout()
817 rawcheckout()
793 return
818 return
794 branches = rev2branch[revision]
819 branches = rev2branch[revision]
795 firstlocalbranch = None
820 firstlocalbranch = None
796 for b in branches:
821 for b in branches:
797 if b == 'refs/heads/master':
822 if b == 'refs/heads/master':
798 # master trumps all other branches
823 # master trumps all other branches
799 checkout(['refs/heads/master'])
824 checkout(['refs/heads/master'])
800 return
825 return
801 if not firstlocalbranch and not b.startswith('refs/remotes/'):
826 if not firstlocalbranch and not b.startswith('refs/remotes/'):
802 firstlocalbranch = b
827 firstlocalbranch = b
803 if firstlocalbranch:
828 if firstlocalbranch:
804 checkout([firstlocalbranch])
829 checkout([firstlocalbranch])
805 return
830 return
806
831
807 tracking = self._gittracking(branch2rev.keys())
832 tracking = self._gittracking(branch2rev.keys())
808 # choose a remote branch already tracked if possible
833 # choose a remote branch already tracked if possible
809 remote = branches[0]
834 remote = branches[0]
810 if remote not in tracking:
835 if remote not in tracking:
811 for b in branches:
836 for b in branches:
812 if b in tracking:
837 if b in tracking:
813 remote = b
838 remote = b
814 break
839 break
815
840
816 if remote not in tracking:
841 if remote not in tracking:
817 # create a new local tracking branch
842 # create a new local tracking branch
818 local = remote.split('/', 2)[2]
843 local = remote.split('/', 2)[2]
819 checkout(['-b', local, remote])
844 checkout(['-b', local, remote])
820 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
845 elif self._gitisancestor(branch2rev[tracking[remote]], remote):
821 # When updating to a tracked remote branch,
846 # When updating to a tracked remote branch,
822 # if the local tracking branch is downstream of it,
847 # if the local tracking branch is downstream of it,
823 # a normal `git pull` would have performed a "fast-forward merge"
848 # a normal `git pull` would have performed a "fast-forward merge"
824 # which is equivalent to updating the local branch to the remote.
849 # which is equivalent to updating the local branch to the remote.
825 # Since we are only looking at branching at update, we need to
850 # Since we are only looking at branching at update, we need to
826 # detect this situation and perform this action lazily.
851 # detect this situation and perform this action lazily.
827 if tracking[remote] != self._gitcurrentbranch():
852 if tracking[remote] != self._gitcurrentbranch():
828 checkout([tracking[remote]])
853 checkout([tracking[remote]])
829 self._gitcommand(['merge', '--ff', remote])
854 self._gitcommand(['merge', '--ff', remote])
830 else:
855 else:
831 # a real merge would be required, just checkout the revision
856 # a real merge would be required, just checkout the revision
832 rawcheckout()
857 rawcheckout()
833
858
834 def commit(self, text, user, date):
859 def commit(self, text, user, date):
835 cmd = ['commit', '-a', '-m', text]
860 cmd = ['commit', '-a', '-m', text]
836 env = os.environ.copy()
861 env = os.environ.copy()
837 if user:
862 if user:
838 cmd += ['--author', user]
863 cmd += ['--author', user]
839 if date:
864 if date:
840 # git's date parser silently ignores when seconds < 1e9
865 # git's date parser silently ignores when seconds < 1e9
841 # convert to ISO8601
866 # convert to ISO8601
842 env['GIT_AUTHOR_DATE'] = util.datestr(date,
867 env['GIT_AUTHOR_DATE'] = util.datestr(date,
843 '%Y-%m-%dT%H:%M:%S %1%2')
868 '%Y-%m-%dT%H:%M:%S %1%2')
844 self._gitcommand(cmd, env=env)
869 self._gitcommand(cmd, env=env)
845 # make sure commit works otherwise HEAD might not exist under certain
870 # make sure commit works otherwise HEAD might not exist under certain
846 # circumstances
871 # circumstances
847 return self._gitstate()
872 return self._gitstate()
848
873
849 def merge(self, state):
874 def merge(self, state):
850 source, revision, kind = state
875 source, revision, kind = state
851 self._fetch(source, revision)
876 self._fetch(source, revision)
852 base = self._gitcommand(['merge-base', revision, self._state[1]])
877 base = self._gitcommand(['merge-base', revision, self._state[1]])
853 if base == revision:
878 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD'])
854 self.get(state) # fast forward merge
879
855 elif base != self._state[1]:
880 def mergefunc():
856 self._gitcommand(['merge', '--no-commit', revision])
881 if base == revision:
882 self.get(state) # fast forward merge
883 elif base != self._state[1]:
884 self._gitcommand(['merge', '--no-commit', revision])
885
886 if self.dirty():
887 if self._gitstate() != revision:
888 dirty = self._gitstate() == self._state[1] or code != 0
889 if _updateprompt(self._ui, self, dirty, self._state[1], revision):
890 mergefunc()
891 else:
892 mergefunc()
857
893
858 def push(self, force):
894 def push(self, force):
859 # if a branch in origin contains the revision, nothing to do
895 # if a branch in origin contains the revision, nothing to do
860 branch2rev, rev2branch = self._gitbranchmap()
896 branch2rev, rev2branch = self._gitbranchmap()
861 if self._state[1] in rev2branch:
897 if self._state[1] in rev2branch:
862 for b in rev2branch[self._state[1]]:
898 for b in rev2branch[self._state[1]]:
863 if b.startswith('refs/remotes/origin/'):
899 if b.startswith('refs/remotes/origin/'):
864 return True
900 return True
865 for b, revision in branch2rev.iteritems():
901 for b, revision in branch2rev.iteritems():
866 if b.startswith('refs/remotes/origin/'):
902 if b.startswith('refs/remotes/origin/'):
867 if self._gitisancestor(self._state[1], revision):
903 if self._gitisancestor(self._state[1], revision):
868 return True
904 return True
869 # otherwise, try to push the currently checked out branch
905 # otherwise, try to push the currently checked out branch
870 cmd = ['push']
906 cmd = ['push']
871 if force:
907 if force:
872 cmd.append('--force')
908 cmd.append('--force')
873
909
874 current = self._gitcurrentbranch()
910 current = self._gitcurrentbranch()
875 if current:
911 if current:
876 # determine if the current branch is even useful
912 # determine if the current branch is even useful
877 if not self._gitisancestor(self._state[1], current):
913 if not self._gitisancestor(self._state[1], current):
878 self._ui.warn(_('unrelated git branch checked out '
914 self._ui.warn(_('unrelated git branch checked out '
879 'in subrepo %s\n') % self._relpath)
915 'in subrepo %s\n') % self._relpath)
880 return False
916 return False
881 self._ui.status(_('pushing branch %s of subrepo %s\n') %
917 self._ui.status(_('pushing branch %s of subrepo %s\n') %
882 (current.split('/', 2)[2], self._relpath))
918 (current.split('/', 2)[2], self._relpath))
883 self._gitcommand(cmd + ['origin', current])
919 self._gitcommand(cmd + ['origin', current])
884 return True
920 return True
885 else:
921 else:
886 self._ui.warn(_('no branch checked out in subrepo %s\n'
922 self._ui.warn(_('no branch checked out in subrepo %s\n'
887 'cannot push revision %s') %
923 'cannot push revision %s') %
888 (self._relpath, self._state[1]))
924 (self._relpath, self._state[1]))
889 return False
925 return False
890
926
891 def remove(self):
927 def remove(self):
892 if self.dirty():
928 if self.dirty():
893 self._ui.warn(_('not removing repo %s because '
929 self._ui.warn(_('not removing repo %s because '
894 'it has changes.\n') % self._relpath)
930 'it has changes.\n') % self._relpath)
895 return
931 return
896 # we can't fully delete the repository as it may contain
932 # we can't fully delete the repository as it may contain
897 # local-only history
933 # local-only history
898 self._ui.note(_('removing subrepo %s\n') % self._relpath)
934 self._ui.note(_('removing subrepo %s\n') % self._relpath)
899 self._gitcommand(['config', 'core.bare', 'true'])
935 self._gitcommand(['config', 'core.bare', 'true'])
900 for f in os.listdir(self._abspath):
936 for f in os.listdir(self._abspath):
901 if f == '.git':
937 if f == '.git':
902 continue
938 continue
903 path = os.path.join(self._abspath, f)
939 path = os.path.join(self._abspath, f)
904 if os.path.isdir(path) and not os.path.islink(path):
940 if os.path.isdir(path) and not os.path.islink(path):
905 shutil.rmtree(path)
941 shutil.rmtree(path)
906 else:
942 else:
907 os.remove(path)
943 os.remove(path)
908
944
909 def archive(self, ui, archiver, prefix):
945 def archive(self, ui, archiver, prefix):
910 source, revision = self._state
946 source, revision = self._state
911 self._fetch(source, revision)
947 self._fetch(source, revision)
912
948
913 # Parse git's native archive command.
949 # Parse git's native archive command.
914 # This should be much faster than manually traversing the trees
950 # This should be much faster than manually traversing the trees
915 # and objects with many subprocess calls.
951 # and objects with many subprocess calls.
916 tarstream = self._gitcommand(['archive', revision], stream=True)
952 tarstream = self._gitcommand(['archive', revision], stream=True)
917 tar = tarfile.open(fileobj=tarstream, mode='r|')
953 tar = tarfile.open(fileobj=tarstream, mode='r|')
918 relpath = subrelpath(self)
954 relpath = subrelpath(self)
919 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
955 ui.progress(_('archiving (%s)') % relpath, 0, unit=_('files'))
920 for i, info in enumerate(tar):
956 for i, info in enumerate(tar):
921 if info.isdir():
957 if info.isdir():
922 continue
958 continue
923 if info.issym():
959 if info.issym():
924 data = info.linkname
960 data = info.linkname
925 else:
961 else:
926 data = tar.extractfile(info).read()
962 data = tar.extractfile(info).read()
927 archiver.addfile(os.path.join(prefix, self._path, info.name),
963 archiver.addfile(os.path.join(prefix, self._path, info.name),
928 info.mode, info.issym(), data)
964 info.mode, info.issym(), data)
929 ui.progress(_('archiving (%s)') % relpath, i + 1,
965 ui.progress(_('archiving (%s)') % relpath, i + 1,
930 unit=_('files'))
966 unit=_('files'))
931 ui.progress(_('archiving (%s)') % relpath, None)
967 ui.progress(_('archiving (%s)') % relpath, None)
932
968
933
969
934 def status(self, rev2, **opts):
970 def status(self, rev2, **opts):
935 rev1 = self._state[1]
971 rev1 = self._state[1]
936 modified, added, removed = [], [], []
972 modified, added, removed = [], [], []
937 if rev2:
973 if rev2:
938 command = ['diff-tree', rev1, rev2]
974 command = ['diff-tree', rev1, rev2]
939 else:
975 else:
940 command = ['diff-index', rev1]
976 command = ['diff-index', rev1]
941 out = self._gitcommand(command)
977 out = self._gitcommand(command)
942 for line in out.split('\n'):
978 for line in out.split('\n'):
943 tab = line.find('\t')
979 tab = line.find('\t')
944 if tab == -1:
980 if tab == -1:
945 continue
981 continue
946 status, f = line[tab - 1], line[tab + 1:]
982 status, f = line[tab - 1], line[tab + 1:]
947 if status == 'M':
983 if status == 'M':
948 modified.append(f)
984 modified.append(f)
949 elif status == 'A':
985 elif status == 'A':
950 added.append(f)
986 added.append(f)
951 elif status == 'D':
987 elif status == 'D':
952 removed.append(f)
988 removed.append(f)
953
989
954 deleted = unknown = ignored = clean = []
990 deleted = unknown = ignored = clean = []
955 return modified, added, removed, deleted, unknown, ignored, clean
991 return modified, added, removed, deleted, unknown, ignored, clean
956
992
957 types = {
993 types = {
958 'hg': hgsubrepo,
994 'hg': hgsubrepo,
959 'svn': svnsubrepo,
995 'svn': svnsubrepo,
960 'git': gitsubrepo,
996 'git': gitsubrepo,
961 }
997 }
@@ -1,331 +1,445 b''
1 $ "$TESTDIR/hghave" git || exit 80
1 $ "$TESTDIR/hghave" git || exit 80
2
2
3 make git commits repeatable
3 make git commits repeatable
4
4
5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
5 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
6 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
7 $ GIT_AUTHOR_DATE='1234567891 +0000'; export GIT_AUTHOR_DATE
8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
8 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
9 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
10 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
11
11
12 root hg repo
12 root hg repo
13
13
14 $ hg init t
14 $ hg init t
15 $ cd t
15 $ cd t
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 $ cd ..
19 $ cd ..
20
20
21 new external git repo
21 new external git repo
22
22
23 $ mkdir gitroot
23 $ mkdir gitroot
24 $ cd gitroot
24 $ cd gitroot
25 $ git init -q
25 $ git init -q
26 $ echo g > g
26 $ echo g > g
27 $ git add g
27 $ git add g
28 $ git commit -q -m g
28 $ git commit -q -m g
29
29
30 add subrepo clone
30 add subrepo clone
31
31
32 $ cd ../t
32 $ cd ../t
33 $ echo 's = [git]../gitroot' > .hgsub
33 $ echo 's = [git]../gitroot' > .hgsub
34 $ git clone -q ../gitroot s
34 $ git clone -q ../gitroot s
35 $ hg add .hgsub
35 $ hg add .hgsub
36 $ hg commit -m 'new git subrepo'
36 $ hg commit -m 'new git subrepo'
37 committing subrepository s
37 committing subrepository s
38 $ hg debugsub
38 $ hg debugsub
39 path s
39 path s
40 source ../gitroot
40 source ../gitroot
41 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
41 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
42
42
43 record a new commit from upstream from a different branch
43 record a new commit from upstream from a different branch
44
44
45 $ cd ../gitroot
45 $ cd ../gitroot
46 $ git checkout -q -b testing
46 $ git checkout -q -b testing
47 $ echo gg >> g
47 $ echo gg >> g
48 $ git commit -q -a -m gg
48 $ git commit -q -a -m gg
49
49
50 $ cd ../t/s
50 $ cd ../t/s
51 $ git pull -q >/dev/null 2>/dev/null
51 $ git pull -q >/dev/null 2>/dev/null
52 $ git checkout -q -b testing origin/testing >/dev/null
52 $ git checkout -q -b testing origin/testing >/dev/null
53
53
54 $ cd ..
54 $ cd ..
55 $ hg status --subrepos
55 $ hg status --subrepos
56 M s/g
56 M s/g
57 $ hg commit -m 'update git subrepo'
57 $ hg commit -m 'update git subrepo'
58 committing subrepository s
58 committing subrepository s
59 $ hg debugsub
59 $ hg debugsub
60 path s
60 path s
61 source ../gitroot
61 source ../gitroot
62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
62 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
63
63
64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
64 make $GITROOT pushable, by replacing it with a clone with nothing checked out
65
65
66 $ cd ..
66 $ cd ..
67 $ git clone gitroot gitrootbare --bare -q
67 $ git clone gitroot gitrootbare --bare -q
68 $ rm -rf gitroot
68 $ rm -rf gitroot
69 $ mv gitrootbare gitroot
69 $ mv gitrootbare gitroot
70
70
71 clone root
71 clone root
72
72
73 $ cd t
73 $ cd t
74 $ hg clone . ../tc
74 $ hg clone . ../tc
75 updating to branch default
75 updating to branch default
76 cloning subrepo s
76 cloning subrepo s
77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ cd ../tc
78 $ cd ../tc
79 $ hg debugsub
79 $ hg debugsub
80 path s
80 path s
81 source ../gitroot
81 source ../gitroot
82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
82 revision 126f2a14290cd5ce061fdedc430170e8d39e1c5a
83
83
84 update to previous substate
84 update to previous substate
85
85
86 $ hg update 1 -q
86 $ hg update 1 -q
87 $ cat s/g
87 $ cat s/g
88 g
88 g
89 $ hg debugsub
89 $ hg debugsub
90 path s
90 path s
91 source ../gitroot
91 source ../gitroot
92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
92 revision da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
93
93
94 clone root, make local change
94 clone root, make local change
95
95
96 $ cd ../t
96 $ cd ../t
97 $ hg clone . ../ta
97 $ hg clone . ../ta
98 updating to branch default
98 updating to branch default
99 cloning subrepo s
99 cloning subrepo s
100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
101
101
102 $ cd ../ta
102 $ cd ../ta
103 $ echo ggg >> s/g
103 $ echo ggg >> s/g
104 $ hg status --subrepos
104 $ hg status --subrepos
105 M s/g
105 M s/g
106 $ hg commit -m ggg
106 $ hg commit -m ggg
107 committing subrepository s
107 committing subrepository s
108 $ hg debugsub
108 $ hg debugsub
109 path s
109 path s
110 source ../gitroot
110 source ../gitroot
111 revision 79695940086840c99328513acbe35f90fcd55e57
111 revision 79695940086840c99328513acbe35f90fcd55e57
112
112
113 clone root separately, make different local change
113 clone root separately, make different local change
114
114
115 $ cd ../t
115 $ cd ../t
116 $ hg clone . ../tb
116 $ hg clone . ../tb
117 updating to branch default
117 updating to branch default
118 cloning subrepo s
118 cloning subrepo s
119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120
120
121 $ cd ../tb/s
121 $ cd ../tb/s
122 $ echo f > f
122 $ echo f > f
123 $ git add f
123 $ git add f
124 $ cd ..
124 $ cd ..
125
125
126 $ hg status --subrepos
126 $ hg status --subrepos
127 A s/f
127 A s/f
128 $ hg commit -m f
128 $ hg commit -m f
129 committing subrepository s
129 committing subrepository s
130 $ hg debugsub
130 $ hg debugsub
131 path s
131 path s
132 source ../gitroot
132 source ../gitroot
133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
133 revision aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
134
134
135 user b push changes
135 user b push changes
136
136
137 $ hg push 2>/dev/null
137 $ hg push 2>/dev/null
138 pushing to $TESTTMP/t
138 pushing to $TESTTMP/t
139 pushing branch testing of subrepo s
139 pushing branch testing of subrepo s
140 searching for changes
140 searching for changes
141 adding changesets
141 adding changesets
142 adding manifests
142 adding manifests
143 adding file changes
143 adding file changes
144 added 1 changesets with 1 changes to 1 files
144 added 1 changesets with 1 changes to 1 files
145
145
146 user a pulls, merges, commits
146 user a pulls, merges, commits
147
147
148 $ cd ../ta
148 $ cd ../ta
149 $ hg pull
149 $ hg pull
150 pulling from $TESTTMP/t
150 pulling from $TESTTMP/t
151 searching for changes
151 searching for changes
152 adding changesets
152 adding changesets
153 adding manifests
153 adding manifests
154 adding file changes
154 adding file changes
155 added 1 changesets with 1 changes to 1 files (+1 heads)
155 added 1 changesets with 1 changes to 1 files (+1 heads)
156 (run 'hg heads' to see heads, 'hg merge' to merge)
156 (run 'hg heads' to see heads, 'hg merge' to merge)
157 $ hg merge 2>/dev/null
157 $ hg merge 2>/dev/null
158 pulling subrepo s
158 pulling subrepo s
159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
159 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 (branch merge, don't forget to commit)
160 (branch merge, don't forget to commit)
161 $ cat s/f
161 $ cat s/f
162 f
162 f
163 $ cat s/g
163 $ cat s/g
164 g
164 g
165 gg
165 gg
166 ggg
166 ggg
167 $ hg commit -m 'merge'
167 $ hg commit -m 'merge'
168 committing subrepository s
168 committing subrepository s
169 $ hg status --subrepos --rev 1:5
169 $ hg status --subrepos --rev 1:5
170 M .hgsubstate
170 M .hgsubstate
171 M s/g
171 M s/g
172 A s/f
172 A s/f
173 $ hg debugsub
173 $ hg debugsub
174 path s
174 path s
175 source ../gitroot
175 source ../gitroot
176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
176 revision f47b465e1bce645dbf37232a00574aa1546ca8d3
177 $ hg push 2>/dev/null
177 $ hg push 2>/dev/null
178 pushing to $TESTTMP/t
178 pushing to $TESTTMP/t
179 pushing branch testing of subrepo s
179 pushing branch testing of subrepo s
180 searching for changes
180 searching for changes
181 adding changesets
181 adding changesets
182 adding manifests
182 adding manifests
183 adding file changes
183 adding file changes
184 added 2 changesets with 2 changes to 1 files
184 added 2 changesets with 2 changes to 1 files
185
185
186 make upstream git changes
186 make upstream git changes
187
187
188 $ cd ..
188 $ cd ..
189 $ git clone -q gitroot gitclone
189 $ git clone -q gitroot gitclone
190 $ cd gitclone
190 $ cd gitclone
191 $ echo ff >> f
191 $ echo ff >> f
192 $ git commit -q -a -m ff
192 $ git commit -q -a -m ff
193 $ echo fff >> f
193 $ echo fff >> f
194 $ git commit -q -a -m fff
194 $ git commit -q -a -m fff
195 $ git push origin testing 2>/dev/null
195 $ git push origin testing 2>/dev/null
196
196
197 make and push changes to hg without updating the subrepo
197 make and push changes to hg without updating the subrepo
198
198
199 $ cd ../t
199 $ cd ../t
200 $ hg clone . ../td
200 $ hg clone . ../td
201 updating to branch default
201 updating to branch default
202 cloning subrepo s
202 cloning subrepo s
203 checking out detached HEAD in subrepo s
203 checking out detached HEAD in subrepo s
204 check out a git branch if you intend to make changes
204 check out a git branch if you intend to make changes
205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
205 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 $ cd ../td
206 $ cd ../td
207 $ echo aa >> a
207 $ echo aa >> a
208 $ hg commit -m aa
208 $ hg commit -m aa
209 $ hg push
209 $ hg push
210 pushing to $TESTTMP/t
210 pushing to $TESTTMP/t
211 searching for changes
211 searching for changes
212 adding changesets
212 adding changesets
213 adding manifests
213 adding manifests
214 adding file changes
214 adding file changes
215 added 1 changesets with 1 changes to 1 files
215 added 1 changesets with 1 changes to 1 files
216
216
217 sync to upstream git, distribute changes
217 sync to upstream git, distribute changes
218
218
219 $ cd ../ta
219 $ cd ../ta
220 $ hg pull -u -q
220 $ hg pull -u -q
221 $ cd s
221 $ cd s
222 $ git pull -q >/dev/null 2>/dev/null
222 $ git pull -q >/dev/null 2>/dev/null
223 $ cd ..
223 $ cd ..
224 $ hg commit -m 'git upstream sync'
224 $ hg commit -m 'git upstream sync'
225 committing subrepository s
225 committing subrepository s
226 $ hg debugsub
226 $ hg debugsub
227 path s
227 path s
228 source ../gitroot
228 source ../gitroot
229 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
229 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
230 $ hg push -q
230 $ hg push -q
231
231
232 $ cd ../tb
232 $ cd ../tb
233 $ hg pull -q
233 $ hg pull -q
234 $ hg update 2>/dev/null
234 $ hg update 2>/dev/null
235 pulling subrepo s
235 pulling subrepo s
236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 $ hg debugsub
237 $ hg debugsub
238 path s
238 path s
239 source ../gitroot
239 source ../gitroot
240 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
240 revision 32a343883b74769118bb1d3b4b1fbf9156f4dddc
241
241
242 update to a revision without the subrepo, keeping the local git repository
242 update to a revision without the subrepo, keeping the local git repository
243
243
244 $ cd ../t
244 $ cd ../t
245 $ hg up 0
245 $ hg up 0
246 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
246 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
247 $ ls -a s
247 $ ls -a s
248 .
248 .
249 ..
249 ..
250 .git
250 .git
251
251
252 $ hg up 2
252 $ hg up 2
253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 $ ls -a s
254 $ ls -a s
255 .
255 .
256 ..
256 ..
257 .git
257 .git
258 g
258 g
259
259
260 archive subrepos
260 archive subrepos
261
261
262 $ cd ../tc
262 $ cd ../tc
263 $ hg pull -q
263 $ hg pull -q
264 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
264 $ hg archive --subrepos -r 5 ../archive 2>/dev/null
265 pulling subrepo s
265 pulling subrepo s
266 $ cd ../archive
266 $ cd ../archive
267 $ cat s/f
267 $ cat s/f
268 f
268 f
269 $ cat s/g
269 $ cat s/g
270 g
270 g
271 gg
271 gg
272 ggg
272 ggg
273
273
274 create nested repo
274 create nested repo
275
275
276 $ cd ..
276 $ cd ..
277 $ hg init outer
277 $ hg init outer
278 $ cd outer
278 $ cd outer
279 $ echo b>b
279 $ echo b>b
280 $ hg add b
280 $ hg add b
281 $ hg commit -m b
281 $ hg commit -m b
282
282
283 $ hg clone ../t inner
283 $ hg clone ../t inner
284 updating to branch default
284 updating to branch default
285 cloning subrepo s
285 cloning subrepo s
286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 $ echo inner = inner > .hgsub
287 $ echo inner = inner > .hgsub
288 $ hg add .hgsub
288 $ hg add .hgsub
289 $ hg commit -m 'nested sub'
289 $ hg commit -m 'nested sub'
290 committing subrepository inner
290 committing subrepository inner
291
291
292 nested commit
292 nested commit
293
293
294 $ echo ffff >> inner/s/f
294 $ echo ffff >> inner/s/f
295 $ hg status --subrepos
295 $ hg status --subrepos
296 M inner/s/f
296 M inner/s/f
297 $ hg commit -m nested
297 $ hg commit -m nested
298 committing subrepository inner
298 committing subrepository inner
299 committing subrepository inner/s
299 committing subrepository inner/s
300
300
301 nested archive
301 nested archive
302
302
303 $ hg archive --subrepos ../narchive
303 $ hg archive --subrepos ../narchive
304 $ ls ../narchive/inner/s | grep -v pax_global_header
304 $ ls ../narchive/inner/s | grep -v pax_global_header
305 f
305 f
306 g
306 g
307
307
308 Check hg update --clean
308 Check hg update --clean
309 $ cd $TESTTMP/ta
309 $ cd $TESTTMP/ta
310 $ echo > s/g
310 $ echo > s/g
311 $ cd s
311 $ cd s
312 $ echo c1 > f1
312 $ echo c1 > f1
313 $ echo c1 > f2
313 $ echo c1 > f2
314 $ git add f1
314 $ git add f1
315 $ cd ..
315 $ cd ..
316 $ hg status -S
316 $ hg status -S
317 M s/g
317 M s/g
318 A s/f1
318 A s/f1
319 $ ls s
319 $ ls s
320 f
320 f
321 f1
321 f1
322 f2
322 f2
323 g
323 g
324 $ hg update --clean
324 $ hg update --clean
325 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
325 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
326 $ hg status -S
326 $ hg status -S
327 $ ls s
327 $ ls s
328 f
328 f
329 f1
329 f1
330 f2
330 f2
331 g
331 g
332
333 Sticky subrepositories, no changes
334 $ cd $TESTTMP/ta
335 $ hg id -n
336 7
337 $ cd s
338 $ git rev-parse HEAD
339 32a343883b74769118bb1d3b4b1fbf9156f4dddc
340 $ cd ..
341 $ hg update 1 > /dev/null 2>&1
342 $ hg id -n
343 1
344 $ cd s
345 $ git rev-parse HEAD
346 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
347 $ cd ..
348
349 Sticky subrepositorys, file changes
350 $ touch s/f1
351 $ cd s
352 $ git add f1
353 $ cd ..
354 $ hg id -n
355 1
356 $ cd s
357 $ git rev-parse HEAD
358 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
359 $ cd ..
360 $ hg update 4
361 subrepository sources for s differ
362 use (l)ocal source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7) or (r)emote source (aa84837ccfbdfedcdcdeeedc309d73e6eb069edc)?
363 l
364 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 $ hg id -n
366 4+
367 $ cd s
368 $ git rev-parse HEAD
369 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
370 $ cd ..
371 $ hg update --clean tip > /dev/null 2>&1
372
373 Sticky subrepository, revision updates
374 $ hg id -n
375 7
376 $ cd s
377 $ git rev-parse HEAD
378 32a343883b74769118bb1d3b4b1fbf9156f4dddc
379 $ cd ..
380 $ cd s
381 $ git checkout aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
382 Previous HEAD position was 32a3438... fff
383 HEAD is now at aa84837... f
384 $ cd ..
385 $ hg update 1
386 subrepository sources for s differ (in checked out version)
387 use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7)?
388 l
389 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
390 $ hg id -n
391 1+
392 $ cd s
393 $ git rev-parse HEAD
394 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
395 $ cd ..
396
397 Sticky subrepository, file changes and revision updates
398 $ touch s/f1
399 $ cd s
400 $ git add f1
401 $ git rev-parse HEAD
402 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
403 $ cd ..
404 $ hg id -n
405 1+
406 $ hg update 7
407 subrepository sources for s differ
408 use (l)ocal source (32a343883b74769118bb1d3b4b1fbf9156f4dddc) or (r)emote source (32a343883b74769118bb1d3b4b1fbf9156f4dddc)?
409 l
410 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
411 $ hg id -n
412 7
413 $ cd s
414 $ git rev-parse HEAD
415 aa84837ccfbdfedcdcdeeedc309d73e6eb069edc
416 $ cd ..
417
418 Sticky repository, update --clean
419 $ hg update --clean tip
420 Previous HEAD position was aa84837... f
421 HEAD is now at 32a3438... fff
422 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 $ hg id -n
424 7
425 $ cd s
426 $ git rev-parse HEAD
427 32a343883b74769118bb1d3b4b1fbf9156f4dddc
428 $ cd ..
429
430 Test subrepo already at intended revision:
431 $ cd s
432 $ git checkout 32a343883b74769118bb1d3b4b1fbf9156f4dddc
433 HEAD is now at 32a3438... fff
434 $ cd ..
435 $ hg update 1
436 Previous HEAD position was 32a3438... fff
437 HEAD is now at da5f5b1... g
438 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
439 $ hg id -n
440 1
441 $ cd s
442 $ git rev-parse HEAD
443 da5f5b1d8ffcf62fb8327bcd3c89a4367a6018e7
444 $ cd ..
445
@@ -1,298 +1,440 b''
1 $ "$TESTDIR/hghave" svn || exit 80
1 $ "$TESTDIR/hghave" svn || exit 80
2
2
3 $ fix_path()
3 $ fix_path()
4 > {
4 > {
5 > tr '\\' /
5 > tr '\\' /
6 > }
6 > }
7
7
8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
8 SVN wants all paths to start with a slash. Unfortunately, Windows ones
9 don't. Handle that.
9 don't. Handle that.
10
10
11 $ escapedwd=`pwd | fix_path`
11 $ escapedwd=`pwd | fix_path`
12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
12 $ expr "$escapedwd" : '\/' > /dev/null || escapedwd="/$escapedwd"
13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
13 $ escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
14
14
15 create subversion repo
15 create subversion repo
16
16
17 $ SVNREPO="file://$escapedwd/svn-repo"
17 $ SVNREPO="file://$escapedwd/svn-repo"
18 $ WCROOT="`pwd`/svn-wc"
18 $ WCROOT="`pwd`/svn-wc"
19 $ svnadmin create svn-repo
19 $ svnadmin create svn-repo
20 $ svn co "$SVNREPO" svn-wc
20 $ svn co "$SVNREPO" svn-wc
21 Checked out revision 0.
21 Checked out revision 0.
22 $ cd svn-wc
22 $ cd svn-wc
23 $ mkdir src
23 $ mkdir src
24 $ echo alpha > src/alpha
24 $ echo alpha > src/alpha
25 $ svn add src
25 $ svn add src
26 A src
26 A src
27 A src/alpha
27 A src/alpha
28 $ mkdir externals
28 $ mkdir externals
29 $ echo other > externals/other
29 $ echo other > externals/other
30 $ svn add externals
30 $ svn add externals
31 A externals
31 A externals
32 A externals/other
32 A externals/other
33 $ svn ci -m 'Add alpha'
33 $ svn ci -m 'Add alpha'
34 Adding externals
34 Adding externals
35 Adding externals/other
35 Adding externals/other
36 Adding src
36 Adding src
37 Adding src/alpha
37 Adding src/alpha
38 Transmitting file data ..
38 Transmitting file data ..
39 Committed revision 1.
39 Committed revision 1.
40 $ svn up
40 $ svn up
41 At revision 1.
41 At revision 1.
42 $ echo "externals -r1 $SVNREPO/externals" > extdef
42 $ echo "externals -r1 $SVNREPO/externals" > extdef
43 $ svn propset -F extdef svn:externals src
43 $ svn propset -F extdef svn:externals src
44 property 'svn:externals' set on 'src'
44 property 'svn:externals' set on 'src'
45 $ svn ci -m 'Setting externals'
45 $ svn ci -m 'Setting externals'
46 Sending src
46 Sending src
47
47
48 Committed revision 2.
48 Committed revision 2.
49 $ cd ..
49 $ cd ..
50
50
51 create hg repo
51 create hg repo
52
52
53 $ mkdir sub
53 $ mkdir sub
54 $ cd sub
54 $ cd sub
55 $ hg init t
55 $ hg init t
56 $ cd t
56 $ cd t
57
57
58 first revision, no sub
58 first revision, no sub
59
59
60 $ echo a > a
60 $ echo a > a
61 $ hg ci -Am0
61 $ hg ci -Am0
62 adding a
62 adding a
63
63
64 add first svn sub with leading whitespaces
64 add first svn sub with leading whitespaces
65
65
66 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
66 $ echo "s = [svn] $SVNREPO/src" >> .hgsub
67 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
67 $ echo "subdir/s = [svn] $SVNREPO/src" >> .hgsub
68 $ svn co --quiet "$SVNREPO"/src s
68 $ svn co --quiet "$SVNREPO"/src s
69 $ mkdir subdir
69 $ mkdir subdir
70 $ svn co --quiet "$SVNREPO"/src subdir/s
70 $ svn co --quiet "$SVNREPO"/src subdir/s
71 $ hg add .hgsub
71 $ hg add .hgsub
72 $ hg ci -m1
72 $ hg ci -m1
73 committing subrepository s
73 committing subrepository s
74 committing subrepository subdir/s
74 committing subrepository subdir/s
75
75
76 make sure we avoid empty commits (issue2445)
76 make sure we avoid empty commits (issue2445)
77
77
78 $ hg sum
78 $ hg sum
79 parent: 1:* tip (glob)
79 parent: 1:* tip (glob)
80 1
80 1
81 branch: default
81 branch: default
82 commit: (clean)
82 commit: (clean)
83 update: (current)
83 update: (current)
84 $ hg ci -moops
84 $ hg ci -moops
85 nothing changed
85 nothing changed
86 [1]
86 [1]
87
87
88 debugsub
88 debugsub
89
89
90 $ hg debugsub
90 $ hg debugsub
91 path s
91 path s
92 source file://*/svn-repo/src (glob)
92 source file://*/svn-repo/src (glob)
93 revision 2
93 revision 2
94 path subdir/s
94 path subdir/s
95 source file://*/svn-repo/src (glob)
95 source file://*/svn-repo/src (glob)
96 revision 2
96 revision 2
97
97
98 change file in svn and hg, commit
98 change file in svn and hg, commit
99
99
100 $ echo a >> a
100 $ echo a >> a
101 $ echo alpha >> s/alpha
101 $ echo alpha >> s/alpha
102 $ hg sum
102 $ hg sum
103 parent: 1:* tip (glob)
103 parent: 1:* tip (glob)
104 1
104 1
105 branch: default
105 branch: default
106 commit: 1 modified, 1 subrepos
106 commit: 1 modified, 1 subrepos
107 update: (current)
107 update: (current)
108 $ hg commit -m 'Message!'
108 $ hg commit -m 'Message!'
109 committing subrepository s
109 committing subrepository s
110 Sending*s/alpha (glob)
110 Sending*s/alpha (glob)
111 Transmitting file data .
111 Transmitting file data .
112 Committed revision 3.
112 Committed revision 3.
113
113
114 Fetching external item into '$TESTTMP/sub/t/s/externals'
114 Fetching external item into '$TESTTMP/sub/t/s/externals'
115 External at revision 1.
115 External at revision 1.
116
116
117 At revision 3.
117 At revision 3.
118 $ hg debugsub
118 $ hg debugsub
119 path s
119 path s
120 source file://*/svn-repo/src (glob)
120 source file://*/svn-repo/src (glob)
121 revision 3
121 revision 3
122 path subdir/s
122 path subdir/s
123 source file://*/svn-repo/src (glob)
123 source file://*/svn-repo/src (glob)
124 revision 2
124 revision 2
125
125
126 add an unrelated revision in svn and update the subrepo to without
126 add an unrelated revision in svn and update the subrepo to without
127 bringing any changes.
127 bringing any changes.
128
128
129 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
129 $ svn mkdir "$SVNREPO/unrelated" -m 'create unrelated'
130
130
131 Committed revision 4.
131 Committed revision 4.
132 $ svn up s
132 $ svn up s
133
133
134 Fetching external item into 's/externals'
134 Fetching external item into 's/externals'
135 External at revision 1.
135 External at revision 1.
136
136
137 At revision 4.
137 At revision 4.
138 $ hg sum
138 $ hg sum
139 parent: 2:* tip (glob)
139 parent: 2:* tip (glob)
140 Message!
140 Message!
141 branch: default
141 branch: default
142 commit: (clean)
142 commit: (clean)
143 update: (current)
143 update: (current)
144
144
145 $ echo a > s/a
145 $ echo a > s/a
146
146
147 should be empty despite change to s/a
147 should be empty despite change to s/a
148
148
149 $ hg st
149 $ hg st
150
150
151 add a commit from svn
151 add a commit from svn
152
152
153 $ cd "$WCROOT"/src
153 $ cd "$WCROOT"/src
154 $ svn up
154 $ svn up
155 U alpha
155 U alpha
156
156
157 Fetching external item into 'externals'
157 Fetching external item into 'externals'
158 A externals/other
158 A externals/other
159 Updated external to revision 1.
159 Updated external to revision 1.
160
160
161 Updated to revision 4.
161 Updated to revision 4.
162 $ echo xyz >> alpha
162 $ echo xyz >> alpha
163 $ svn propset svn:mime-type 'text/xml' alpha
163 $ svn propset svn:mime-type 'text/xml' alpha
164 property 'svn:mime-type' set on 'alpha'
164 property 'svn:mime-type' set on 'alpha'
165 $ svn ci -m 'amend a from svn'
165 $ svn ci -m 'amend a from svn'
166 Sending src/alpha
166 Sending src/alpha
167 Transmitting file data .
167 Transmitting file data .
168 Committed revision 5.
168 Committed revision 5.
169 $ cd ../../sub/t
169 $ cd ../../sub/t
170
170
171 this commit from hg will fail
171 this commit from hg will fail
172
172
173 $ echo zzz >> s/alpha
173 $ echo zzz >> s/alpha
174 $ hg ci -m 'amend alpha from hg'
174 $ hg ci -m 'amend alpha from hg'
175 committing subrepository s
175 committing subrepository s
176 abort: svn: Commit failed (details follow):
176 abort: svn: Commit failed (details follow):
177 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
177 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
178 [255]
178 [255]
179 $ svn revert -q s/alpha
179 $ svn revert -q s/alpha
180
180
181 this commit fails because of meta changes
181 this commit fails because of meta changes
182
182
183 $ svn propset svn:mime-type 'text/html' s/alpha
183 $ svn propset svn:mime-type 'text/html' s/alpha
184 property 'svn:mime-type' set on 's/alpha'
184 property 'svn:mime-type' set on 's/alpha'
185 $ hg ci -m 'amend alpha from hg'
185 $ hg ci -m 'amend alpha from hg'
186 committing subrepository s
186 committing subrepository s
187 abort: svn: Commit failed (details follow):
187 abort: svn: Commit failed (details follow):
188 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
188 svn: (Out of date)?.*/src/alpha.*(is out of date)? (re)
189 [255]
189 [255]
190 $ svn revert -q s/alpha
190 $ svn revert -q s/alpha
191
191
192 this commit fails because of externals changes
192 this commit fails because of externals changes
193
193
194 $ echo zzz > s/externals/other
194 $ echo zzz > s/externals/other
195 $ hg ci -m 'amend externals from hg'
195 $ hg ci -m 'amend externals from hg'
196 committing subrepository s
196 committing subrepository s
197 abort: cannot commit svn externals
197 abort: cannot commit svn externals
198 [255]
198 [255]
199 $ hg diff --subrepos -r 1:2 | grep -v diff
199 $ hg diff --subrepos -r 1:2 | grep -v diff
200 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
200 --- a/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
201 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
201 +++ b/.hgsubstate Thu Jan 01 00:00:00 1970 +0000
202 @@ -1,2 +1,2 @@
202 @@ -1,2 +1,2 @@
203 -2 s
203 -2 s
204 +3 s
204 +3 s
205 2 subdir/s
205 2 subdir/s
206 --- a/a Thu Jan 01 00:00:00 1970 +0000
206 --- a/a Thu Jan 01 00:00:00 1970 +0000
207 +++ b/a Thu Jan 01 00:00:00 1970 +0000
207 +++ b/a Thu Jan 01 00:00:00 1970 +0000
208 @@ -1,1 +1,2 @@
208 @@ -1,1 +1,2 @@
209 a
209 a
210 +a
210 +a
211 $ svn revert -q s/externals/other
211 $ svn revert -q s/externals/other
212
212
213 this commit fails because of externals meta changes
213 this commit fails because of externals meta changes
214
214
215 $ svn propset svn:mime-type 'text/html' s/externals/other
215 $ svn propset svn:mime-type 'text/html' s/externals/other
216 property 'svn:mime-type' set on 's/externals/other'
216 property 'svn:mime-type' set on 's/externals/other'
217 $ hg ci -m 'amend externals from hg'
217 $ hg ci -m 'amend externals from hg'
218 committing subrepository s
218 committing subrepository s
219 abort: cannot commit svn externals
219 abort: cannot commit svn externals
220 [255]
220 [255]
221 $ svn revert -q s/externals/other
221 $ svn revert -q s/externals/other
222
222
223 clone
223 clone
224
224
225 $ cd ..
225 $ cd ..
226 $ hg clone t tc | fix_path
226 $ hg clone t tc | fix_path
227 updating to branch default
227 updating to branch default
228 A tc/subdir/s/alpha
228 A tc/subdir/s/alpha
229 U tc/subdir/s
229 U tc/subdir/s
230
230
231 Fetching external item into 'tc/subdir/s/externals'
231 Fetching external item into 'tc/subdir/s/externals'
232 A tc/subdir/s/externals/other
232 A tc/subdir/s/externals/other
233 Checked out external at revision 1.
233 Checked out external at revision 1.
234
234
235 Checked out revision 2.
235 Checked out revision 2.
236 A tc/s/alpha
236 A tc/s/alpha
237 U tc/s
237 U tc/s
238
238
239 Fetching external item into 'tc/s/externals'
239 Fetching external item into 'tc/s/externals'
240 A tc/s/externals/other
240 A tc/s/externals/other
241 Checked out external at revision 1.
241 Checked out external at revision 1.
242
242
243 Checked out revision 3.
243 Checked out revision 3.
244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
245 $ cd tc
245 $ cd tc
246
246
247 debugsub in clone
247 debugsub in clone
248
248
249 $ hg debugsub
249 $ hg debugsub
250 path s
250 path s
251 source file://*/svn-repo/src (glob)
251 source file://*/svn-repo/src (glob)
252 revision 3
252 revision 3
253 path subdir/s
253 path subdir/s
254 source file://*/svn-repo/src (glob)
254 source file://*/svn-repo/src (glob)
255 revision 2
255 revision 2
256
256
257 verify subrepo is contained within the repo directory
257 verify subrepo is contained within the repo directory
258
258
259 $ python -c "import os.path; print os.path.exists('s')"
259 $ python -c "import os.path; print os.path.exists('s')"
260 True
260 True
261
261
262 update to nullrev (must delete the subrepo)
262 update to nullrev (must delete the subrepo)
263
263
264 $ hg up null
264 $ hg up null
265 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
265 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
266 $ ls
266 $ ls
267
267
268 Check hg update --clean
268 Check hg update --clean
269 $ cd $TESTTMP/sub/t
269 $ cd $TESTTMP/sub/t
270 $ cd s
270 $ cd s
271 $ echo c0 > alpha
271 $ echo c0 > alpha
272 $ echo c1 > f1
272 $ echo c1 > f1
273 $ echo c1 > f2
273 $ echo c1 > f2
274 $ svn add f1 -q
274 $ svn add f1 -q
275 $ svn status
275 $ svn status
276 ? * a (glob)
276 ? * a (glob)
277 X * externals (glob)
277 X * externals (glob)
278 ? * f2 (glob)
278 ? * f2 (glob)
279 M * alpha (glob)
279 M * alpha (glob)
280 A * f1 (glob)
280 A * f1 (glob)
281
281
282 Performing status on external item at 'externals'
282 Performing status on external item at 'externals'
283 $ cd ../..
283 $ cd ../..
284 $ hg -R t update -C
284 $ hg -R t update -C
285
285
286 Fetching external item into 't/s/externals'
286 Fetching external item into 't/s/externals'
287 Checked out external at revision 1.
287 Checked out external at revision 1.
288
288
289 Checked out revision 3.
289 Checked out revision 3.
290 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
290 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
291 $ cd t/s
291 $ cd t/s
292 $ svn status
292 $ svn status
293 ? * a (glob)
293 ? * a (glob)
294 X * externals (glob)
294 X * externals (glob)
295 ? * f1 (glob)
295 ? * f1 (glob)
296 ? * f2 (glob)
296 ? * f2 (glob)
297
297
298 Performing status on external item at 'externals'
298 Performing status on external item at 'externals'
299
300 Sticky subrepositories, no changes
301 $ cd $TESTTMP/sub/t
302 $ hg id -n
303 2
304 $ cd s
305 $ svnversion
306 3
307 $ cd ..
308 $ hg update 1
309 U $TESTTMP/sub/t/s/alpha
310
311 Fetching external item into '$TESTTMP/sub/t/s/externals'
312 Checked out external at revision 1.
313
314 Checked out revision 2.
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 $ hg id -n
317 1
318 $ cd s
319 $ svnversion
320 2
321 $ cd ..
322
323 Sticky subrepositorys, file changes
324 $ touch s/f1
325 $ cd s
326 $ svn add f1
327 A f1
328 $ cd ..
329 $ hg id -n
330 1
331 $ cd s
332 $ svnversion
333 2M
334 $ cd ..
335 $ hg update tip
336 subrepository sources for s differ
337 use (l)ocal source (2) or (r)emote source (3)?
338 l
339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 $ hg id -n
341 2+
342 $ cd s
343 $ svnversion
344 2M
345 $ cd ..
346 $ hg update --clean tip
347 U $TESTTMP/sub/t/s/alpha
348
349 Fetching external item into '$TESTTMP/sub/t/s/externals'
350 Checked out external at revision 1.
351
352 Checked out revision 3.
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354
355 Sticky subrepository, revision updates
356 $ hg id -n
357 2
358 $ cd s
359 $ svnversion
360 3
361 $ cd ..
362 $ cd s
363 $ svn update -r 1
364 U alpha
365 U .
366
367 Fetching external item into 'externals'
368 Updated external to revision 1.
369
370 Updated to revision 1.
371 $ cd ..
372 $ hg update 1
373 subrepository sources for s differ (in checked out version)
374 use (l)ocal source (1) or (r)emote source (2)?
375 l
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 $ hg id -n
378 1+
379 $ cd s
380 $ svnversion
381 1
382 $ cd ..
383
384 Sticky subrepository, file changes and revision updates
385 $ touch s/f1
386 $ cd s
387 $ svn add f1
388 A f1
389 $ svnversion
390 1M
391 $ cd ..
392 $ hg id -n
393 1+
394 $ hg update tip
395 subrepository sources for s differ
396 use (l)ocal source (1) or (r)emote source (3)?
397 l
398 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 $ hg id -n
400 2
401 $ cd s
402 $ svnversion
403 1M
404 $ cd ..
405
406 Sticky repository, update --clean
407 $ hg update --clean tip
408 U $TESTTMP/sub/t/s/alpha
409 U $TESTTMP/sub/t/s
410
411 Fetching external item into '$TESTTMP/sub/t/s/externals'
412 Checked out external at revision 1.
413
414 Checked out revision 3.
415 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
416 $ hg id -n
417 2
418 $ cd s
419 $ svnversion
420 3
421 $ cd ..
422
423 Test subrepo already at intended revision:
424 $ cd s
425 $ svn update -r 2
426 U alpha
427
428 Fetching external item into 'externals'
429 Updated external to revision 1.
430
431 Updated to revision 2.
432 $ cd ..
433 $ hg update 1
434 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
435 $ hg id -n
436 1+
437 $ cd s
438 $ svnversion
439 2
440 $ cd ..
@@ -1,708 +1,830 b''
1 $ rm -rf sub
1 $ rm -rf sub
2 $ mkdir sub
2 $ mkdir sub
3 $ cd sub
3 $ cd sub
4 $ hg init t
4 $ hg init t
5 $ cd t
5 $ cd t
6
6
7 first revision, no sub
7 first revision, no sub
8
8
9 $ echo a > a
9 $ echo a > a
10 $ hg ci -Am0
10 $ hg ci -Am0
11 adding a
11 adding a
12
12
13 add first sub
13 add first sub
14
14
15 $ echo s = s > .hgsub
15 $ echo s = s > .hgsub
16 $ hg add .hgsub
16 $ hg add .hgsub
17 $ hg init s
17 $ hg init s
18 $ echo a > s/a
18 $ echo a > s/a
19
19
20 Issue2232: committing a subrepo without .hgsub
20 Issue2232: committing a subrepo without .hgsub
21
21
22 $ hg ci -mbad s
22 $ hg ci -mbad s
23 abort: can't commit subrepos without .hgsub
23 abort: can't commit subrepos without .hgsub
24 [255]
24 [255]
25
25
26 $ hg -R s ci -Ams0
26 $ hg -R s ci -Ams0
27 adding a
27 adding a
28 $ hg sum
28 $ hg sum
29 parent: 0:f7b1eb17ad24 tip
29 parent: 0:f7b1eb17ad24 tip
30 0
30 0
31 branch: default
31 branch: default
32 commit: 1 added, 1 subrepos
32 commit: 1 added, 1 subrepos
33 update: (current)
33 update: (current)
34 $ hg ci -m1
34 $ hg ci -m1
35 committing subrepository s
35 committing subrepository s
36
36
37 Issue2022: update -C
37 Issue2022: update -C
38
38
39 $ echo b > s/a
39 $ echo b > s/a
40 $ hg sum
40 $ hg sum
41 parent: 1:7cf8cfea66e4 tip
41 parent: 1:7cf8cfea66e4 tip
42 1
42 1
43 branch: default
43 branch: default
44 commit: 1 subrepos
44 commit: 1 subrepos
45 update: (current)
45 update: (current)
46 $ hg co -C 1
46 $ hg co -C 1
47 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 $ hg sum
48 $ hg sum
49 parent: 1:7cf8cfea66e4 tip
49 parent: 1:7cf8cfea66e4 tip
50 1
50 1
51 branch: default
51 branch: default
52 commit: (clean)
52 commit: (clean)
53 update: (current)
53 update: (current)
54
54
55 add sub sub
55 add sub sub
56
56
57 $ echo ss = ss > s/.hgsub
57 $ echo ss = ss > s/.hgsub
58 $ hg init s/ss
58 $ hg init s/ss
59 $ echo a > s/ss/a
59 $ echo a > s/ss/a
60 $ hg -R s add s/.hgsub
60 $ hg -R s add s/.hgsub
61 $ hg -R s/ss add s/ss/a
61 $ hg -R s/ss add s/ss/a
62 $ hg sum
62 $ hg sum
63 parent: 1:7cf8cfea66e4 tip
63 parent: 1:7cf8cfea66e4 tip
64 1
64 1
65 branch: default
65 branch: default
66 commit: 1 subrepos
66 commit: 1 subrepos
67 update: (current)
67 update: (current)
68 $ hg ci -m2
68 $ hg ci -m2
69 committing subrepository s
69 committing subrepository s
70 committing subrepository s/ss
70 committing subrepository s/ss
71 $ hg sum
71 $ hg sum
72 parent: 2:df30734270ae tip
72 parent: 2:df30734270ae tip
73 2
73 2
74 branch: default
74 branch: default
75 commit: (clean)
75 commit: (clean)
76 update: (current)
76 update: (current)
77
77
78 bump sub rev (and check it is ignored by ui.commitsubrepos)
78 bump sub rev (and check it is ignored by ui.commitsubrepos)
79
79
80 $ echo b > s/a
80 $ echo b > s/a
81 $ hg -R s ci -ms1
81 $ hg -R s ci -ms1
82 $ hg --config ui.commitsubrepos=no ci -m3
82 $ hg --config ui.commitsubrepos=no ci -m3
83 committing subrepository s
83 committing subrepository s
84
84
85 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
85 leave sub dirty (and check ui.commitsubrepos=no aborts the commit)
86
86
87 $ echo c > s/a
87 $ echo c > s/a
88 $ hg --config ui.commitsubrepos=no ci -m4
88 $ hg --config ui.commitsubrepos=no ci -m4
89 abort: uncommitted changes in subrepo s
89 abort: uncommitted changes in subrepo s
90 [255]
90 [255]
91 $ hg ci -m4
91 $ hg ci -m4
92 committing subrepository s
92 committing subrepository s
93 $ hg tip -R s
93 $ hg tip -R s
94 changeset: 3:1c833a7a9e3a
94 changeset: 3:1c833a7a9e3a
95 tag: tip
95 tag: tip
96 user: test
96 user: test
97 date: Thu Jan 01 00:00:00 1970 +0000
97 date: Thu Jan 01 00:00:00 1970 +0000
98 summary: 4
98 summary: 4
99
99
100
100
101 check caching
101 check caching
102
102
103 $ hg co 0
103 $ hg co 0
104 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
104 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
105 $ hg debugsub
105 $ hg debugsub
106
106
107 restore
107 restore
108
108
109 $ hg co
109 $ hg co
110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ hg debugsub
111 $ hg debugsub
112 path s
112 path s
113 source s
113 source s
114 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
114 revision 1c833a7a9e3a4445c711aaf0f012379cd0d4034e
115
115
116 new branch for merge tests
116 new branch for merge tests
117
117
118 $ hg co 1
118 $ hg co 1
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 $ echo t = t >> .hgsub
120 $ echo t = t >> .hgsub
121 $ hg init t
121 $ hg init t
122 $ echo t > t/t
122 $ echo t > t/t
123 $ hg -R t add t
123 $ hg -R t add t
124 adding t/t
124 adding t/t
125
125
126 5
126 5
127
127
128 $ hg ci -m5 # add sub
128 $ hg ci -m5 # add sub
129 committing subrepository t
129 committing subrepository t
130 created new head
130 created new head
131 $ echo t2 > t/t
131 $ echo t2 > t/t
132
132
133 6
133 6
134
134
135 $ hg st -R s
135 $ hg st -R s
136 $ hg ci -m6 # change sub
136 $ hg ci -m6 # change sub
137 committing subrepository t
137 committing subrepository t
138 $ hg debugsub
138 $ hg debugsub
139 path s
139 path s
140 source s
140 source s
141 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
141 revision e4ece1bf43360ddc8f6a96432201a37b7cd27ae4
142 path t
142 path t
143 source t
143 source t
144 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
144 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
145 $ echo t3 > t/t
145 $ echo t3 > t/t
146
146
147 7
147 7
148
148
149 $ hg ci -m7 # change sub again for conflict test
149 $ hg ci -m7 # change sub again for conflict test
150 committing subrepository t
150 committing subrepository t
151 $ hg rm .hgsub
151 $ hg rm .hgsub
152
152
153 8
153 8
154
154
155 $ hg ci -m8 # remove sub
155 $ hg ci -m8 # remove sub
156
156
157 merge tests
157 merge tests
158
158
159 $ hg co -C 3
159 $ hg co -C 3
160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 $ hg merge 5 # test adding
161 $ hg merge 5 # test adding
162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 (branch merge, don't forget to commit)
163 (branch merge, don't forget to commit)
164 $ hg debugsub
164 $ hg debugsub
165 path s
165 path s
166 source s
166 source s
167 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
167 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
168 path t
168 path t
169 source t
169 source t
170 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
170 revision 60ca1237c19474e7a3978b0dc1ca4e6f36d51382
171 $ hg ci -m9
171 $ hg ci -m9
172 created new head
172 created new head
173 $ hg merge 6 --debug # test change
173 $ hg merge 6 --debug # test change
174 searching for copies back to rev 2
174 searching for copies back to rev 2
175 resolving manifests
175 resolving manifests
176 overwrite None partial False
176 overwrite None partial False
177 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
177 ancestor 1f14a2e2d3ec local f0d2028bf86d+ remote 1831e14459c4
178 .hgsubstate: versions differ -> m
178 .hgsubstate: versions differ -> m
179 updating: .hgsubstate 1/1 files (100.00%)
179 updating: .hgsubstate 1/1 files (100.00%)
180 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
180 subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
181 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
181 subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
182 getting subrepo t
182 getting subrepo t
183 resolving manifests
183 resolving manifests
184 overwrite True partial False
184 overwrite True partial False
185 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
185 ancestor 60ca1237c194+ local 60ca1237c194+ remote 6747d179aa9a
186 t: remote is newer -> g
186 t: remote is newer -> g
187 updating: t 1/1 files (100.00%)
187 updating: t 1/1 files (100.00%)
188 getting t
188 getting t
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
189 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 (branch merge, don't forget to commit)
190 (branch merge, don't forget to commit)
191 $ hg debugsub
191 $ hg debugsub
192 path s
192 path s
193 source s
193 source s
194 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
194 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
195 path t
195 path t
196 source t
196 source t
197 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
197 revision 6747d179aa9a688023c4b0cad32e4c92bb7f34ad
198 $ echo conflict > t/t
198 $ echo conflict > t/t
199 $ hg ci -m10
199 $ hg ci -m10
200 committing subrepository t
200 committing subrepository t
201 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
201 $ HGMERGE=internal:merge hg merge --debug 7 # test conflict
202 searching for copies back to rev 2
202 searching for copies back to rev 2
203 resolving manifests
203 resolving manifests
204 overwrite None partial False
204 overwrite None partial False
205 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
205 ancestor 1831e14459c4 local e45c8b14af55+ remote f94576341bcf
206 .hgsubstate: versions differ -> m
206 .hgsubstate: versions differ -> m
207 updating: .hgsubstate 1/1 files (100.00%)
207 updating: .hgsubstate 1/1 files (100.00%)
208 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
208 subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
209 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
209 subrepo t: both sides changed, merge with t:7af322bc1198a32402fe903e0b7ebcfc5c9bf8f4:hg
210 merging subrepo t
210 merging subrepo t
211 searching for copies back to rev 2
211 searching for copies back to rev 2
212 resolving manifests
212 resolving manifests
213 overwrite None partial False
213 overwrite None partial False
214 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
214 ancestor 6747d179aa9a local 20a0db6fbf6c+ remote 7af322bc1198
215 t: versions differ -> m
215 t: versions differ -> m
216 preserving t for resolve of t
216 preserving t for resolve of t
217 updating: t 1/1 files (100.00%)
217 updating: t 1/1 files (100.00%)
218 picked tool 'internal:merge' for t (binary False symlink False)
218 picked tool 'internal:merge' for t (binary False symlink False)
219 merging t
219 merging t
220 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
220 my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
221 warning: conflicts during merge.
221 warning: conflicts during merge.
222 merging t failed!
222 merging t failed!
223 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
223 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
224 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
224 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
225 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
225 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 (branch merge, don't forget to commit)
226 (branch merge, don't forget to commit)
227
227
228 should conflict
228 should conflict
229
229
230 $ cat t/t
230 $ cat t/t
231 <<<<<<< local
231 <<<<<<< local
232 conflict
232 conflict
233 =======
233 =======
234 t3
234 t3
235 >>>>>>> other
235 >>>>>>> other
236
236
237 clone
237 clone
238
238
239 $ cd ..
239 $ cd ..
240 $ hg clone t tc
240 $ hg clone t tc
241 updating to branch default
241 updating to branch default
242 pulling subrepo s from $TESTTMP/sub/t/s
242 pulling subrepo s from $TESTTMP/sub/t/s
243 requesting all changes
243 requesting all changes
244 adding changesets
244 adding changesets
245 adding manifests
245 adding manifests
246 adding file changes
246 adding file changes
247 added 4 changesets with 5 changes to 3 files
247 added 4 changesets with 5 changes to 3 files
248 pulling subrepo s/ss from $TESTTMP/sub/t/s/ss
248 pulling subrepo s/ss from $TESTTMP/sub/t/s/ss
249 requesting all changes
249 requesting all changes
250 adding changesets
250 adding changesets
251 adding manifests
251 adding manifests
252 adding file changes
252 adding file changes
253 added 1 changesets with 1 changes to 1 files
253 added 1 changesets with 1 changes to 1 files
254 pulling subrepo t from $TESTTMP/sub/t/t
254 pulling subrepo t from $TESTTMP/sub/t/t
255 requesting all changes
255 requesting all changes
256 adding changesets
256 adding changesets
257 adding manifests
257 adding manifests
258 adding file changes
258 adding file changes
259 added 4 changesets with 4 changes to 1 files (+1 heads)
259 added 4 changesets with 4 changes to 1 files (+1 heads)
260 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
260 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 $ cd tc
261 $ cd tc
262 $ hg debugsub
262 $ hg debugsub
263 path s
263 path s
264 source s
264 source s
265 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
265 revision fc627a69481fcbe5f1135069e8a3881c023e4cf5
266 path t
266 path t
267 source t
267 source t
268 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
268 revision 20a0db6fbf6c3d2836e6519a642ae929bfc67c0e
269
269
270 push
270 push
271
271
272 $ echo bah > t/t
272 $ echo bah > t/t
273 $ hg ci -m11
273 $ hg ci -m11
274 committing subrepository t
274 committing subrepository t
275 $ hg push
275 $ hg push
276 pushing to $TESTTMP/sub/t
276 pushing to $TESTTMP/sub/t
277 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
277 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
278 searching for changes
278 searching for changes
279 no changes found
279 no changes found
280 pushing subrepo s to $TESTTMP/sub/t/s
280 pushing subrepo s to $TESTTMP/sub/t/s
281 searching for changes
281 searching for changes
282 no changes found
282 no changes found
283 pushing subrepo t to $TESTTMP/sub/t/t
283 pushing subrepo t to $TESTTMP/sub/t/t
284 searching for changes
284 searching for changes
285 adding changesets
285 adding changesets
286 adding manifests
286 adding manifests
287 adding file changes
287 adding file changes
288 added 1 changesets with 1 changes to 1 files
288 added 1 changesets with 1 changes to 1 files
289 searching for changes
289 searching for changes
290 adding changesets
290 adding changesets
291 adding manifests
291 adding manifests
292 adding file changes
292 adding file changes
293 added 1 changesets with 1 changes to 1 files
293 added 1 changesets with 1 changes to 1 files
294
294
295 push -f
295 push -f
296
296
297 $ echo bah > s/a
297 $ echo bah > s/a
298 $ hg ci -m12
298 $ hg ci -m12
299 committing subrepository s
299 committing subrepository s
300 $ hg push
300 $ hg push
301 pushing to $TESTTMP/sub/t
301 pushing to $TESTTMP/sub/t
302 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
302 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
303 searching for changes
303 searching for changes
304 no changes found
304 no changes found
305 pushing subrepo s to $TESTTMP/sub/t/s
305 pushing subrepo s to $TESTTMP/sub/t/s
306 searching for changes
306 searching for changes
307 abort: push creates new remote heads on branch 'default'!
307 abort: push creates new remote heads on branch 'default'!
308 (did you forget to merge? use push -f to force)
308 (did you forget to merge? use push -f to force)
309 [255]
309 [255]
310 $ hg push -f
310 $ hg push -f
311 pushing to $TESTTMP/sub/t
311 pushing to $TESTTMP/sub/t
312 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
312 pushing subrepo s/ss to $TESTTMP/sub/t/s/ss
313 searching for changes
313 searching for changes
314 no changes found
314 no changes found
315 pushing subrepo s to $TESTTMP/sub/t/s
315 pushing subrepo s to $TESTTMP/sub/t/s
316 searching for changes
316 searching for changes
317 adding changesets
317 adding changesets
318 adding manifests
318 adding manifests
319 adding file changes
319 adding file changes
320 added 1 changesets with 1 changes to 1 files (+1 heads)
320 added 1 changesets with 1 changes to 1 files (+1 heads)
321 pushing subrepo t to $TESTTMP/sub/t/t
321 pushing subrepo t to $TESTTMP/sub/t/t
322 searching for changes
322 searching for changes
323 no changes found
323 no changes found
324 searching for changes
324 searching for changes
325 adding changesets
325 adding changesets
326 adding manifests
326 adding manifests
327 adding file changes
327 adding file changes
328 added 1 changesets with 1 changes to 1 files
328 added 1 changesets with 1 changes to 1 files
329
329
330 update
330 update
331
331
332 $ cd ../t
332 $ cd ../t
333 $ hg up -C # discard our earlier merge
333 $ hg up -C # discard our earlier merge
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 $ echo blah > t/t
335 $ echo blah > t/t
336 $ hg ci -m13
336 $ hg ci -m13
337 committing subrepository t
337 committing subrepository t
338
338
339 pull
339 pull
340
340
341 $ cd ../tc
341 $ cd ../tc
342 $ hg pull
342 $ hg pull
343 pulling from $TESTTMP/sub/t
343 pulling from $TESTTMP/sub/t
344 searching for changes
344 searching for changes
345 adding changesets
345 adding changesets
346 adding manifests
346 adding manifests
347 adding file changes
347 adding file changes
348 added 1 changesets with 1 changes to 1 files
348 added 1 changesets with 1 changes to 1 files
349 (run 'hg update' to get a working copy)
349 (run 'hg update' to get a working copy)
350
350
351 should pull t
351 should pull t
352
352
353 $ hg up
353 $ hg up
354 pulling subrepo t from $TESTTMP/sub/t/t
354 pulling subrepo t from $TESTTMP/sub/t/t
355 searching for changes
355 searching for changes
356 adding changesets
356 adding changesets
357 adding manifests
357 adding manifests
358 adding file changes
358 adding file changes
359 added 1 changesets with 1 changes to 1 files
359 added 1 changesets with 1 changes to 1 files
360 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
360 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
361 $ cat t/t
361 $ cat t/t
362 blah
362 blah
363
363
364 bogus subrepo path aborts
364 bogus subrepo path aborts
365
365
366 $ echo 'bogus=[boguspath' >> .hgsub
366 $ echo 'bogus=[boguspath' >> .hgsub
367 $ hg ci -m 'bogus subrepo path'
367 $ hg ci -m 'bogus subrepo path'
368 abort: missing ] in subrepo source
368 abort: missing ] in subrepo source
369 [255]
369 [255]
370
370
371 Issue1986: merge aborts when trying to merge a subrepo that
371 Issue1986: merge aborts when trying to merge a subrepo that
372 shouldn't need merging
372 shouldn't need merging
373
373
374 # subrepo layout
374 # subrepo layout
375 #
375 #
376 # o 5 br
376 # o 5 br
377 # /|
377 # /|
378 # o | 4 default
378 # o | 4 default
379 # | |
379 # | |
380 # | o 3 br
380 # | o 3 br
381 # |/|
381 # |/|
382 # o | 2 default
382 # o | 2 default
383 # | |
383 # | |
384 # | o 1 br
384 # | o 1 br
385 # |/
385 # |/
386 # o 0 default
386 # o 0 default
387
387
388 $ cd ..
388 $ cd ..
389 $ rm -rf sub
389 $ rm -rf sub
390 $ hg init main
390 $ hg init main
391 $ cd main
391 $ cd main
392 $ hg init s
392 $ hg init s
393 $ cd s
393 $ cd s
394 $ echo a > a
394 $ echo a > a
395 $ hg ci -Am1
395 $ hg ci -Am1
396 adding a
396 adding a
397 $ hg branch br
397 $ hg branch br
398 marked working directory as branch br
398 marked working directory as branch br
399 $ echo a >> a
399 $ echo a >> a
400 $ hg ci -m1
400 $ hg ci -m1
401 $ hg up default
401 $ hg up default
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
402 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
403 $ echo b > b
403 $ echo b > b
404 $ hg ci -Am1
404 $ hg ci -Am1
405 adding b
405 adding b
406 $ hg up br
406 $ hg up br
407 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
407 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
408 $ hg merge tip
408 $ hg merge tip
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 (branch merge, don't forget to commit)
410 (branch merge, don't forget to commit)
411 $ hg ci -m1
411 $ hg ci -m1
412 $ hg up 2
412 $ hg up 2
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
414 $ echo c > c
414 $ echo c > c
415 $ hg ci -Am1
415 $ hg ci -Am1
416 adding c
416 adding c
417 $ hg up 3
417 $ hg up 3
418 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
418 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 $ hg merge 4
419 $ hg merge 4
420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 (branch merge, don't forget to commit)
421 (branch merge, don't forget to commit)
422 $ hg ci -m1
422 $ hg ci -m1
423
423
424 # main repo layout:
424 # main repo layout:
425 #
425 #
426 # * <-- try to merge default into br again
426 # * <-- try to merge default into br again
427 # .`|
427 # .`|
428 # . o 5 br --> substate = 5
428 # . o 5 br --> substate = 5
429 # . |
429 # . |
430 # o | 4 default --> substate = 4
430 # o | 4 default --> substate = 4
431 # | |
431 # | |
432 # | o 3 br --> substate = 2
432 # | o 3 br --> substate = 2
433 # |/|
433 # |/|
434 # o | 2 default --> substate = 2
434 # o | 2 default --> substate = 2
435 # | |
435 # | |
436 # | o 1 br --> substate = 3
436 # | o 1 br --> substate = 3
437 # |/
437 # |/
438 # o 0 default --> substate = 2
438 # o 0 default --> substate = 2
439
439
440 $ cd ..
440 $ cd ..
441 $ echo 's = s' > .hgsub
441 $ echo 's = s' > .hgsub
442 $ hg -R s up 2
442 $ hg -R s up 2
443 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
443 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
444 $ hg ci -Am1
444 $ hg ci -Am1
445 adding .hgsub
445 adding .hgsub
446 committing subrepository s
446 committing subrepository s
447 $ hg branch br
447 $ hg branch br
448 marked working directory as branch br
448 marked working directory as branch br
449 $ echo b > b
449 $ echo b > b
450 $ hg -R s up 3
450 $ hg -R s up 3
451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 $ hg ci -Am1
452 $ hg ci -Am1
453 adding b
453 adding b
454 committing subrepository s
454 committing subrepository s
455 $ hg up default
455 $ hg up default
456 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
456 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
457 $ echo c > c
457 $ echo c > c
458 $ hg ci -Am1
458 $ hg ci -Am1
459 adding c
459 adding c
460 $ hg up 1
460 $ hg up 1
461 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
461 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
462 $ hg merge 2
462 $ hg merge 2
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
464 (branch merge, don't forget to commit)
464 (branch merge, don't forget to commit)
465 $ hg ci -m1
465 $ hg ci -m1
466 $ hg up 2
466 $ hg up 2
467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
467 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
468 $ hg -R s up 4
468 $ hg -R s up 4
469 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 $ echo d > d
470 $ echo d > d
471 $ hg ci -Am1
471 $ hg ci -Am1
472 adding d
472 adding d
473 committing subrepository s
473 committing subrepository s
474 $ hg up 3
474 $ hg up 3
475 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
475 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
476 $ hg -R s up 5
476 $ hg -R s up 5
477 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
477 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
478 $ echo e > e
478 $ echo e > e
479 $ hg ci -Am1
479 $ hg ci -Am1
480 adding e
480 adding e
481 committing subrepository s
481 committing subrepository s
482
482
483 $ hg up 5
483 $ hg up 5
484 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
484 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
485 $ hg merge 4 # try to merge default into br again
485 $ hg merge 4 # try to merge default into br again
486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
486 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
487 (branch merge, don't forget to commit)
487 (branch merge, don't forget to commit)
488 $ cd ..
488 $ cd ..
489
489
490 test subrepo delete from .hgsubstate
490 test subrepo delete from .hgsubstate
491
491
492 $ hg init testdelete
492 $ hg init testdelete
493 $ mkdir testdelete/nested testdelete/nested2
493 $ mkdir testdelete/nested testdelete/nested2
494 $ hg init testdelete/nested
494 $ hg init testdelete/nested
495 $ hg init testdelete/nested2
495 $ hg init testdelete/nested2
496 $ echo test > testdelete/nested/foo
496 $ echo test > testdelete/nested/foo
497 $ echo test > testdelete/nested2/foo
497 $ echo test > testdelete/nested2/foo
498 $ hg -R testdelete/nested add
498 $ hg -R testdelete/nested add
499 adding testdelete/nested/foo
499 adding testdelete/nested/foo
500 $ hg -R testdelete/nested2 add
500 $ hg -R testdelete/nested2 add
501 adding testdelete/nested2/foo
501 adding testdelete/nested2/foo
502 $ hg -R testdelete/nested ci -m test
502 $ hg -R testdelete/nested ci -m test
503 $ hg -R testdelete/nested2 ci -m test
503 $ hg -R testdelete/nested2 ci -m test
504 $ echo nested = nested > testdelete/.hgsub
504 $ echo nested = nested > testdelete/.hgsub
505 $ echo nested2 = nested2 >> testdelete/.hgsub
505 $ echo nested2 = nested2 >> testdelete/.hgsub
506 $ hg -R testdelete add
506 $ hg -R testdelete add
507 adding testdelete/.hgsub
507 adding testdelete/.hgsub
508 $ hg -R testdelete ci -m "nested 1 & 2 added"
508 $ hg -R testdelete ci -m "nested 1 & 2 added"
509 committing subrepository nested
509 committing subrepository nested
510 committing subrepository nested2
510 committing subrepository nested2
511 $ echo nested = nested > testdelete/.hgsub
511 $ echo nested = nested > testdelete/.hgsub
512 $ hg -R testdelete ci -m "nested 2 deleted"
512 $ hg -R testdelete ci -m "nested 2 deleted"
513 $ cat testdelete/.hgsubstate
513 $ cat testdelete/.hgsubstate
514 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
514 bdf5c9a3103743d900b12ae0db3ffdcfd7b0d878 nested
515 $ hg -R testdelete remove testdelete/.hgsub
515 $ hg -R testdelete remove testdelete/.hgsub
516 $ hg -R testdelete ci -m ".hgsub deleted"
516 $ hg -R testdelete ci -m ".hgsub deleted"
517 $ cat testdelete/.hgsubstate
517 $ cat testdelete/.hgsubstate
518
518
519 test repository cloning
519 test repository cloning
520
520
521 $ mkdir mercurial mercurial2
521 $ mkdir mercurial mercurial2
522 $ hg init nested_absolute
522 $ hg init nested_absolute
523 $ echo test > nested_absolute/foo
523 $ echo test > nested_absolute/foo
524 $ hg -R nested_absolute add
524 $ hg -R nested_absolute add
525 adding nested_absolute/foo
525 adding nested_absolute/foo
526 $ hg -R nested_absolute ci -mtest
526 $ hg -R nested_absolute ci -mtest
527 $ cd mercurial
527 $ cd mercurial
528 $ hg init nested_relative
528 $ hg init nested_relative
529 $ echo test2 > nested_relative/foo2
529 $ echo test2 > nested_relative/foo2
530 $ hg -R nested_relative add
530 $ hg -R nested_relative add
531 adding nested_relative/foo2
531 adding nested_relative/foo2
532 $ hg -R nested_relative ci -mtest2
532 $ hg -R nested_relative ci -mtest2
533 $ hg init main
533 $ hg init main
534 $ echo "nested_relative = ../nested_relative" > main/.hgsub
534 $ echo "nested_relative = ../nested_relative" > main/.hgsub
535 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
535 $ echo "nested_absolute = `pwd`/nested_absolute" >> main/.hgsub
536 $ hg -R main add
536 $ hg -R main add
537 adding main/.hgsub
537 adding main/.hgsub
538 $ hg -R main ci -m "add subrepos"
538 $ hg -R main ci -m "add subrepos"
539 committing subrepository nested_absolute
539 committing subrepository nested_absolute
540 committing subrepository nested_relative
540 committing subrepository nested_relative
541 $ cd ..
541 $ cd ..
542 $ hg clone mercurial/main mercurial2/main
542 $ hg clone mercurial/main mercurial2/main
543 updating to branch default
543 updating to branch default
544 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
544 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
545 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
545 $ cat mercurial2/main/nested_absolute/.hg/hgrc \
546 > mercurial2/main/nested_relative/.hg/hgrc
546 > mercurial2/main/nested_relative/.hg/hgrc
547 [paths]
547 [paths]
548 default = $TESTTMP/sub/mercurial/nested_absolute
548 default = $TESTTMP/sub/mercurial/nested_absolute
549 [paths]
549 [paths]
550 default = $TESTTMP/sub/mercurial/nested_relative
550 default = $TESTTMP/sub/mercurial/nested_relative
551 $ rm -rf mercurial mercurial2
551 $ rm -rf mercurial mercurial2
552
552
553 Issue1977: multirepo push should fail if subrepo push fails
553 Issue1977: multirepo push should fail if subrepo push fails
554
554
555 $ hg init repo
555 $ hg init repo
556 $ hg init repo/s
556 $ hg init repo/s
557 $ echo a > repo/s/a
557 $ echo a > repo/s/a
558 $ hg -R repo/s ci -Am0
558 $ hg -R repo/s ci -Am0
559 adding a
559 adding a
560 $ echo s = s > repo/.hgsub
560 $ echo s = s > repo/.hgsub
561 $ hg -R repo ci -Am1
561 $ hg -R repo ci -Am1
562 adding .hgsub
562 adding .hgsub
563 committing subrepository s
563 committing subrepository s
564 $ hg clone repo repo2
564 $ hg clone repo repo2
565 updating to branch default
565 updating to branch default
566 pulling subrepo s from $TESTTMP/sub/repo/s
566 pulling subrepo s from $TESTTMP/sub/repo/s
567 requesting all changes
567 requesting all changes
568 adding changesets
568 adding changesets
569 adding manifests
569 adding manifests
570 adding file changes
570 adding file changes
571 added 1 changesets with 1 changes to 1 files
571 added 1 changesets with 1 changes to 1 files
572 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
572 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 $ hg -q -R repo2 pull -u
573 $ hg -q -R repo2 pull -u
574 $ echo 1 > repo2/s/a
574 $ echo 1 > repo2/s/a
575 $ hg -R repo2/s ci -m2
575 $ hg -R repo2/s ci -m2
576 $ hg -q -R repo2/s push
576 $ hg -q -R repo2/s push
577 $ hg -R repo2/s up -C 0
577 $ hg -R repo2/s up -C 0
578 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
578 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
579 $ echo 2 > repo2/s/a
579 $ echo 2 > repo2/s/a
580 $ hg -R repo2/s ci -m3
580 $ hg -R repo2/s ci -m3
581 created new head
581 created new head
582 $ hg -R repo2 ci -m3
582 $ hg -R repo2 ci -m3
583 committing subrepository s
583 committing subrepository s
584 $ hg -q -R repo2 push
584 $ hg -q -R repo2 push
585 abort: push creates new remote heads on branch 'default'!
585 abort: push creates new remote heads on branch 'default'!
586 (did you forget to merge? use push -f to force)
586 (did you forget to merge? use push -f to force)
587 [255]
587 [255]
588 $ hg -R repo update
588 $ hg -R repo update
589 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
589 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
590 $ rm -rf repo2 repo
590 $ rm -rf repo2 repo
591
591
592
592
593 Issue1852 subrepos with relative paths always push/pull relative to default
593 Issue1852 subrepos with relative paths always push/pull relative to default
594
594
595 Prepare a repo with subrepo
595 Prepare a repo with subrepo
596
596
597 $ hg init issue1852a
597 $ hg init issue1852a
598 $ cd issue1852a
598 $ cd issue1852a
599 $ hg init sub/repo
599 $ hg init sub/repo
600 $ echo test > sub/repo/foo
600 $ echo test > sub/repo/foo
601 $ hg -R sub/repo add sub/repo/foo
601 $ hg -R sub/repo add sub/repo/foo
602 $ echo sub/repo = sub/repo > .hgsub
602 $ echo sub/repo = sub/repo > .hgsub
603 $ hg add .hgsub
603 $ hg add .hgsub
604 $ hg ci -mtest
604 $ hg ci -mtest
605 committing subrepository sub/repo
605 committing subrepository sub/repo
606 $ echo test >> sub/repo/foo
606 $ echo test >> sub/repo/foo
607 $ hg ci -mtest
607 $ hg ci -mtest
608 committing subrepository sub/repo
608 committing subrepository sub/repo
609 $ cd ..
609 $ cd ..
610
610
611 Create repo without default path, pull top repo, and see what happens on update
611 Create repo without default path, pull top repo, and see what happens on update
612
612
613 $ hg init issue1852b
613 $ hg init issue1852b
614 $ hg -R issue1852b pull issue1852a
614 $ hg -R issue1852b pull issue1852a
615 pulling from issue1852a
615 pulling from issue1852a
616 requesting all changes
616 requesting all changes
617 adding changesets
617 adding changesets
618 adding manifests
618 adding manifests
619 adding file changes
619 adding file changes
620 added 2 changesets with 3 changes to 2 files
620 added 2 changesets with 3 changes to 2 files
621 (run 'hg update' to get a working copy)
621 (run 'hg update' to get a working copy)
622 $ hg -R issue1852b update
622 $ hg -R issue1852b update
623 abort: default path for subrepository sub/repo not found
623 abort: default path for subrepository sub/repo not found
624 [255]
624 [255]
625
625
626 Pull -u now doesn't help
626 Pull -u now doesn't help
627
627
628 $ hg -R issue1852b pull -u issue1852a
628 $ hg -R issue1852b pull -u issue1852a
629 pulling from issue1852a
629 pulling from issue1852a
630 searching for changes
630 searching for changes
631 no changes found
631 no changes found
632
632
633 Try the same, but with pull -u
633 Try the same, but with pull -u
634
634
635 $ hg init issue1852c
635 $ hg init issue1852c
636 $ hg -R issue1852c pull -r0 -u issue1852a
636 $ hg -R issue1852c pull -r0 -u issue1852a
637 pulling from issue1852a
637 pulling from issue1852a
638 adding changesets
638 adding changesets
639 adding manifests
639 adding manifests
640 adding file changes
640 adding file changes
641 added 1 changesets with 2 changes to 2 files
641 added 1 changesets with 2 changes to 2 files
642 pulling subrepo sub/repo from issue1852a/sub/repo
642 pulling subrepo sub/repo from issue1852a/sub/repo
643 requesting all changes
643 requesting all changes
644 adding changesets
644 adding changesets
645 adding manifests
645 adding manifests
646 adding file changes
646 adding file changes
647 added 2 changesets with 2 changes to 1 files
647 added 2 changesets with 2 changes to 1 files
648 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
649
649
650 Try to push from the other side
650 Try to push from the other side
651
651
652 $ hg -R issue1852a push `pwd`/issue1852c
652 $ hg -R issue1852a push `pwd`/issue1852c
653 pushing to $TESTTMP/sub/issue1852c
653 pushing to $TESTTMP/sub/issue1852c
654 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
654 pushing subrepo sub/repo to $TESTTMP/sub/issue1852c/sub/repo
655 searching for changes
655 searching for changes
656 no changes found
656 no changes found
657 searching for changes
657 searching for changes
658 adding changesets
658 adding changesets
659 adding manifests
659 adding manifests
660 adding file changes
660 adding file changes
661 added 1 changesets with 1 changes to 1 files
661 added 1 changesets with 1 changes to 1 files
662
662
663 Check status of files when none of them belong to the first
663 Check status of files when none of them belong to the first
664 subrepository:
664 subrepository:
665
665
666 $ hg init subrepo-status
666 $ hg init subrepo-status
667 $ cd subrepo-status
667 $ cd subrepo-status
668 $ hg init subrepo-1
668 $ hg init subrepo-1
669 $ hg init subrepo-2
669 $ hg init subrepo-2
670 $ cd subrepo-2
670 $ cd subrepo-2
671 $ touch file
671 $ touch file
672 $ hg add file
672 $ hg add file
673 $ cd ..
673 $ cd ..
674 $ echo subrepo-1 = subrepo-1 > .hgsub
674 $ echo subrepo-1 = subrepo-1 > .hgsub
675 $ echo subrepo-2 = subrepo-2 >> .hgsub
675 $ echo subrepo-2 = subrepo-2 >> .hgsub
676 $ hg add .hgsub
676 $ hg add .hgsub
677 $ hg ci -m 'Added subrepos'
677 $ hg ci -m 'Added subrepos'
678 committing subrepository subrepo-1
678 committing subrepository subrepo-1
679 committing subrepository subrepo-2
679 committing subrepository subrepo-2
680 $ hg st subrepo-2/file
680 $ hg st subrepo-2/file
681
681
682 Check hg update --clean
682 Check hg update --clean
683 $ cd $TESTTMP/sub/t
683 $ cd $TESTTMP/sub/t
684 $ rm -r t/t.orig
684 $ rm -r t/t.orig
685 $ hg status -S --all
685 $ hg status -S --all
686 C .hgsub
686 C .hgsub
687 C .hgsubstate
687 C .hgsubstate
688 C a
688 C a
689 C s/.hgsub
689 C s/.hgsub
690 C s/.hgsubstate
690 C s/.hgsubstate
691 C s/a
691 C s/a
692 C s/ss/a
692 C s/ss/a
693 C t/t
693 C t/t
694 $ echo c1 > s/a
694 $ echo c1 > s/a
695 $ cd s
695 $ cd s
696 $ echo c1 > b
696 $ echo c1 > b
697 $ echo c1 > c
697 $ echo c1 > c
698 $ hg add b
698 $ hg add b
699 $ cd ..
699 $ cd ..
700 $ hg status -S
700 $ hg status -S
701 M s/a
701 M s/a
702 A s/b
702 A s/b
703 ? s/c
703 ? s/c
704 $ hg update -C
704 $ hg update -C
705 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
705 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
706 $ hg status -S
706 $ hg status -S
707 ? s/b
707 ? s/b
708 ? s/c
708 ? s/c
709
710 Sticky subrepositories, no changes
711 $ cd $TESTTMP/sub/t
712 $ hg id
713 925c17564ef8 tip
714 $ hg -R s id
715 12a213df6fa9 tip
716 $ hg -R t id
717 52c0adc0515a tip
718 $ hg update 11
719 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
720 $ hg id
721 365661e5936a
722 $ hg -R s id
723 fc627a69481f
724 $ hg -R t id
725 e95bcfa18a35
726
727 Sticky subrepositorys, file changes
728 $ touch s/f1
729 $ touch t/f1
730 $ hg add -S s/f1
731 $ hg add -S t/f1
732 $ hg id
733 365661e5936a
734 $ hg -R s id
735 fc627a69481f+
736 $ hg -R t id
737 e95bcfa18a35+
738 $ hg update tip
739 subrepository sources for s differ
740 use (l)ocal source (fc627a69481f) or (r)emote source (12a213df6fa9)?
741 l
742 subrepository sources for t differ
743 use (l)ocal source (e95bcfa18a35) or (r)emote source (52c0adc0515a)?
744 l
745 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
746 $ hg id
747 925c17564ef8+ tip
748 $ hg -R s id
749 fc627a69481f+
750 $ hg -R t id
751 e95bcfa18a35+
752 $ hg update --clean tip
753 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
754
755 Sticky subrepository, revision updates
756 $ hg id
757 925c17564ef8 tip
758 $ hg -R s id
759 12a213df6fa9 tip
760 $ hg -R t id
761 52c0adc0515a tip
762 $ cd s
763 $ hg update -r -2
764 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
765 $ cd ../t
766 $ hg update -r 2
767 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
768 $ cd ..
769 $ hg update 10
770 subrepository sources for t differ (in checked out version)
771 use (l)ocal source (7af322bc1198) or (r)emote source (20a0db6fbf6c)?
772 l
773 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
774 $ hg id
775 e45c8b14af55+
776 $ hg -R s id
777 1c833a7a9e3a
778 $ hg -R t id
779 7af322bc1198
780
781 Sticky subrepository, file changes and revision updates
782 $ touch s/f1
783 $ touch t/f1
784 $ hg add -S s/f1
785 $ hg add -S t/f1
786 $ hg id
787 e45c8b14af55+
788 $ hg -R s id
789 1c833a7a9e3a+
790 $ hg -R t id
791 7af322bc1198+
792 $ hg update tip
793 subrepository sources for s differ
794 use (l)ocal source (1c833a7a9e3a) or (r)emote source (12a213df6fa9)?
795 l
796 subrepository sources for t differ
797 use (l)ocal source (7af322bc1198) or (r)emote source (52c0adc0515a)?
798 l
799 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
800 $ hg id
801 925c17564ef8 tip
802 $ hg -R s id
803 1c833a7a9e3a+
804 $ hg -R t id
805 7af322bc1198+
806
807 Sticky repository, update --clean
808 $ hg update --clean tip
809 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
810 $ hg id
811 925c17564ef8 tip
812 $ hg -R s id
813 12a213df6fa9 tip
814 $ hg -R t id
815 52c0adc0515a tip
816
817 Test subrepo already at intended revision:
818 $ cd s
819 $ hg update fc627a69481f
820 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
821 $ cd ..
822 $ hg update 11
823 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
824 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
825 $ hg id -n
826 11+
827 $ hg -R s id
828 fc627a69481f
829 $ hg -R t id
830 e95bcfa18a35
General Comments 0
You need to be logged in to leave comments. Login now