182
182
result_branch = source_branch.sprout(
183
183
result, revision_id=revision_id, repository=result_repo)
184
184
if (create_tree_if_local and
185
result.open_branch(name="").name == result_branch.name and
186
185
isinstance(target_transport, LocalTransport) and
187
186
(result_repo is None or result_repo.make_working_trees())):
188
wt = result.create_workingtree(
187
result.create_workingtree(
189
188
accelerator_tree=accelerator_tree,
190
189
hardlink=hardlink, from_branch=result_branch)
193
if recurse == 'down':
194
with contextlib.ExitStack() as stack:
197
basis = wt.basis_tree()
198
elif result_branch is not None:
199
basis = result_branch.basis_tree()
200
elif source_branch is not None:
201
basis = source_branch.basis_tree()
202
if basis is not None:
203
stack.enter_context(basis.lock_read())
204
subtrees = basis.iter_references()
207
for path in subtrees:
208
target = urlutils.join(url, urlutils.escape(path))
209
sublocation = wt.reference_parent(
210
path, possible_transports=possible_transports)
211
if sublocation is None:
213
'Ignoring nested tree %s, parent location unknown.',
216
sublocation.controldir.sprout(
217
target, basis.get_reference_revision(path),
218
force_new_repo=force_new_repo, recurse=recurse,
220
if getattr(result_repo, '_git', None):
221
# Don't leak resources:
222
# TODO(jelmer): This shouldn't be git-specific, and possibly
223
# just use read locks.
224
result_repo._git.object_store.close()
227
192
def clone_on_transport(self, transport, revision_id=None,
228
193
force_new_repo=False, preserve_stacking=False,
229
194
stacked_on=None, create_prefix=False,
230
use_existing_dir=True, no_tree=False,
195
use_existing_dir=True, no_tree=False):
232
196
"""See ControlDir.clone_on_transport."""
233
197
from ..repository import InterRepository
234
198
from .mapping import default_mapping
235
from ..transport.local import LocalTransport
236
199
if stacked_on is not None:
237
200
raise _mod_branch.UnstackableBranchFormat(
238
201
self._format, self.user_url)
251
214
interrepo = InterRepository.get(source_repo, target_repo)
252
215
if revision_id is not None:
253
216
determine_wants = interrepo.get_determine_wants_revids(
254
[revision_id], include_tags=True, tag_selector=tag_selector)
217
[revision_id], include_tags=True)
256
219
determine_wants = interrepo.determine_wants_all
257
220
(pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
258
221
mapping=default_mapping)
259
for name, val in refs.items():
222
for name, val in viewitems(refs):
260
223
target_git_repo.refs[name] = val
261
result_dir = LocalGitDir(transport, target_git_repo, format)
224
result_dir = self.__class__(transport, target_git_repo, format)
262
225
if revision_id is not None:
263
226
result_dir.open_branch().set_last_revision(revision_id)
264
if not no_tree and isinstance(result_dir.root_transport, LocalTransport):
228
# Cheaper to check if the target is not local, than to try making
230
result_dir.root_transport.local_abspath('.')
265
231
if result_dir.open_repository().make_working_trees():
267
local_wt = self.open_workingtree()
268
except brz_errors.NoWorkingTree:
270
except brz_errors.NotLocalUrl:
271
result_dir.create_workingtree(revision_id=revision_id)
273
local_wt.clone(result_dir, revision_id=revision_id)
232
self.open_workingtree().clone(
233
result_dir, revision_id=revision_id)
234
except (brz_errors.NoWorkingTree, brz_errors.NotLocalUrl):
275
237
return result_dir
306
268
return UseExistingRepository(self.find_repository())
308
def branch_names(self):
309
from .refs import ref_to_branch_name
311
for ref in self.get_refs_container().keys():
313
branch_name = ref_to_branch_name(ref)
314
except UnicodeDecodeError:
315
trace.warning("Ignoring branch %r with unicode error ref", ref)
319
ret.append(branch_name)
322
270
def get_branches(self):
323
271
from .refs import ref_to_branch_name
325
273
for ref in self.get_refs_container().keys():
327
275
branch_name = ref_to_branch_name(ref)
328
278
except UnicodeDecodeError:
329
279
trace.warning("Ignoring branch %r with unicode error ref", ref)
333
281
ret[branch_name] = self.open_branch(ref=ref)
339
287
def push_branch(self, source, revision_id=None, overwrite=False,
340
288
remember=False, create_prefix=False, lossy=False,
341
name=None, tag_selector=None):
342
290
"""Push the source branch into this ControlDir."""
343
291
push_result = GitPushResult()
344
292
push_result.workingtree_updated = None
351
299
target = self.open_branch(name, nascent_ok=True)
352
300
push_result.branch_push_result = source.push(
353
301
target, overwrite=overwrite, stop_revision=revision_id,
354
lossy=lossy, tag_selector=tag_selector)
355
303
push_result.new_revid = push_result.branch_push_result.new_revid
356
304
push_result.old_revid = push_result.branch_push_result.old_revid
358
wt = self.open_workingtree()
359
except brz_errors.NoWorkingTree:
360
push_result.workingtree_updated = None
362
if self.open_branch(name="").name == target.name:
364
old_revision=push_result.old_revid,
365
new_revision=push_result.new_revid)
366
push_result.workingtree_updated = True
368
push_result.workingtree_updated = False
369
305
push_result.target_branch = target
370
306
if source.get_push_location() is None or remember:
371
307
source.set_push_location(push_result.target_branch.base)
402
338
from .transportgit import TransportRepo
404
340
def _open(transport):
406
return TransportRepo(transport, self.bare,
407
refs_text=getattr(self, "_refs_text", None))
408
except ValueError as e:
409
if e.args == ('Expected file to start with \'gitdir: \'', ):
410
raise brz_errors.NotBranchError(path=transport.base)
341
return TransportRepo(transport, self.bare,
342
refs_text=getattr(self, "_refs_text", None))
413
344
def redirected(transport, e, redirection_notice):
414
345
trace.note(redirection_notice)
415
346
return transport._redirected_to(e.source, e.target)
416
347
gitrepo = do_catching_redirections(_open, transport, redirected)
417
if not _found and not gitrepo._controltransport.has('objects'):
348
if not gitrepo._controltransport.has('HEAD'):
418
349
raise brz_errors.NotBranchError(path=transport.base)
419
350
return LocalGitDir(transport, gitrepo, self)
473
401
raise brz_errors.NotBranchError(path=transport.base)
474
402
return external_url.startswith("file:")
476
def is_control_filename(self, filename):
477
return (filename == '.git'
478
or filename.startswith('.git/')
479
or filename.startswith('.git\\'))
482
405
class BareLocalGitControlDirFormat(LocalGitControlDirFormat):
523
443
self.transport = transport.clone('.git')
524
444
self._mode_check_done = None
446
def is_control_filename(self, filename):
447
return (filename == '.git'
448
or filename.startswith('.git/')
449
or filename.startswith('.git\\'))
526
451
def _get_symref(self, ref):
527
452
ref_chain, unused_sha = self._git.refs.follow(ref)
528
453
if len(ref_chain) == 1:
546
471
target_branch._format, self._format)
547
472
# TODO(jelmer): Do some consistency checking across branches..
548
473
self.control_transport.put_bytes(
549
'commondir', encode_git_path(target_path))
474
'commondir', target_path.encode('utf-8'))
550
475
# TODO(jelmer): Urgh, avoid mucking about with internals.
551
476
self._git._commontransport = (
552
477
target_branch.repository._git._commontransport.clone())
586
511
base_url = self.user_url.rstrip('/')
588
513
base_url = urlutils.local_path_to_url(
589
decode_git_path(commondir)).rstrip('/.git/') + '/'
514
commondir.decode(osutils._fs_enc)).rstrip('/.git/') + '/'
516
params = {k: v.encode('utf-8') for (k, v) in viewitems(params)}
590
517
return urlutils.join_segment_parameters(base_url, params)