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
185
186
isinstance(target_transport, LocalTransport) and
186
187
(result_repo is None or result_repo.make_working_trees())):
187
result.create_workingtree(
188
wt = result.create_workingtree(
188
189
accelerator_tree=accelerator_tree,
189
190
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()
192
227
def clone_on_transport(self, transport, revision_id=None,
193
228
force_new_repo=False, preserve_stacking=False,
194
229
stacked_on=None, create_prefix=False,
195
use_existing_dir=True, no_tree=False):
230
use_existing_dir=True, no_tree=False,
196
232
"""See ControlDir.clone_on_transport."""
197
233
from ..repository import InterRepository
198
234
from .mapping import default_mapping
235
from ..transport.local import LocalTransport
199
236
if stacked_on is not None:
200
237
raise _mod_branch.UnstackableBranchFormat(
201
238
self._format, self.user_url)
214
251
interrepo = InterRepository.get(source_repo, target_repo)
215
252
if revision_id is not None:
216
253
determine_wants = interrepo.get_determine_wants_revids(
217
[revision_id], include_tags=True)
254
[revision_id], include_tags=True, tag_selector=tag_selector)
219
256
determine_wants = interrepo.determine_wants_all
220
257
(pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
221
258
mapping=default_mapping)
222
for name, val in viewitems(refs):
259
for name, val in refs.items():
223
260
target_git_repo.refs[name] = val
224
result_dir = self.__class__(transport, target_git_repo, format)
261
result_dir = LocalGitDir(transport, target_git_repo, format)
225
262
if revision_id is not None:
226
263
result_dir.open_branch().set_last_revision(revision_id)
228
# Cheaper to check if the target is not local, than to try making
230
result_dir.root_transport.local_abspath('.')
264
if not no_tree and isinstance(result_dir.root_transport, LocalTransport):
231
265
if result_dir.open_repository().make_working_trees():
232
self.open_workingtree().clone(
233
result_dir, revision_id=revision_id)
234
except (brz_errors.NoWorkingTree, brz_errors.NotLocalUrl):
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)
237
275
return result_dir
268
306
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)
270
322
def get_branches(self):
271
323
from .refs import ref_to_branch_name
273
325
for ref in self.get_refs_container().keys():
275
327
branch_name = ref_to_branch_name(ref)
278
328
except UnicodeDecodeError:
279
329
trace.warning("Ignoring branch %r with unicode error ref", ref)
281
333
ret[branch_name] = self.open_branch(ref=ref)
287
339
def push_branch(self, source, revision_id=None, overwrite=False,
288
340
remember=False, create_prefix=False, lossy=False,
341
name=None, tag_selector=None):
290
342
"""Push the source branch into this ControlDir."""
291
343
push_result = GitPushResult()
292
344
push_result.workingtree_updated = None
299
351
target = self.open_branch(name, nascent_ok=True)
300
352
push_result.branch_push_result = source.push(
301
353
target, overwrite=overwrite, stop_revision=revision_id,
354
lossy=lossy, tag_selector=tag_selector)
303
355
push_result.new_revid = push_result.branch_push_result.new_revid
304
356
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
305
369
push_result.target_branch = target
306
370
if source.get_push_location() is None or remember:
307
371
source.set_push_location(push_result.target_branch.base)
338
402
from .transportgit import TransportRepo
340
404
def _open(transport):
341
return TransportRepo(transport, self.bare,
342
refs_text=getattr(self, "_refs_text", None))
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)
344
413
def redirected(transport, e, redirection_notice):
345
414
trace.note(redirection_notice)
346
415
return transport._redirected_to(e.source, e.target)
347
416
gitrepo = do_catching_redirections(_open, transport, redirected)
348
if not gitrepo._controltransport.has('HEAD'):
417
if not _found and not gitrepo._controltransport.has('objects'):
349
418
raise brz_errors.NotBranchError(path=transport.base)
350
419
return LocalGitDir(transport, gitrepo, self)
401
473
raise brz_errors.NotBranchError(path=transport.base)
402
474
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\\'))
405
482
class BareLocalGitControlDirFormat(LocalGitControlDirFormat):
443
523
self.transport = transport.clone('.git')
444
524
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\\'))
451
526
def _get_symref(self, ref):
452
527
ref_chain, unused_sha = self._git.refs.follow(ref)
453
528
if len(ref_chain) == 1:
471
546
target_branch._format, self._format)
472
547
# TODO(jelmer): Do some consistency checking across branches..
473
548
self.control_transport.put_bytes(
474
'commondir', target_path.encode('utf-8'))
549
'commondir', encode_git_path(target_path))
475
550
# TODO(jelmer): Urgh, avoid mucking about with internals.
476
551
self._git._commontransport = (
477
552
target_branch.repository._git._commontransport.clone())
511
586
base_url = self.user_url.rstrip('/')
513
588
base_url = urlutils.local_path_to_url(
514
commondir.decode(osutils._fs_enc)).rstrip('/.git/') + '/'
516
params = {k: v.encode('utf-8') for (k, v) in viewitems(params)}
589
decode_git_path(commondir)).rstrip('/.git/') + '/'
517
590
return urlutils.join_segment_parameters(base_url, params)