106
105
self.branch = branch
107
106
self.repository = branch.repository
109
def _merge_to_remote_git(self, target_repo, source_tag_refs, overwrite=False):
108
def _merge_to_remote_git(self, target_repo, source_tag_refs,
112
113
def get_changed_refs(old_refs):
113
114
ret = dict(old_refs)
114
for ref_name, tag_name, peeled, unpeeled in source_tag_refs.iteritems():
115
for ref_name, tag_name, peeled, unpeeled in (
116
source_tag_refs.iteritems()):
115
117
if old_refs.get(ref_name) == unpeeled:
117
elif overwrite or not ref_name in old_refs:
119
elif overwrite or ref_name not in old_refs:
118
120
ret[ref_name] = unpeeled
119
updates[tag_name] = target_repo.lookup_foreign_revision_id(peeled)
121
updates[tag_name] = target_repo.lookup_foreign_revision_id(
121
124
conflicts.append(
123
self.repository.lookup_foreign_revision_id(peeled),
124
target_repo.lookup_foreign_revision_id(old_refs[ref_name])))
126
self.repository.lookup_foreign_revision_id(peeled),
127
target_repo.lookup_foreign_revision_id(
128
old_refs[ref_name])))
126
target_repo.controldir.send_pack(get_changed_refs, lambda have, want: [])
130
target_repo.controldir.send_pack(
131
get_changed_refs, lambda have, want: [])
127
132
return updates, conflicts
129
def _merge_to_local_git(self, target_repo, source_tag_refs, overwrite=False):
134
def _merge_to_local_git(self, target_repo, source_tag_refs,
132
138
for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
133
139
if target_repo._git.refs.get(ref_name) == unpeeled:
135
elif overwrite or not ref_name in target_repo._git.refs:
141
elif overwrite or ref_name not in target_repo._git.refs:
136
142
target_repo._git.refs[ref_name] = unpeeled or peeled
138
updates[tag_name] = self.repository.lookup_foreign_revision_id(peeled)
144
updates[tag_name] = (
145
self.repository.lookup_foreign_revision_id(peeled))
140
147
trace.warning('%s does not point to a valid object',
145
source_revid = self.repository.lookup_foreign_revision_id(peeled)
152
source_revid = self.repository.lookup_foreign_revision_id(
146
154
target_revid = target_repo.lookup_foreign_revision_id(
147
target_repo._git.refs[ref_name])
155
target_repo._git.refs[ref_name])
149
157
trace.warning('%s does not point to a valid object',
160
168
if getattr(target_repo, "_git", None):
161
return self._merge_to_local_git(target_repo, source_tag_refs, overwrite)
169
return self._merge_to_local_git(
170
target_repo, source_tag_refs, overwrite)
163
return self._merge_to_remote_git(target_repo, source_tag_refs, overwrite)
172
return self._merge_to_remote_git(
173
target_repo, source_tag_refs, overwrite)
165
175
to_tags.branch._tag_refs = None
182
192
result[tag_name] = bzr_revid
183
193
updates[tag_name] = bzr_revid
185
conflicts.append((tag_name, bzr_revid, result[n]))
195
conflicts.append((tag_name, bzr_revid, result[tag_name]))
186
196
to_tags._set_tag_dict(result)
187
197
if len(unpeeled_map) > 0:
188
198
map_file = UnpeelMap.from_repository(to_tags.branch.repository)
208
218
if master is not None:
209
219
master.lock_write()
211
updates, conflicts = self._merge_to_non_git(to_tags, source_tag_refs,
221
updates, conflicts = self._merge_to_non_git(
222
to_tags, source_tag_refs, overwrite=overwrite)
213
223
if master is not None:
214
224
extra_updates, extra_conflicts = self.merge_to(
215
225
master.tags, overwrite=overwrite,
216
source_tag_refs=source_tag_refs,
217
ignore_master=ignore_master)
226
source_tag_refs=source_tag_refs,
227
ignore_master=ignore_master)
218
228
updates.update(extra_updates)
219
229
conflicts += extra_conflicts
220
230
return updates, conflicts
326
337
from .dir import LocalGitDir
327
338
if not isinstance(a_controldir, LocalGitDir):
328
339
raise errors.IncompatibleFormat(self, a_controldir._format)
329
return a_controldir.create_branch(repository=repository, name=name,
340
return a_controldir.create_branch(
341
repository=repository, name=name,
330
342
append_revisions_only=append_revisions_only)
398
410
if getattr(self.repository, '_git', None):
399
411
cs = self.repository._git.get_config_stack()
401
return cs.get((b"branch", self.name.encode('utf-8')), b"nick").decode("utf-8")
413
return cs.get((b"branch", self.name.encode('utf-8')),
414
b"nick").decode("utf-8")
404
417
return self.name or u"HEAD"
406
419
def _set_nick(self, nick):
407
420
cf = self.repository._git.get_config()
408
cf.set((b"branch", self.name.encode('utf-8')), b"nick", nick.encode("utf-8"))
421
cf.set((b"branch", self.name.encode('utf-8')),
422
b"nick", nick.encode("utf-8"))
410
424
cf.write_to_file(f)
411
425
self.repository._git._put_named_file('config', f.getvalue())
415
429
def __repr__(self):
416
430
return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
419
def generate_revision_history(self, revid, last_rev=None, other_branch=None):
433
def generate_revision_history(self, revid, last_rev=None,
420
435
if last_rev is not None:
421
436
graph = self.repository.get_graph()
422
437
if not graph.is_ancestor(last_rev, revid):
587
602
def __init__(self, controldir, repository, ref):
588
603
super(LocalGitBranch, self).__init__(controldir, repository, ref,
589
LocalGitBranchFormat())
604
LocalGitBranchFormat())
591
606
def create_checkout(self, to_location, revision_id=None, lightweight=False,
592
accelerator_tree=None, hardlink=False):
607
accelerator_tree=None, hardlink=False):
593
608
t = transport.get_transport(to_location)
595
610
format = self._get_checkout_format(lightweight=lightweight)
598
613
from_branch = checkout.set_branch_reference(target_branch=self)
600
615
policy = checkout.determine_repository_policy()
601
repo = policy.acquire_repository()[0]
616
policy.acquire_repository()
603
617
checkout_branch = checkout.create_branch()
604
618
checkout_branch.bind(self)
605
619
checkout_branch.pull(self, stop_revision=revision_id)
606
620
from_branch = None
607
return checkout.create_workingtree(revision_id,
608
from_branch=from_branch, hardlink=hardlink)
621
return checkout.create_workingtree(
622
revision_id, from_branch=from_branch, hardlink=hardlink)
610
624
def _lock_ref(self):
611
625
self._ref_lock = self.repository._git.refs.lock_ref(self.ref)
626
640
last_revid = self.last_revision()
627
641
graph = self.repository.get_graph()
629
ret = list(graph.iter_lefthand_ancestry(last_revid,
630
(revision.NULL_REVISION, )))
643
ret = list(graph.iter_lefthand_ancestry(
644
last_revid, (revision.NULL_REVISION, )))
631
645
except errors.RevisionNotPresent as e:
632
646
raise errors.GhostRevisionsHaveNoRevno(last_revid, e.revision_id)
643
657
last_revid = self.last_revision()
644
658
graph = self.repository.get_graph()
646
revno = graph.find_distance_to_null(last_revid,
647
[(revision.NULL_REVISION, 0)])
660
revno = graph.find_distance_to_null(
661
last_revid, [(revision.NULL_REVISION, 0)])
648
662
except errors.GhostRevisionsHaveNoRevno:
650
664
return revno, last_revid
714
729
def create_memorytree(self):
715
730
from .memorytree import GitMemoryTree
716
return GitMemoryTree(self, self.repository._git.object_store, self.head)
731
return GitMemoryTree(self, self.repository._git.object_store,
718
734
def reference_parent(self, path, file_id=None, possible_transports=None):
719
735
"""Return the parent branch for a tree-reference file_id
725
741
# FIXME should provide multiple branches, based on config
726
742
url = urlutils.join(self.user_url, path)
727
743
return branch.Branch.open(
729
possible_transports=possible_transports)
745
possible_transports=possible_transports)
733
748
def _quick_lookup_revno(local_branch, remote_branch, revid):
740
755
except errors.NoSuchRevision:
741
756
graph = local_branch.repository.get_graph()
743
return graph.find_distance_to_null(revid,
744
[(revision.NULL_REVISION, 0)])
758
return graph.find_distance_to_null(
759
revid, [(revision.NULL_REVISION, 0)])
745
760
except errors.GhostRevisionsHaveNoRevno:
746
761
# FIXME: Check using graph.find_distance_to_null() ?
747
762
with remote_branch.lock_read():
762
777
to_file.write('No revisions to pull.\n')
763
778
elif self.new_git_head is not None:
764
779
to_file.write('Now on revision %d (git sha: %s).\n' %
765
(self.new_revno, self.new_git_head))
780
(self.new_revno, self.new_git_head))
767
782
to_file.write('Now on revision %d.\n' % (self.new_revno,))
768
783
self._show_tag_conficts(to_file)
770
785
def _lookup_revno(self, revid):
771
786
return _quick_lookup_revno(self.target_branch, self.source_branch,
774
789
def _get_old_revno(self):
775
790
if self._old_revno is not None:
830
845
def _get_interrepo(self, source, target):
831
return _mod_repository.InterRepository.get(source.repository, target.repository)
846
return _mod_repository.InterRepository.get(
847
source.repository, target.repository)
834
850
def is_compatible(cls, source, target):
837
853
if isinstance(target, GitBranch):
838
854
# InterLocalGitRemoteGitBranch or InterToGitBranch should be used
840
if getattr(cls._get_interrepo(source, target), "fetch_objects", None) is None:
856
if (getattr(cls._get_interrepo(source, target), "fetch_objects", None)
841
858
# fetch_objects is necessary for this to work
866
885
pack_hint, head, refs = interrepo.fetch_objects(
867
886
determine_wants, self.source.mapping, limit=limit)
868
887
if (pack_hint is not None and
869
self.target.repository._format.pack_compresses):
888
self.target.repository._format.pack_compresses):
870
889
self.target.repository.pack(hint=pack_hint)
871
890
return head, refs
876
895
prev_last_revid = None
878
897
prev_last_revid = self.target.last_revision()
879
self.target.generate_revision_history(self._last_revid,
880
last_rev=prev_last_revid, other_branch=self.source)
898
self.target.generate_revision_history(
899
self._last_revid, last_rev=prev_last_revid,
900
other_branch=self.source)
881
901
return head, refs
883
903
def _basic_pull(self, stop_revision, overwrite, run_hooks,
884
_override_hook_target, _hook_master):
904
_override_hook_target, _hook_master):
885
905
if overwrite is True:
886
906
overwrite = set(["history", "tags"])
887
907
elif not overwrite:
899
919
self.target.last_revision_info()
900
920
result.new_git_head, remote_refs = self._update_revisions(
901
921
stop_revision, overwrite=("history" in overwrite))
902
tags_ret = self.source.tags.merge_to(
903
self.target.tags, ("tags" in overwrite), ignore_master=True)
922
tags_ret = self.source.tags.merge_to(
923
self.target.tags, ("tags" in overwrite), ignore_master=True)
904
924
if isinstance(tags_ret, tuple):
905
925
result.tag_updates, result.tag_conflicts = tags_ret
956
976
if master_branch:
957
977
# pull from source into master.
958
978
master_branch.pull(self.source, overwrite, stop_revision,
960
980
result = self._basic_pull(stop_revision, overwrite, run_hooks,
961
_override_hook_target, _hook_master=master_branch)
981
_override_hook_target,
982
_hook_master=master_branch)
963
984
self.source.unlock()
977
998
result.old_revno, result.old_revid = self.target.last_revision_info()
978
999
result.new_git_head, remote_refs = self._update_revisions(
979
1000
stop_revision, overwrite=("history" in overwrite))
980
tags_ret = self.source.tags.merge_to(self.target.tags,
981
"tags" in overwrite, ignore_master=True)
1001
tags_ret = self.source.tags.merge_to(
1002
self.target.tags, "tags" in overwrite, ignore_master=True)
982
1003
(result.tag_updates, result.tag_conflicts) = tags_ret
983
1004
result.new_revno, result.new_revid = self.target.last_revision_info()
1012
1033
result.target_branch = self.target
1013
1034
if stop_revision is None:
1014
1035
stop_revision = self.source.last_revision()
1015
1037
def get_changed_refs(old_refs):
1016
1038
old_ref = old_refs.get(self.target.ref, None)
1017
1039
if old_ref is None:
1018
1040
result.old_revid = revision.NULL_REVISION
1020
result.old_revid = self.target.lookup_foreign_revision_id(old_ref)
1021
new_ref = self.source.repository.lookup_bzr_revision_id(stop_revision)[0]
1042
result.old_revid = self.target.lookup_foreign_revision_id(
1044
new_ref = self.source.repository.lookup_bzr_revision_id(
1022
1046
if not overwrite:
1023
if remote_divergence(old_ref, new_ref, self.source.repository._git.object_store):
1047
if remote_divergence(
1049
self.source.repository._git.object_store):
1024
1050
raise errors.DivergedBranches(self.source, self.target)
1025
refs = { self.target.ref: new_ref }
1051
refs = {self.target.ref: new_ref}
1026
1052
result.new_revid = stop_revision
1027
for name, sha in viewitems(self.source.repository._git.refs.as_dict(b"refs/tags")):
1053
for name, sha in viewitems(
1054
self.source.repository._git.refs.as_dict(b"refs/tags")):
1028
1055
refs[tag_name_to_ref(name)] = sha
1030
self.target.repository.send_pack(get_changed_refs,
1057
self.target.repository.send_pack(
1031
1059
self.source.repository._git.object_store.generate_pack_data)
1050
1078
def fetch(self, stop_revision=None, fetch_tags=None, limit=None):
1051
1079
interrepo = _mod_repository.InterRepository.get(self.source.repository,
1052
self.target.repository)
1080
self.target.repository)
1053
1081
if stop_revision is None:
1054
1082
stop_revision = self.source.last_revision()
1055
1083
determine_wants = interrepo.get_determine_wants_revids(
1066
1094
result.target_branch = self.target
1067
1095
result.old_revid = self.target.last_revision()
1068
1096
refs, stop_revision = self.update_refs(stop_revision)
1069
self.target.generate_revision_history(stop_revision,
1070
(result.old_revid if ("history" not in overwrite) else None),
1071
other_branch=self.source)
1072
tags_ret = self.source.tags.merge_to(self.target.tags,
1097
self.target.generate_revision_history(
1099
(result.old_revid if ("history" not in overwrite) else None),
1100
other_branch=self.source)
1101
tags_ret = self.source.tags.merge_to(
1073
1103
source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1074
1104
overwrite=("tags" in overwrite))
1075
1105
if isinstance(tags_ret, tuple):
1082
1112
def update_refs(self, stop_revision=None):
1083
1113
interrepo = _mod_repository.InterRepository.get(
1084
self.source.repository, self.target.repository)
1114
self.source.repository, self.target.repository)
1085
1115
c = self.source.get_config_stack()
1086
1116
fetch_tags = c.get('branch.fetch_tags')
1095
1125
stop_revision = self.target.lookup_foreign_revision_id(head)
1097
refs = interrepo.fetch(revision_id=stop_revision, include_tags=fetch_tags)
1127
refs = interrepo.fetch(
1128
revision_id=stop_revision, include_tags=fetch_tags)
1098
1129
return refs, stop_revision
1100
1131
def pull(self, stop_revision=None, overwrite=False,
1113
1144
with self.target.lock_write(), self.source.lock_read():
1114
1145
result.old_revid = self.target.last_revision()
1115
1146
refs, stop_revision = self.update_refs(stop_revision)
1116
self.target.generate_revision_history(stop_revision,
1117
(result.old_revid if ("history" not in overwrite) else None),
1118
other_branch=self.source)
1119
tags_ret = self.source.tags.merge_to(self.target.tags,
1120
overwrite=("tags" in overwrite),
1147
self.target.generate_revision_history(
1149
(result.old_revid if ("history" not in overwrite) else None),
1150
other_branch=self.source)
1151
tags_ret = self.source.tags.merge_to(
1152
self.target.tags, overwrite=("tags" in overwrite),
1121
1153
source_tag_refs=remote_refs_dict_to_tag_refs(refs))
1122
1154
if isinstance(tags_ret, tuple):
1123
1155
(result.tag_updates, result.tag_conflicts) = tags_ret
1135
1167
class InterToGitBranch(branch.GenericInterBranch):
1136
"""InterBranch implementation that pulls from a non-bzr into a Git branch."""
1168
"""InterBranch implementation that pulls into a Git branch."""
1138
1170
def __init__(self, source, target):
1139
1171
super(InterToGitBranch, self).__init__(source, target)
1140
1172
self.interrepo = _mod_repository.InterRepository.get(source.repository,
1144
1176
def _get_branch_formats_to_test():
1166
1198
if not isinstance(stop_revision, bytes):
1167
1199
raise TypeError(stop_revision)
1168
1200
main_ref = self.target.ref
1169
refs = { main_ref: (None, stop_revision) }
1201
refs = {main_ref: (None, stop_revision)}
1170
1202
if fetch_tags is None:
1171
1203
c = self.source.get_config_stack()
1172
1204
fetch_tags = c.get('branch.fetch_tags')
1196
1229
if (value[0] is not None and
1197
1230
git_sha is not None and
1198
value[0] == git_sha):
1231
value[0] == git_sha):
1200
1233
if (value[1] is not None and
1201
1234
revid is not None and
1204
# FIXME: If one side only has the git sha available and the other only
1205
# has the bzr revid, then this will cause us to show a tag as updated
1206
# that hasn't actually been updated.
1237
# FIXME: If one side only has the git sha available and the other
1238
# only has the bzr revid, then this will cause us to show a tag as
1239
# updated that hasn't actually been updated.
1208
1241
# FIXME: Check for diverged branches
1209
1242
for ref, (git_sha, revid) in viewitems(new_refs):
1231
1264
except ValueError:
1234
result.tag_conflicts.append((name, revid, ret[name][1]))
1267
result.tag_conflicts.append(
1268
(name, revid, ret[name][1]))
1236
1270
ret[ref] = (git_sha, revid)
1239
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False, limit=None):
1273
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False,
1240
1275
if stop_revision is None:
1241
1276
stop_revision = self.source.last_revision()
1257
1292
with self.source.lock_read(), self.target.lock_write():
1258
1293
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1260
1296
def update_refs(old_refs):
1261
1297
return self._update_refs(result, old_refs, new_refs, overwrite)
1263
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1264
update_refs, lossy=False)
1299
result.revidmap, old_refs, new_refs = (
1300
self.interrepo.fetch_refs(update_refs, lossy=False))
1265
1301
except NoPushSupport:
1266
1302
raise errors.NoRoundtrippingSupport(self.source, self.target)
1267
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1303
(old_sha1, result.old_revid) = old_refs.get(
1304
main_ref, (ZERO_SHA, NULL_REVISION))
1268
1305
if result.old_revid is None:
1269
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1306
result.old_revid = self.target.lookup_foreign_revision_id(
1270
1308
result.new_revid = new_refs[main_ref][1]
1271
1309
result.local_branch = None
1272
1310
result.master_branch = self.target
1283
1321
result.local_branch = None
1284
1322
result.master_branch = result.target_branch
1285
1323
with self.source.lock_read(), self.target.lock_write():
1286
new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
1324
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1287
1327
def update_refs(old_refs):
1288
1328
return self._update_refs(result, old_refs, new_refs, overwrite)
1290
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1291
update_refs, lossy=lossy, overwrite=overwrite)
1330
result.revidmap, old_refs, new_refs = (
1331
self.interrepo.fetch_refs(
1332
update_refs, lossy=lossy, overwrite=overwrite))
1292
1333
except NoPushSupport:
1293
1334
raise errors.NoRoundtrippingSupport(self.source, self.target)
1294
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1335
(old_sha1, result.old_revid) = old_refs.get(
1336
main_ref, (ZERO_SHA, NULL_REVISION))
1295
1337
if result.old_revid is None:
1296
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1338
result.old_revid = self.target.lookup_foreign_revision_id(
1297
1340
result.new_revid = new_refs[main_ref][1]
1298
(result.new_original_revno, result.new_original_revid) = stop_revinfo
1341
(result.new_original_revno,
1342
result.new_original_revid) = stop_revinfo
1299
1343
for hook in branch.Branch.hooks['post_push']: