##// END OF EJS Templates
subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot -
r10666:4c50a90b stable
parent child Browse files
Show More
@@ -1,361 +1,369 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
8 import errno, os, re, xml.dom.minidom, shutil
9 from i18n import _
9 from i18n import _
10 import config, util, node, error
10 import config, util, node, error
11 hg = None
11 hg = None
12
12
13 nullstate = ('', '', 'empty')
13 nullstate = ('', '', 'empty')
14
14
15 def state(ctx):
15 def state(ctx):
16 p = config.config()
16 p = config.config()
17 def read(f, sections=None, remap=None):
17 def read(f, sections=None, remap=None):
18 if f in ctx:
18 if f in ctx:
19 p.parse(f, ctx[f].data(), sections, remap, read)
19 p.parse(f, ctx[f].data(), sections, remap, read)
20 else:
20 else:
21 raise util.Abort(_("subrepo spec file %s not found") % f)
21 raise util.Abort(_("subrepo spec file %s not found") % f)
22
22
23 if '.hgsub' in ctx:
23 if '.hgsub' in ctx:
24 read('.hgsub')
24 read('.hgsub')
25
25
26 rev = {}
26 rev = {}
27 if '.hgsubstate' in ctx:
27 if '.hgsubstate' in ctx:
28 try:
28 try:
29 for l in ctx['.hgsubstate'].data().splitlines():
29 for l in ctx['.hgsubstate'].data().splitlines():
30 revision, path = l.split(" ", 1)
30 revision, path = l.split(" ", 1)
31 rev[path] = revision
31 rev[path] = revision
32 except IOError, err:
32 except IOError, err:
33 if err.errno != errno.ENOENT:
33 if err.errno != errno.ENOENT:
34 raise
34 raise
35
35
36 state = {}
36 state = {}
37 for path, src in p[''].items():
37 for path, src in p[''].items():
38 kind = 'hg'
38 kind = 'hg'
39 if src.startswith('['):
39 if src.startswith('['):
40 if ']' not in src:
40 if ']' not in src:
41 raise util.Abort(_('missing ] in subrepo source'))
41 raise util.Abort(_('missing ] in subrepo source'))
42 kind, src = src.split(']', 1)
42 kind, src = src.split(']', 1)
43 kind = kind[1:]
43 kind = kind[1:]
44 state[path] = (src.strip(), rev.get(path, ''), kind)
44 state[path] = (src.strip(), rev.get(path, ''), kind)
45
45
46 return state
46 return state
47
47
48 def writestate(repo, state):
48 def writestate(repo, state):
49 repo.wwrite('.hgsubstate',
49 repo.wwrite('.hgsubstate',
50 ''.join(['%s %s\n' % (state[s][1], s)
50 ''.join(['%s %s\n' % (state[s][1], s)
51 for s in sorted(state)]), '')
51 for s in sorted(state)]), '')
52
52
53 def submerge(repo, wctx, mctx, actx):
53 def submerge(repo, wctx, mctx, actx):
54 # working context, merging context, ancestor context
54 # working context, merging context, ancestor context
55 if mctx == actx: # backwards?
55 if mctx == actx: # backwards?
56 actx = wctx.p1()
56 actx = wctx.p1()
57 s1 = wctx.substate
57 s1 = wctx.substate
58 s2 = mctx.substate
58 s2 = mctx.substate
59 sa = actx.substate
59 sa = actx.substate
60 sm = {}
60 sm = {}
61
61
62 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
62 repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
63
63
64 def debug(s, msg, r=""):
64 def debug(s, msg, r=""):
65 if r:
65 if r:
66 r = "%s:%s:%s" % r
66 r = "%s:%s:%s" % r
67 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
67 repo.ui.debug(" subrepo %s: %s %s\n" % (s, msg, r))
68
68
69 for s, l in s1.items():
69 for s, l in s1.items():
70 if wctx != actx and wctx.sub(s).dirty():
70 if wctx != actx and wctx.sub(s).dirty():
71 l = (l[0], l[1] + "+")
71 l = (l[0], l[1] + "+")
72 a = sa.get(s, nullstate)
72 a = sa.get(s, nullstate)
73 if s in s2:
73 if s in s2:
74 r = s2[s]
74 r = s2[s]
75 if l == r or r == a: # no change or local is newer
75 if l == r or r == a: # no change or local is newer
76 sm[s] = l
76 sm[s] = l
77 continue
77 continue
78 elif l == a: # other side changed
78 elif l == a: # other side changed
79 debug(s, "other changed, get", r)
79 debug(s, "other changed, get", r)
80 wctx.sub(s).get(r)
80 wctx.sub(s).get(r)
81 sm[s] = r
81 sm[s] = r
82 elif l[0] != r[0]: # sources differ
82 elif l[0] != r[0]: # sources differ
83 if repo.ui.promptchoice(
83 if repo.ui.promptchoice(
84 _(' subrepository sources for %s differ\n'
84 _(' subrepository sources for %s differ\n'
85 'use (l)ocal source (%s) or (r)emote source (%s)?')
85 'use (l)ocal source (%s) or (r)emote source (%s)?')
86 % (s, l[0], r[0]),
86 % (s, l[0], r[0]),
87 (_('&Local'), _('&Remote')), 0):
87 (_('&Local'), _('&Remote')), 0):
88 debug(s, "prompt changed, get", r)
88 debug(s, "prompt changed, get", r)
89 wctx.sub(s).get(r)
89 wctx.sub(s).get(r)
90 sm[s] = r
90 sm[s] = r
91 elif l[1] == a[1]: # local side is unchanged
91 elif l[1] == a[1]: # local side is unchanged
92 debug(s, "other side changed, get", r)
92 debug(s, "other side changed, get", r)
93 wctx.sub(s).get(r)
93 wctx.sub(s).get(r)
94 sm[s] = r
94 sm[s] = r
95 else:
95 else:
96 debug(s, "both sides changed, merge with", r)
96 debug(s, "both sides changed, merge with", r)
97 wctx.sub(s).merge(r)
97 wctx.sub(s).merge(r)
98 sm[s] = l
98 sm[s] = l
99 elif l == a: # remote removed, local unchanged
99 elif l == a: # remote removed, local unchanged
100 debug(s, "remote removed, remove")
100 debug(s, "remote removed, remove")
101 wctx.sub(s).remove()
101 wctx.sub(s).remove()
102 else:
102 else:
103 if repo.ui.promptchoice(
103 if repo.ui.promptchoice(
104 _(' local changed subrepository %s which remote removed\n'
104 _(' local changed subrepository %s which remote removed\n'
105 'use (c)hanged version or (d)elete?') % s,
105 'use (c)hanged version or (d)elete?') % s,
106 (_('&Changed'), _('&Delete')), 0):
106 (_('&Changed'), _('&Delete')), 0):
107 debug(s, "prompt remove")
107 debug(s, "prompt remove")
108 wctx.sub(s).remove()
108 wctx.sub(s).remove()
109
109
110 for s, r in s2.items():
110 for s, r in s2.items():
111 if s in s1:
111 if s in s1:
112 continue
112 continue
113 elif s not in sa:
113 elif s not in sa:
114 debug(s, "remote added, get", r)
114 debug(s, "remote added, get", r)
115 mctx.sub(s).get(r)
115 mctx.sub(s).get(r)
116 sm[s] = r
116 sm[s] = r
117 elif r != sa[s]:
117 elif r != sa[s]:
118 if repo.ui.promptchoice(
118 if repo.ui.promptchoice(
119 _(' remote changed subrepository %s which local removed\n'
119 _(' remote changed subrepository %s which local removed\n'
120 'use (c)hanged version or (d)elete?') % s,
120 'use (c)hanged version or (d)elete?') % s,
121 (_('&Changed'), _('&Delete')), 0) == 0:
121 (_('&Changed'), _('&Delete')), 0) == 0:
122 debug(s, "prompt recreate", r)
122 debug(s, "prompt recreate", r)
123 wctx.sub(s).get(r)
123 wctx.sub(s).get(r)
124 sm[s] = r
124 sm[s] = r
125
125
126 # record merged .hgsubstate
126 # record merged .hgsubstate
127 writestate(repo, sm)
127 writestate(repo, sm)
128
128
129 def _abssource(repo, push=False):
129 def _abssource(repo, push=False):
130 if hasattr(repo, '_subparent'):
130 if hasattr(repo, '_subparent'):
131 source = repo._subsource
131 source = repo._subsource
132 if source.startswith('/') or '://' in source:
132 if source.startswith('/') or '://' in source:
133 return source
133 return source
134 parent = _abssource(repo._subparent, push)
134 parent = _abssource(repo._subparent, push)
135 if '://' in parent:
135 if '://' in parent:
136 if parent[-1] == '/':
136 if parent[-1] == '/':
137 parent = parent[:-1]
137 parent = parent[:-1]
138 return parent + '/' + source
138 return parent + '/' + source
139 return os.path.join(parent, repo._subsource)
139 return os.path.join(parent, repo._subsource)
140 if push and repo.ui.config('paths', 'default-push'):
140 if push and repo.ui.config('paths', 'default-push'):
141 return repo.ui.config('paths', 'default-push', repo.root)
141 return repo.ui.config('paths', 'default-push', repo.root)
142 return repo.ui.config('paths', 'default', repo.root)
142 return repo.ui.config('paths', 'default', repo.root)
143
143
144 def subrepo(ctx, path):
144 def subrepo(ctx, path):
145 # subrepo inherently violates our import layering rules
145 # subrepo inherently violates our import layering rules
146 # because it wants to make repo objects from deep inside the stack
146 # because it wants to make repo objects from deep inside the stack
147 # so we manually delay the circular imports to not break
147 # so we manually delay the circular imports to not break
148 # scripts that don't use our demand-loading
148 # scripts that don't use our demand-loading
149 global hg
149 global hg
150 import hg as h
150 import hg as h
151 hg = h
151 hg = h
152
152
153 util.path_auditor(ctx._repo.root)(path)
153 util.path_auditor(ctx._repo.root)(path)
154 state = ctx.substate.get(path, nullstate)
154 state = ctx.substate.get(path, nullstate)
155 if state[2] not in types:
155 if state[2] not in types:
156 raise util.Abort(_('unknown subrepo type %s') % state[2])
156 raise util.Abort(_('unknown subrepo type %s') % state[2])
157 return types[state[2]](ctx, path, state[:2])
157 return types[state[2]](ctx, path, state[:2])
158
158
159 # subrepo classes need to implement the following methods:
159 # subrepo classes need to implement the following methods:
160 # __init__(self, ctx, path, state)
160 # __init__(self, ctx, path, state)
161 # dirty(self): returns true if the dirstate of the subrepo
161 # dirty(self): returns true if the dirstate of the subrepo
162 # does not match current stored state
162 # does not match current stored state
163 # commit(self, text, user, date): commit the current changes
163 # commit(self, text, user, date): commit the current changes
164 # to the subrepo with the given log message. Use given
164 # to the subrepo with the given log message. Use given
165 # user and date if possible. Return the new state of the subrepo.
165 # user and date if possible. Return the new state of the subrepo.
166 # remove(self): remove the subrepo (should verify the dirstate
166 # remove(self): remove the subrepo (should verify the dirstate
167 # is not dirty first)
167 # is not dirty first)
168 # get(self, state): run whatever commands are needed to put the
168 # get(self, state): run whatever commands are needed to put the
169 # subrepo into this state
169 # subrepo into this state
170 # merge(self, state): merge currently-saved state with the new state.
170 # merge(self, state): merge currently-saved state with the new state.
171 # push(self, force): perform whatever action is analagous to 'hg push'
171 # push(self, force): perform whatever action is analagous to 'hg push'
172 # This may be a no-op on some systems.
172 # This may be a no-op on some systems.
173
173
174 class hgsubrepo(object):
174 class hgsubrepo(object):
175 def __init__(self, ctx, path, state):
175 def __init__(self, ctx, path, state):
176 self._path = path
176 self._path = path
177 self._state = state
177 self._state = state
178 r = ctx._repo
178 r = ctx._repo
179 root = r.wjoin(path)
179 root = r.wjoin(path)
180 if os.path.exists(os.path.join(root, '.hg')):
180 create = False
181 self._repo = hg.repository(r.ui, root)
181 if not os.path.exists(os.path.join(root, '.hg')):
182 else:
182 create = True
183 util.makedirs(root)
183 util.makedirs(root)
184 self._repo = hg.repository(r.ui, root, create=True)
184 self._repo = hg.repository(r.ui, root, create=create)
185 f = file(os.path.join(root, '.hg', 'hgrc'), 'w')
186 f.write('[paths]\ndefault = %s\n' % os.path.join(
187 _abssource(ctx._repo), path))
188 f.close()
189 self._repo._subparent = r
185 self._repo._subparent = r
190 self._repo._subsource = state[0]
186 self._repo._subsource = state[0]
191
187
188 if create:
189 fp = self._repo.opener("hgrc", "w", text=True)
190 fp.write('[paths]\n')
191
192 def addpathconfig(key, value):
193 fp.write('%s = %s\n' % (key, value))
194 self._repo.ui.setconfig('paths', key, value)
195
196 defpath = os.path.join(_abssource(ctx._repo), path)
197 addpathconfig('default', defpath)
198 fp.close()
199
192 def dirty(self):
200 def dirty(self):
193 r = self._state[1]
201 r = self._state[1]
194 if r == '':
202 if r == '':
195 return True
203 return True
196 w = self._repo[None]
204 w = self._repo[None]
197 if w.p1() != self._repo[r]: # version checked out changed
205 if w.p1() != self._repo[r]: # version checked out change
198 return True
206 return True
199 return w.dirty() # working directory changed
207 return w.dirty() # working directory changed
200
208
201 def commit(self, text, user, date):
209 def commit(self, text, user, date):
202 self._repo.ui.debug("committing subrepo %s\n" % self._path)
210 self._repo.ui.debug("committing subrepo %s\n" % self._path)
203 n = self._repo.commit(text, user, date)
211 n = self._repo.commit(text, user, date)
204 if not n:
212 if not n:
205 return self._repo['.'].hex() # different version checked out
213 return self._repo['.'].hex() # different version checked out
206 return node.hex(n)
214 return node.hex(n)
207
215
208 def remove(self):
216 def remove(self):
209 # we can't fully delete the repository as it may contain
217 # we can't fully delete the repository as it may contain
210 # local-only history
218 # local-only history
211 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
219 self._repo.ui.note(_('removing subrepo %s\n') % self._path)
212 hg.clean(self._repo, node.nullid, False)
220 hg.clean(self._repo, node.nullid, False)
213
221
214 def _get(self, state):
222 def _get(self, state):
215 source, revision, kind = state
223 source, revision, kind = state
216 try:
224 try:
217 self._repo.lookup(revision)
225 self._repo.lookup(revision)
218 except error.RepoError:
226 except error.RepoError:
219 self._repo._subsource = source
227 self._repo._subsource = source
220 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
228 self._repo.ui.status(_('pulling subrepo %s\n') % self._path)
221 srcurl = _abssource(self._repo)
229 srcurl = _abssource(self._repo)
222 other = hg.repository(self._repo.ui, srcurl)
230 other = hg.repository(self._repo.ui, srcurl)
223 self._repo.pull(other)
231 self._repo.pull(other)
224
232
225 def get(self, state):
233 def get(self, state):
226 self._get(state)
234 self._get(state)
227 source, revision, kind = state
235 source, revision, kind = state
228 self._repo.ui.debug("getting subrepo %s\n" % self._path)
236 self._repo.ui.debug("getting subrepo %s\n" % self._path)
229 hg.clean(self._repo, revision, False)
237 hg.clean(self._repo, revision, False)
230
238
231 def merge(self, state):
239 def merge(self, state):
232 self._get(state)
240 self._get(state)
233 cur = self._repo['.']
241 cur = self._repo['.']
234 dst = self._repo[state[1]]
242 dst = self._repo[state[1]]
235 anc = dst.ancestor(cur)
243 anc = dst.ancestor(cur)
236 if anc == cur:
244 if anc == cur:
237 self._repo.ui.debug("updating subrepo %s\n" % self._path)
245 self._repo.ui.debug("updating subrepo %s\n" % self._path)
238 hg.update(self._repo, state[1])
246 hg.update(self._repo, state[1])
239 elif anc == dst:
247 elif anc == dst:
240 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
248 self._repo.ui.debug("skipping subrepo %s\n" % self._path)
241 else:
249 else:
242 self._repo.ui.debug("merging subrepo %s\n" % self._path)
250 self._repo.ui.debug("merging subrepo %s\n" % self._path)
243 hg.merge(self._repo, state[1], remind=False)
251 hg.merge(self._repo, state[1], remind=False)
244
252
245 def push(self, force):
253 def push(self, force):
246 # push subrepos depth-first for coherent ordering
254 # push subrepos depth-first for coherent ordering
247 c = self._repo['']
255 c = self._repo['']
248 subs = c.substate # only repos that are committed
256 subs = c.substate # only repos that are committed
249 for s in sorted(subs):
257 for s in sorted(subs):
250 c.sub(s).push(force)
258 c.sub(s).push(force)
251
259
252 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
260 self._repo.ui.status(_('pushing subrepo %s\n') % self._path)
253 dsturl = _abssource(self._repo, True)
261 dsturl = _abssource(self._repo, True)
254 other = hg.repository(self._repo.ui, dsturl)
262 other = hg.repository(self._repo.ui, dsturl)
255 self._repo.push(other, force)
263 self._repo.push(other, force)
256
264
257 class svnsubrepo(object):
265 class svnsubrepo(object):
258 def __init__(self, ctx, path, state):
266 def __init__(self, ctx, path, state):
259 self._path = path
267 self._path = path
260 self._state = state
268 self._state = state
261 self._ctx = ctx
269 self._ctx = ctx
262 self._ui = ctx._repo.ui
270 self._ui = ctx._repo.ui
263
271
264 def _svncommand(self, commands):
272 def _svncommand(self, commands):
265 cmd = ['svn'] + commands + [self._path]
273 cmd = ['svn'] + commands + [self._path]
266 cmd = [util.shellquote(arg) for arg in cmd]
274 cmd = [util.shellquote(arg) for arg in cmd]
267 cmd = util.quotecommand(' '.join(cmd))
275 cmd = util.quotecommand(' '.join(cmd))
268 env = dict(os.environ)
276 env = dict(os.environ)
269 # Avoid localized output, preserve current locale for everything else.
277 # Avoid localized output, preserve current locale for everything else.
270 env['LC_MESSAGES'] = 'C'
278 env['LC_MESSAGES'] = 'C'
271 write, read, err = util.popen3(cmd, env=env, newlines=True)
279 write, read, err = util.popen3(cmd, env=env, newlines=True)
272 retdata = read.read()
280 retdata = read.read()
273 err = err.read().strip()
281 err = err.read().strip()
274 if err:
282 if err:
275 raise util.Abort(err)
283 raise util.Abort(err)
276 return retdata
284 return retdata
277
285
278 def _wcrev(self):
286 def _wcrev(self):
279 output = self._svncommand(['info', '--xml'])
287 output = self._svncommand(['info', '--xml'])
280 doc = xml.dom.minidom.parseString(output)
288 doc = xml.dom.minidom.parseString(output)
281 entries = doc.getElementsByTagName('entry')
289 entries = doc.getElementsByTagName('entry')
282 if not entries:
290 if not entries:
283 return 0
291 return 0
284 return int(entries[0].getAttribute('revision') or 0)
292 return int(entries[0].getAttribute('revision') or 0)
285
293
286 def _wcchanged(self):
294 def _wcchanged(self):
287 """Return (changes, extchanges) where changes is True
295 """Return (changes, extchanges) where changes is True
288 if the working directory was changed, and extchanges is
296 if the working directory was changed, and extchanges is
289 True if any of these changes concern an external entry.
297 True if any of these changes concern an external entry.
290 """
298 """
291 output = self._svncommand(['status', '--xml'])
299 output = self._svncommand(['status', '--xml'])
292 externals, changes = [], []
300 externals, changes = [], []
293 doc = xml.dom.minidom.parseString(output)
301 doc = xml.dom.minidom.parseString(output)
294 for e in doc.getElementsByTagName('entry'):
302 for e in doc.getElementsByTagName('entry'):
295 s = e.getElementsByTagName('wc-status')
303 s = e.getElementsByTagName('wc-status')
296 if not s:
304 if not s:
297 continue
305 continue
298 item = s[0].getAttribute('item')
306 item = s[0].getAttribute('item')
299 props = s[0].getAttribute('props')
307 props = s[0].getAttribute('props')
300 path = e.getAttribute('path')
308 path = e.getAttribute('path')
301 if item == 'external':
309 if item == 'external':
302 externals.append(path)
310 externals.append(path)
303 if (item not in ('', 'normal', 'unversioned', 'external')
311 if (item not in ('', 'normal', 'unversioned', 'external')
304 or props not in ('', 'none')):
312 or props not in ('', 'none')):
305 changes.append(path)
313 changes.append(path)
306 for path in changes:
314 for path in changes:
307 for ext in externals:
315 for ext in externals:
308 if path == ext or path.startswith(ext + os.sep):
316 if path == ext or path.startswith(ext + os.sep):
309 return True, True
317 return True, True
310 return bool(changes), False
318 return bool(changes), False
311
319
312 def dirty(self):
320 def dirty(self):
313 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
321 if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
314 return False
322 return False
315 return True
323 return True
316
324
317 def commit(self, text, user, date):
325 def commit(self, text, user, date):
318 # user and date are out of our hands since svn is centralized
326 # user and date are out of our hands since svn is centralized
319 changed, extchanged = self._wcchanged()
327 changed, extchanged = self._wcchanged()
320 if not changed:
328 if not changed:
321 return self._wcrev()
329 return self._wcrev()
322 if extchanged:
330 if extchanged:
323 # Do not try to commit externals
331 # Do not try to commit externals
324 raise util.Abort(_('cannot commit svn externals'))
332 raise util.Abort(_('cannot commit svn externals'))
325 commitinfo = self._svncommand(['commit', '-m', text])
333 commitinfo = self._svncommand(['commit', '-m', text])
326 self._ui.status(commitinfo)
334 self._ui.status(commitinfo)
327 newrev = re.search('Committed revision ([\d]+).', commitinfo)
335 newrev = re.search('Committed revision ([\d]+).', commitinfo)
328 if not newrev:
336 if not newrev:
329 raise util.Abort(commitinfo.splitlines()[-1])
337 raise util.Abort(commitinfo.splitlines()[-1])
330 newrev = newrev.groups()[0]
338 newrev = newrev.groups()[0]
331 self._ui.status(self._svncommand(['update', '-r', newrev]))
339 self._ui.status(self._svncommand(['update', '-r', newrev]))
332 return newrev
340 return newrev
333
341
334 def remove(self):
342 def remove(self):
335 if self.dirty():
343 if self.dirty():
336 self._ui.warn(_('not removing repo %s because '
344 self._ui.warn(_('not removing repo %s because '
337 'it has changes.\n' % self._path))
345 'it has changes.\n' % self._path))
338 return
346 return
339 self._ui.note(_('removing subrepo %s\n') % self._path)
347 self._ui.note(_('removing subrepo %s\n') % self._path)
340 shutil.rmtree(self._ctx.repo.join(self._path))
348 shutil.rmtree(self._ctx.repo.join(self._path))
341
349
342 def get(self, state):
350 def get(self, state):
343 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
351 status = self._svncommand(['checkout', state[0], '--revision', state[1]])
344 if not re.search('Checked out revision [\d]+.', status):
352 if not re.search('Checked out revision [\d]+.', status):
345 raise util.Abort(status.splitlines()[-1])
353 raise util.Abort(status.splitlines()[-1])
346 self._ui.status(status)
354 self._ui.status(status)
347
355
348 def merge(self, state):
356 def merge(self, state):
349 old = int(self._state[1])
357 old = int(self._state[1])
350 new = int(state[1])
358 new = int(state[1])
351 if new > old:
359 if new > old:
352 self.get(state)
360 self.get(state)
353
361
354 def push(self, force):
362 def push(self, force):
355 # nothing for svn
363 # nothing for svn
356 pass
364 pass
357
365
358 types = {
366 types = {
359 'hg': hgsubrepo,
367 'hg': hgsubrepo,
360 'svn': svnsubrepo,
368 'svn': svnsubrepo,
361 }
369 }
General Comments 0
You need to be logged in to leave comments. Login now