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)
392
408
:return: Branch nick
394
cs = self.repository._git.get_config_stack()
396
return cs.get((b"branch", self.name.encode('utf-8')), b"nick").decode("utf-8")
410
if getattr(self.repository, '_git', None):
411
cs = self.repository._git.get_config_stack()
413
return cs.get((b"branch", self.name.encode('utf-8')),
414
b"nick").decode("utf-8")
399
417
return self.name or u"HEAD"
401
419
def _set_nick(self, nick):
402
420
cf = self.repository._git.get_config()
403
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"))
405
424
cf.write_to_file(f)
406
425
self.repository._git._put_named_file('config', f.getvalue())
410
429
def __repr__(self):
411
430
return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
414
def generate_revision_history(self, revid, last_rev=None, other_branch=None):
433
def generate_revision_history(self, revid, last_rev=None,
415
435
if last_rev is not None:
416
436
graph = self.repository.get_graph()
417
437
if not graph.is_ancestor(last_rev, revid):
582
602
def __init__(self, controldir, repository, ref):
583
603
super(LocalGitBranch, self).__init__(controldir, repository, ref,
584
LocalGitBranchFormat())
604
LocalGitBranchFormat())
586
606
def create_checkout(self, to_location, revision_id=None, lightweight=False,
587
accelerator_tree=None, hardlink=False):
607
accelerator_tree=None, hardlink=False):
588
608
t = transport.get_transport(to_location)
590
610
format = self._get_checkout_format(lightweight=lightweight)
593
613
from_branch = checkout.set_branch_reference(target_branch=self)
595
615
policy = checkout.determine_repository_policy()
596
repo = policy.acquire_repository()[0]
616
policy.acquire_repository()
598
617
checkout_branch = checkout.create_branch()
599
618
checkout_branch.bind(self)
600
619
checkout_branch.pull(self, stop_revision=revision_id)
601
620
from_branch = None
602
return checkout.create_workingtree(revision_id,
603
from_branch=from_branch, hardlink=hardlink)
621
return checkout.create_workingtree(
622
revision_id, from_branch=from_branch, hardlink=hardlink)
605
624
def _lock_ref(self):
606
625
self._ref_lock = self.repository._git.refs.lock_ref(self.ref)
621
640
last_revid = self.last_revision()
622
641
graph = self.repository.get_graph()
624
ret = list(graph.iter_lefthand_ancestry(last_revid,
625
(revision.NULL_REVISION, )))
643
ret = list(graph.iter_lefthand_ancestry(
644
last_revid, (revision.NULL_REVISION, )))
626
645
except errors.RevisionNotPresent as e:
627
646
raise errors.GhostRevisionsHaveNoRevno(last_revid, e.revision_id)
637
656
def _read_last_revision_info(self):
638
657
last_revid = self.last_revision()
639
658
graph = self.repository.get_graph()
640
revno = graph.find_distance_to_null(last_revid,
641
[(revision.NULL_REVISION, 0)])
660
revno = graph.find_distance_to_null(
661
last_revid, [(revision.NULL_REVISION, 0)])
662
except errors.GhostRevisionsHaveNoRevno:
642
664
return revno, last_revid
644
666
def set_last_revision_info(self, revno, revision_id):
706
729
def create_memorytree(self):
707
730
from .memorytree import GitMemoryTree
708
return GitMemoryTree(self, self.repository._git.object_store, self.head)
731
return GitMemoryTree(self, self.repository._git.object_store,
710
734
def reference_parent(self, path, file_id=None, possible_transports=None):
711
735
"""Return the parent branch for a tree-reference file_id
717
741
# FIXME should provide multiple branches, based on config
718
742
url = urlutils.join(self.user_url, path)
719
743
return branch.Branch.open(
721
possible_transports=possible_transports)
745
possible_transports=possible_transports)
725
748
def _quick_lookup_revno(local_branch, remote_branch, revid):
732
755
except errors.NoSuchRevision:
733
756
graph = local_branch.repository.get_graph()
735
return graph.find_distance_to_null(revid,
736
[(revision.NULL_REVISION, 0)])
758
return graph.find_distance_to_null(
759
revid, [(revision.NULL_REVISION, 0)])
737
760
except errors.GhostRevisionsHaveNoRevno:
738
761
# FIXME: Check using graph.find_distance_to_null() ?
739
762
with remote_branch.lock_read():
754
777
to_file.write('No revisions to pull.\n')
755
778
elif self.new_git_head is not None:
756
779
to_file.write('Now on revision %d (git sha: %s).\n' %
757
(self.new_revno, self.new_git_head))
780
(self.new_revno, self.new_git_head))
759
782
to_file.write('Now on revision %d.\n' % (self.new_revno,))
760
783
self._show_tag_conficts(to_file)
762
785
def _lookup_revno(self, revid):
763
786
return _quick_lookup_revno(self.target_branch, self.source_branch,
766
789
def _get_old_revno(self):
767
790
if self._old_revno is not None:
822
845
def _get_interrepo(self, source, target):
823
return _mod_repository.InterRepository.get(source.repository, target.repository)
846
return _mod_repository.InterRepository.get(
847
source.repository, target.repository)
826
850
def is_compatible(cls, source, target):
829
853
if isinstance(target, GitBranch):
830
854
# InterLocalGitRemoteGitBranch or InterToGitBranch should be used
832
if getattr(cls._get_interrepo(source, target), "fetch_objects", None) is None:
856
if (getattr(cls._get_interrepo(source, target), "fetch_objects", None)
833
858
# fetch_objects is necessary for this to work
858
885
pack_hint, head, refs = interrepo.fetch_objects(
859
886
determine_wants, self.source.mapping, limit=limit)
860
887
if (pack_hint is not None and
861
self.target.repository._format.pack_compresses):
888
self.target.repository._format.pack_compresses):
862
889
self.target.repository.pack(hint=pack_hint)
863
890
return head, refs
868
895
prev_last_revid = None
870
897
prev_last_revid = self.target.last_revision()
871
self.target.generate_revision_history(self._last_revid,
872
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)
873
901
return head, refs
875
903
def _basic_pull(self, stop_revision, overwrite, run_hooks,
876
_override_hook_target, _hook_master):
904
_override_hook_target, _hook_master):
877
905
if overwrite is True:
878
906
overwrite = set(["history", "tags"])
880
908
overwrite = set()
881
909
result = GitBranchPullResult()
882
910
result.source_branch = self.source
891
919
self.target.last_revision_info()
892
920
result.new_git_head, remote_refs = self._update_revisions(
893
921
stop_revision, overwrite=("history" in overwrite))
894
tags_ret = self.source.tags.merge_to(
895
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)
896
924
if isinstance(tags_ret, tuple):
897
925
result.tag_updates, result.tag_conflicts = tags_ret
948
976
if master_branch:
949
977
# pull from source into master.
950
978
master_branch.pull(self.source, overwrite, stop_revision,
952
980
result = self._basic_pull(stop_revision, overwrite, run_hooks,
953
_override_hook_target, _hook_master=master_branch)
981
_override_hook_target,
982
_hook_master=master_branch)
955
984
self.source.unlock()
969
998
result.old_revno, result.old_revid = self.target.last_revision_info()
970
999
result.new_git_head, remote_refs = self._update_revisions(
971
1000
stop_revision, overwrite=("history" in overwrite))
972
tags_ret = self.source.tags.merge_to(self.target.tags,
973
"tags" in overwrite, ignore_master=True)
1001
tags_ret = self.source.tags.merge_to(
1002
self.target.tags, "tags" in overwrite, ignore_master=True)
974
1003
(result.tag_updates, result.tag_conflicts) = tags_ret
975
1004
result.new_revno, result.new_revid = self.target.last_revision_info()
1004
1033
result.target_branch = self.target
1005
1034
if stop_revision is None:
1006
1035
stop_revision = self.source.last_revision()
1007
1037
def get_changed_refs(old_refs):
1008
1038
old_ref = old_refs.get(self.target.ref, None)
1009
1039
if old_ref is None:
1010
1040
result.old_revid = revision.NULL_REVISION
1012
result.old_revid = self.target.lookup_foreign_revision_id(old_ref)
1013
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(
1014
1046
if not overwrite:
1015
if remote_divergence(old_ref, new_ref, self.source.repository._git.object_store):
1047
if remote_divergence(
1049
self.source.repository._git.object_store):
1016
1050
raise errors.DivergedBranches(self.source, self.target)
1017
refs = { self.target.ref: new_ref }
1051
refs = {self.target.ref: new_ref}
1018
1052
result.new_revid = stop_revision
1019
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")):
1020
1055
refs[tag_name_to_ref(name)] = sha
1022
self.target.repository.send_pack(get_changed_refs,
1057
self.target.repository.send_pack(
1023
1059
self.source.repository._git.object_store.generate_pack_data)
1042
1078
def fetch(self, stop_revision=None, fetch_tags=None, limit=None):
1043
1079
interrepo = _mod_repository.InterRepository.get(self.source.repository,
1044
self.target.repository)
1080
self.target.repository)
1045
1081
if stop_revision is None:
1046
1082
stop_revision = self.source.last_revision()
1047
1083
determine_wants = interrepo.get_determine_wants_revids(
1051
1087
def _basic_push(self, overwrite=False, stop_revision=None):
1052
1088
if overwrite is True:
1053
1089
overwrite = set(["history", "tags"])
1055
1091
overwrite = set()
1056
1092
result = GitBranchPushResult()
1057
1093
result.source_branch = self.source
1058
1094
result.target_branch = self.target
1059
1095
result.old_revid = self.target.last_revision()
1060
1096
refs, stop_revision = self.update_refs(stop_revision)
1061
self.target.generate_revision_history(stop_revision,
1062
(result.old_revid if ("history" not in overwrite) else None),
1063
other_branch=self.source)
1064
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(
1065
1103
source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1066
1104
overwrite=("tags" in overwrite))
1067
1105
if isinstance(tags_ret, tuple):
1074
1112
def update_refs(self, stop_revision=None):
1075
1113
interrepo = _mod_repository.InterRepository.get(
1076
self.source.repository, self.target.repository)
1114
self.source.repository, self.target.repository)
1077
1115
c = self.source.get_config_stack()
1078
1116
fetch_tags = c.get('branch.fetch_tags')
1080
1118
if stop_revision is None:
1081
refs = interrepo.fetch(branches=[b"HEAD"], include_tags=fetch_tags)
1119
refs = interrepo.fetch(branches=[self.source.ref], include_tags=fetch_tags)
1083
head = refs[b"HEAD"]
1121
head = refs[self.source.ref]
1084
1122
except KeyError:
1085
1123
stop_revision = revision.NULL_REVISION
1087
1125
stop_revision = self.target.lookup_foreign_revision_id(head)
1089
refs = interrepo.fetch(revision_id=stop_revision, include_tags=fetch_tags)
1127
refs = interrepo.fetch(
1128
revision_id=stop_revision, include_tags=fetch_tags)
1090
1129
return refs, stop_revision
1092
1131
def pull(self, stop_revision=None, overwrite=False,
1105
1144
with self.target.lock_write(), self.source.lock_read():
1106
1145
result.old_revid = self.target.last_revision()
1107
1146
refs, stop_revision = self.update_refs(stop_revision)
1108
self.target.generate_revision_history(stop_revision,
1109
(result.old_revid if ("history" not in overwrite) else None),
1110
other_branch=self.source)
1111
tags_ret = self.source.tags.merge_to(self.target.tags,
1112
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),
1113
1153
source_tag_refs=remote_refs_dict_to_tag_refs(refs))
1114
1154
if isinstance(tags_ret, tuple):
1115
1155
(result.tag_updates, result.tag_conflicts) = tags_ret
1127
1167
class InterToGitBranch(branch.GenericInterBranch):
1128
"""InterBranch implementation that pulls from a non-bzr into a Git branch."""
1168
"""InterBranch implementation that pulls into a Git branch."""
1130
1170
def __init__(self, source, target):
1131
1171
super(InterToGitBranch, self).__init__(source, target)
1132
1172
self.interrepo = _mod_repository.InterRepository.get(source.repository,
1136
1176
def _get_branch_formats_to_test():
1158
1198
if not isinstance(stop_revision, bytes):
1159
1199
raise TypeError(stop_revision)
1160
1200
main_ref = self.target.ref
1161
refs = { main_ref: (None, stop_revision) }
1201
refs = {main_ref: (None, stop_revision)}
1162
1202
if fetch_tags is None:
1163
1203
c = self.source.get_config_stack()
1164
1204
fetch_tags = c.get('branch.fetch_tags')
1188
1229
if (value[0] is not None and
1189
1230
git_sha is not None and
1190
value[0] == git_sha):
1231
value[0] == git_sha):
1192
1233
if (value[1] is not None and
1193
1234
revid is not None and
1196
# FIXME: If one side only has the git sha available and the other only
1197
# has the bzr revid, then this will cause us to show a tag as updated
1198
# 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.
1200
1241
# FIXME: Check for diverged branches
1201
1242
for ref, (git_sha, revid) in viewitems(new_refs):
1223
1264
except ValueError:
1226
result.tag_conflicts.append((name, revid, ret[name][1]))
1267
result.tag_conflicts.append(
1268
(name, revid, ret[name][1]))
1228
1270
ret[ref] = (git_sha, revid)
1231
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,
1232
1275
if stop_revision is None:
1233
1276
stop_revision = self.source.last_revision()
1249
1292
with self.source.lock_read(), self.target.lock_write():
1250
1293
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1252
1296
def update_refs(old_refs):
1253
1297
return self._update_refs(result, old_refs, new_refs, overwrite)
1255
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1256
update_refs, lossy=False)
1299
result.revidmap, old_refs, new_refs = (
1300
self.interrepo.fetch_refs(update_refs, lossy=False))
1257
1301
except NoPushSupport:
1258
1302
raise errors.NoRoundtrippingSupport(self.source, self.target)
1259
(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))
1260
1305
if result.old_revid is None:
1261
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1306
result.old_revid = self.target.lookup_foreign_revision_id(
1262
1308
result.new_revid = new_refs[main_ref][1]
1263
1309
result.local_branch = None
1264
1310
result.master_branch = self.target
1275
1321
result.local_branch = None
1276
1322
result.master_branch = result.target_branch
1277
1323
with self.source.lock_read(), self.target.lock_write():
1278
new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
1324
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1279
1327
def update_refs(old_refs):
1280
1328
return self._update_refs(result, old_refs, new_refs, overwrite)
1282
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1283
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))
1284
1333
except NoPushSupport:
1285
1334
raise errors.NoRoundtrippingSupport(self.source, self.target)
1286
(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))
1287
1337
if result.old_revid is None:
1288
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1338
result.old_revid = self.target.lookup_foreign_revision_id(
1289
1340
result.new_revid = new_refs[main_ref][1]
1290
(result.new_original_revno, result.new_original_revid) = stop_revinfo
1341
(result.new_original_revno,
1342
result.new_original_revid) = stop_revinfo
1291
1343
for hook in branch.Branch.hooks['post_push']: