107
105
self.branch = branch
108
106
self.repository = branch.repository
110
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,
113
113
def get_changed_refs(old_refs):
114
114
ret = dict(old_refs)
115
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()):
116
117
if old_refs.get(ref_name) == unpeeled:
118
elif overwrite or not ref_name in old_refs:
119
elif overwrite or ref_name not in old_refs:
119
120
ret[ref_name] = unpeeled
120
updates[tag_name] = target_repo.lookup_foreign_revision_id(peeled)
121
updates[tag_name] = target_repo.lookup_foreign_revision_id(
122
124
conflicts.append(
124
self.repository.lookup_foreign_revision_id(peeled),
125
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])))
127
target_repo.controldir.send_pack(get_changed_refs, lambda have, want: [])
130
target_repo.controldir.send_pack(
131
get_changed_refs, lambda have, want: [])
128
132
return updates, conflicts
130
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,
133
138
for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
134
139
if target_repo._git.refs.get(ref_name) == unpeeled:
136
elif overwrite or not ref_name in target_repo._git.refs:
141
elif overwrite or ref_name not in target_repo._git.refs:
137
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))
147
trace.warning('%s does not point to a valid object',
140
source_revid = self.repository.lookup_foreign_revision_id(peeled)
152
source_revid = self.repository.lookup_foreign_revision_id(
142
154
target_revid = target_repo.lookup_foreign_revision_id(
143
target_repo._git.refs[ref_name])
155
target_repo._git.refs[ref_name])
145
157
trace.warning('%s does not point to a valid object',
156
168
if getattr(target_repo, "_git", None):
157
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)
159
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)
161
175
to_tags.branch._tag_refs = None
178
192
result[tag_name] = bzr_revid
179
193
updates[tag_name] = bzr_revid
181
conflicts.append((tag_name, bzr_revid, result[n]))
195
conflicts.append((tag_name, bzr_revid, result[tag_name]))
182
196
to_tags._set_tag_dict(result)
183
197
if len(unpeeled_map) > 0:
184
198
map_file = UnpeelMap.from_repository(to_tags.branch.repository)
204
218
if master is not None:
205
219
master.lock_write()
207
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)
209
223
if master is not None:
210
224
extra_updates, extra_conflicts = self.merge_to(
211
225
master.tags, overwrite=overwrite,
212
source_tag_refs=source_tag_refs,
213
ignore_master=ignore_master)
226
source_tag_refs=source_tag_refs,
227
ignore_master=ignore_master)
214
228
updates.update(extra_updates)
215
229
conflicts += extra_conflicts
216
230
return updates, conflicts
301
316
raise NotImplementedError(self.initialize)
303
318
def get_reference(self, controldir, name=None):
304
return controldir.get_branch_reference(name)
319
return controldir.get_branch_reference(name=name)
306
321
def set_reference(self, controldir, name, target):
307
322
return controldir.set_branch_reference(target, name)
322
337
from .dir import LocalGitDir
323
338
if not isinstance(a_controldir, LocalGitDir):
324
339
raise errors.IncompatibleFormat(self, a_controldir._format)
325
return a_controldir.create_branch(repository=repository, name=name,
340
return a_controldir.create_branch(
341
repository=repository, name=name,
326
342
append_revisions_only=append_revisions_only)
394
410
if getattr(self.repository, '_git', None):
395
411
cs = self.repository._git.get_config_stack()
397
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")
400
417
return self.name or u"HEAD"
402
419
def _set_nick(self, nick):
403
420
cf = self.repository._git.get_config()
404
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"))
406
424
cf.write_to_file(f)
407
425
self.repository._git._put_named_file('config', f.getvalue())
411
429
def __repr__(self):
412
430
return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
415
def generate_revision_history(self, revid, last_rev=None, other_branch=None):
433
def generate_revision_history(self, revid, last_rev=None,
416
435
if last_rev is not None:
417
436
graph = self.repository.get_graph()
418
437
if not graph.is_ancestor(last_rev, revid):
603
622
def __init__(self, controldir, repository, ref):
604
623
super(LocalGitBranch, self).__init__(controldir, repository, ref,
605
LocalGitBranchFormat())
624
LocalGitBranchFormat())
607
626
def create_checkout(self, to_location, revision_id=None, lightweight=False,
608
accelerator_tree=None, hardlink=False):
627
accelerator_tree=None, hardlink=False):
609
628
t = transport.get_transport(to_location)
611
630
format = self._get_checkout_format(lightweight=lightweight)
614
633
from_branch = checkout.set_branch_reference(target_branch=self)
616
635
policy = checkout.determine_repository_policy()
617
repo = policy.acquire_repository()[0]
636
policy.acquire_repository()
619
637
checkout_branch = checkout.create_branch()
620
638
checkout_branch.bind(self)
621
639
checkout_branch.pull(self, stop_revision=revision_id)
622
640
from_branch = None
623
return checkout.create_workingtree(revision_id,
624
from_branch=from_branch, hardlink=hardlink)
641
return checkout.create_workingtree(
642
revision_id, from_branch=from_branch, hardlink=hardlink)
626
644
def _lock_ref(self):
627
645
self._ref_lock = self.repository._git.refs.lock_ref(self.ref)
642
660
last_revid = self.last_revision()
643
661
graph = self.repository.get_graph()
645
ret = list(graph.iter_lefthand_ancestry(last_revid,
646
(revision.NULL_REVISION, )))
663
ret = list(graph.iter_lefthand_ancestry(
664
last_revid, (revision.NULL_REVISION, )))
647
665
except errors.RevisionNotPresent as e:
648
666
raise errors.GhostRevisionsHaveNoRevno(last_revid, e.revision_id)
658
676
def _read_last_revision_info(self):
659
677
last_revid = self.last_revision()
660
678
graph = self.repository.get_graph()
661
revno = graph.find_distance_to_null(last_revid,
662
[(revision.NULL_REVISION, 0)])
680
revno = graph.find_distance_to_null(
681
last_revid, [(revision.NULL_REVISION, 0)])
682
except errors.GhostRevisionsHaveNoRevno:
663
684
return revno, last_revid
665
686
def set_last_revision_info(self, revno, revision_id):
727
749
def create_memorytree(self):
728
750
from .memorytree import GitMemoryTree
729
return GitMemoryTree(self, self.repository._git.object_store, self.head)
751
return GitMemoryTree(self, self.repository._git.object_store,
731
754
def reference_parent(self, path, file_id=None, possible_transports=None):
732
755
"""Return the parent branch for a tree-reference file_id
738
761
# FIXME should provide multiple branches, based on config
739
762
url = urlutils.join(self.user_url, path)
740
763
return branch.Branch.open(
742
possible_transports=possible_transports)
765
possible_transports=possible_transports)
746
768
def _quick_lookup_revno(local_branch, remote_branch, revid):
753
775
except errors.NoSuchRevision:
754
776
graph = local_branch.repository.get_graph()
756
return graph.find_distance_to_null(revid,
757
[(revision.NULL_REVISION, 0)])
778
return graph.find_distance_to_null(
779
revid, [(revision.NULL_REVISION, 0)])
758
780
except errors.GhostRevisionsHaveNoRevno:
759
781
# FIXME: Check using graph.find_distance_to_null() ?
760
782
with remote_branch.lock_read():
775
797
to_file.write('No revisions to pull.\n')
776
798
elif self.new_git_head is not None:
777
799
to_file.write('Now on revision %d (git sha: %s).\n' %
778
(self.new_revno, self.new_git_head))
800
(self.new_revno, self.new_git_head))
780
802
to_file.write('Now on revision %d.\n' % (self.new_revno,))
781
803
self._show_tag_conficts(to_file)
783
805
def _lookup_revno(self, revid):
784
806
return _quick_lookup_revno(self.target_branch, self.source_branch,
787
809
def _get_old_revno(self):
788
810
if self._old_revno is not None:
843
865
def _get_interrepo(self, source, target):
844
return _mod_repository.InterRepository.get(source.repository, target.repository)
866
return _mod_repository.InterRepository.get(
867
source.repository, target.repository)
847
870
def is_compatible(cls, source, target):
850
873
if isinstance(target, GitBranch):
851
874
# InterLocalGitRemoteGitBranch or InterToGitBranch should be used
853
if getattr(cls._get_interrepo(source, target), "fetch_objects", None) is None:
876
if (getattr(cls._get_interrepo(source, target), "fetch_objects", None)
854
878
# fetch_objects is necessary for this to work
879
905
pack_hint, head, refs = interrepo.fetch_objects(
880
906
determine_wants, self.source.mapping, limit=limit)
881
907
if (pack_hint is not None and
882
self.target.repository._format.pack_compresses):
908
self.target.repository._format.pack_compresses):
883
909
self.target.repository.pack(hint=pack_hint)
884
910
return head, refs
889
915
prev_last_revid = None
891
917
prev_last_revid = self.target.last_revision()
892
self.target.generate_revision_history(self._last_revid,
893
last_rev=prev_last_revid, other_branch=self.source)
918
self.target.generate_revision_history(
919
self._last_revid, last_rev=prev_last_revid,
920
other_branch=self.source)
894
921
return head, refs
896
923
def _basic_pull(self, stop_revision, overwrite, run_hooks,
897
_override_hook_target, _hook_master):
924
_override_hook_target, _hook_master):
898
925
if overwrite is True:
899
926
overwrite = set(["history", "tags"])
901
928
overwrite = set()
902
929
result = GitBranchPullResult()
903
930
result.source_branch = self.source
912
939
self.target.last_revision_info()
913
940
result.new_git_head, remote_refs = self._update_revisions(
914
941
stop_revision, overwrite=("history" in overwrite))
915
tags_ret = self.source.tags.merge_to(
916
self.target.tags, ("tags" in overwrite), ignore_master=True)
942
tags_ret = self.source.tags.merge_to(
943
self.target.tags, ("tags" in overwrite), ignore_master=True)
917
944
if isinstance(tags_ret, tuple):
918
945
result.tag_updates, result.tag_conflicts = tags_ret
969
996
if master_branch:
970
997
# pull from source into master.
971
998
master_branch.pull(self.source, overwrite, stop_revision,
973
1000
result = self._basic_pull(stop_revision, overwrite, run_hooks,
974
_override_hook_target, _hook_master=master_branch)
1001
_override_hook_target,
1002
_hook_master=master_branch)
976
1004
self.source.unlock()
990
1018
result.old_revno, result.old_revid = self.target.last_revision_info()
991
1019
result.new_git_head, remote_refs = self._update_revisions(
992
1020
stop_revision, overwrite=("history" in overwrite))
993
tags_ret = self.source.tags.merge_to(self.target.tags,
994
"tags" in overwrite, ignore_master=True)
1021
tags_ret = self.source.tags.merge_to(
1022
self.target.tags, "tags" in overwrite, ignore_master=True)
995
1023
(result.tag_updates, result.tag_conflicts) = tags_ret
996
1024
result.new_revno, result.new_revid = self.target.last_revision_info()
1025
1053
result.target_branch = self.target
1026
1054
if stop_revision is None:
1027
1055
stop_revision = self.source.last_revision()
1028
1057
def get_changed_refs(old_refs):
1029
1058
old_ref = old_refs.get(self.target.ref, None)
1030
1059
if old_ref is None:
1031
1060
result.old_revid = revision.NULL_REVISION
1033
result.old_revid = self.target.lookup_foreign_revision_id(old_ref)
1034
new_ref = self.source.repository.lookup_bzr_revision_id(stop_revision)[0]
1062
result.old_revid = self.target.lookup_foreign_revision_id(
1064
new_ref = self.source.repository.lookup_bzr_revision_id(
1035
1066
if not overwrite:
1036
if remote_divergence(old_ref, new_ref, self.source.repository._git.object_store):
1067
if remote_divergence(
1069
self.source.repository._git.object_store):
1037
1070
raise errors.DivergedBranches(self.source, self.target)
1038
refs = { self.target.ref: new_ref }
1071
refs = {self.target.ref: new_ref}
1039
1072
result.new_revid = stop_revision
1040
for name, sha in viewitems(self.source.repository._git.refs.as_dict(b"refs/tags")):
1073
for name, sha in viewitems(
1074
self.source.repository._git.refs.as_dict(b"refs/tags")):
1041
1075
refs[tag_name_to_ref(name)] = sha
1043
self.target.repository.send_pack(get_changed_refs,
1077
self.target.repository.send_pack(
1044
1079
self.source.repository._git.object_store.generate_pack_data)
1063
1098
def fetch(self, stop_revision=None, fetch_tags=None, limit=None):
1064
1099
interrepo = _mod_repository.InterRepository.get(self.source.repository,
1065
self.target.repository)
1100
self.target.repository)
1066
1101
if stop_revision is None:
1067
1102
stop_revision = self.source.last_revision()
1068
1103
determine_wants = interrepo.get_determine_wants_revids(
1072
1107
def _basic_push(self, overwrite=False, stop_revision=None):
1073
1108
if overwrite is True:
1074
1109
overwrite = set(["history", "tags"])
1076
1111
overwrite = set()
1077
1112
result = GitBranchPushResult()
1078
1113
result.source_branch = self.source
1079
1114
result.target_branch = self.target
1080
1115
result.old_revid = self.target.last_revision()
1081
1116
refs, stop_revision = self.update_refs(stop_revision)
1082
self.target.generate_revision_history(stop_revision,
1083
(result.old_revid if ("history" not in overwrite) else None),
1084
other_branch=self.source)
1085
tags_ret = self.source.tags.merge_to(self.target.tags,
1117
self.target.generate_revision_history(
1119
(result.old_revid if ("history" not in overwrite) else None),
1120
other_branch=self.source)
1121
tags_ret = self.source.tags.merge_to(
1086
1123
source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1087
1124
overwrite=("tags" in overwrite))
1088
1125
if isinstance(tags_ret, tuple):
1095
1132
def update_refs(self, stop_revision=None):
1096
1133
interrepo = _mod_repository.InterRepository.get(
1097
self.source.repository, self.target.repository)
1134
self.source.repository, self.target.repository)
1098
1135
c = self.source.get_config_stack()
1099
1136
fetch_tags = c.get('branch.fetch_tags')
1101
1138
if stop_revision is None:
1102
refs = interrepo.fetch(branches=[b"HEAD"], include_tags=fetch_tags)
1139
refs = interrepo.fetch(branches=[self.source.ref], include_tags=fetch_tags)
1104
head = refs[b"HEAD"]
1141
head = refs[self.source.ref]
1105
1142
except KeyError:
1106
1143
stop_revision = revision.NULL_REVISION
1108
1145
stop_revision = self.target.lookup_foreign_revision_id(head)
1110
refs = interrepo.fetch(revision_id=stop_revision, include_tags=fetch_tags)
1147
refs = interrepo.fetch(
1148
revision_id=stop_revision, include_tags=fetch_tags)
1111
1149
return refs, stop_revision
1113
1151
def pull(self, stop_revision=None, overwrite=False,
1126
1164
with self.target.lock_write(), self.source.lock_read():
1127
1165
result.old_revid = self.target.last_revision()
1128
1166
refs, stop_revision = self.update_refs(stop_revision)
1129
self.target.generate_revision_history(stop_revision,
1130
(result.old_revid if ("history" not in overwrite) else None),
1131
other_branch=self.source)
1132
tags_ret = self.source.tags.merge_to(self.target.tags,
1133
overwrite=("tags" in overwrite),
1167
self.target.generate_revision_history(
1169
(result.old_revid if ("history" not in overwrite) else None),
1170
other_branch=self.source)
1171
tags_ret = self.source.tags.merge_to(
1172
self.target.tags, overwrite=("tags" in overwrite),
1134
1173
source_tag_refs=remote_refs_dict_to_tag_refs(refs))
1135
1174
if isinstance(tags_ret, tuple):
1136
1175
(result.tag_updates, result.tag_conflicts) = tags_ret
1148
1187
class InterToGitBranch(branch.GenericInterBranch):
1149
"""InterBranch implementation that pulls from a non-bzr into a Git branch."""
1188
"""InterBranch implementation that pulls into a Git branch."""
1151
1190
def __init__(self, source, target):
1152
1191
super(InterToGitBranch, self).__init__(source, target)
1153
1192
self.interrepo = _mod_repository.InterRepository.get(source.repository,
1157
1196
def _get_branch_formats_to_test():
1180
1219
if not isinstance(stop_revision, bytes):
1181
1220
raise TypeError(stop_revision)
1182
1221
main_ref = self.target.ref
1183
refs = { main_ref: (None, stop_revision) }
1222
refs = {main_ref: (None, stop_revision)}
1184
1223
if fetch_tags is None:
1185
1224
c = self.source.get_config_stack()
1186
1225
fetch_tags = c.get('branch.fetch_tags')
1210
1250
if (value[0] is not None and
1211
1251
git_sha is not None and
1212
value[0] == git_sha):
1252
value[0] == git_sha):
1214
1254
if (value[1] is not None and
1215
1255
revid is not None and
1218
# FIXME: If one side only has the git sha available and the other only
1219
# has the bzr revid, then this will cause us to show a tag as updated
1220
# that hasn't actually been updated.
1258
# FIXME: If one side only has the git sha available and the other
1259
# only has the bzr revid, then this will cause us to show a tag as
1260
# updated that hasn't actually been updated.
1222
1262
# FIXME: Check for diverged branches
1223
1263
for ref, (git_sha, revid) in viewitems(new_refs):
1245
1285
except ValueError:
1248
result.tag_conflicts.append((name, revid, ret[name][1]))
1288
result.tag_conflicts.append(
1289
(name, revid, ret[name][1]))
1250
1291
ret[ref] = (git_sha, revid)
1253
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False, limit=None):
1294
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False,
1254
1296
if stop_revision is None:
1255
1297
stop_revision = self.source.last_revision()
1271
1313
with self.source.lock_read(), self.target.lock_write():
1272
1314
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1273
1315
stop_revision, stop_revno=_stop_revno)
1274
1317
def update_refs(old_refs):
1275
1318
return self._update_refs(result, old_refs, new_refs, overwrite)
1277
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1278
update_refs, lossy=False)
1320
result.revidmap, old_refs, new_refs = (
1321
self.interrepo.fetch_refs(update_refs, lossy=False))
1279
1322
except NoPushSupport:
1280
1323
raise errors.NoRoundtrippingSupport(self.source, self.target)
1281
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1324
(old_sha1, result.old_revid) = old_refs.get(
1325
main_ref, (ZERO_SHA, NULL_REVISION))
1282
1326
if result.old_revid is None:
1283
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1327
result.old_revid = self.target.lookup_foreign_revision_id(
1284
1329
result.new_revid = new_refs[main_ref][1]
1285
1330
result.local_branch = None
1286
1331
result.master_branch = self.target
1297
1342
result.local_branch = None
1298
1343
result.master_branch = result.target_branch
1299
1344
with self.source.lock_read(), self.target.lock_write():
1300
new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision, stop_revno=_stop_revno)
1345
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1346
stop_revision, stop_revno=_stop_revno)
1301
1348
def update_refs(old_refs):
1302
1349
return self._update_refs(result, old_refs, new_refs, overwrite)
1304
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1305
update_refs, lossy=lossy, overwrite=overwrite)
1351
result.revidmap, old_refs, new_refs = (
1352
self.interrepo.fetch_refs(
1353
update_refs, lossy=lossy, overwrite=overwrite))
1306
1354
except NoPushSupport:
1307
1355
raise errors.NoRoundtrippingSupport(self.source, self.target)
1308
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1356
(old_sha1, result.old_revid) = old_refs.get(
1357
main_ref, (ZERO_SHA, NULL_REVISION))
1309
1358
if result.old_revid is None:
1310
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1359
result.old_revid = self.target.lookup_foreign_revision_id(
1311
1361
result.new_revid = new_refs[main_ref][1]
1312
(result.new_original_revno, result.new_original_revid) = stop_revinfo
1362
(result.new_original_revno,
1363
result.new_original_revid) = stop_revinfo
1313
1364
for hook in branch.Branch.hooks['post_push']: