109
108
self.branch = branch
110
109
self.repository = branch.repository
112
def _merge_to_remote_git(self, target_repo, source_tag_refs, overwrite=False):
111
def _merge_to_remote_git(self, target_repo, source_tag_refs,
115
116
def get_changed_refs(old_refs):
116
117
ret = dict(old_refs)
117
for ref_name, tag_name, peeled, unpeeled in source_tag_refs.iteritems():
118
for ref_name, tag_name, peeled, unpeeled in (
119
source_tag_refs.iteritems()):
118
120
if old_refs.get(ref_name) == unpeeled:
120
elif overwrite or not ref_name in old_refs:
122
elif overwrite or ref_name not in old_refs:
121
123
ret[ref_name] = unpeeled
122
updates[tag_name] = target_repo.lookup_foreign_revision_id(peeled)
124
updates[tag_name] = target_repo.lookup_foreign_revision_id(
124
127
conflicts.append(
126
self.repository.lookup_foreign_revision_id(peeled),
127
target_repo.lookup_foreign_revision_id(old_refs[ref_name])))
129
self.repository.lookup_foreign_revision_id(peeled),
130
target_repo.lookup_foreign_revision_id(
131
old_refs[ref_name])))
129
target_repo.controldir.send_pack(get_changed_refs, lambda have, want: [])
133
target_repo.controldir.send_pack(
134
get_changed_refs, lambda have, want: [])
130
135
return updates, conflicts
132
def _merge_to_local_git(self, target_repo, source_tag_refs, overwrite=False):
137
def _merge_to_local_git(self, target_repo, source_tag_refs,
135
141
for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
136
142
if target_repo._git.refs.get(ref_name) == unpeeled:
138
elif overwrite or not ref_name in target_repo._git.refs:
144
elif overwrite or ref_name not in target_repo._git.refs:
139
145
target_repo._git.refs[ref_name] = unpeeled or peeled
141
updates[tag_name] = self.repository.lookup_foreign_revision_id(peeled)
147
updates[tag_name] = (
148
self.repository.lookup_foreign_revision_id(peeled))
143
150
trace.warning('%s does not point to a valid object',
148
source_revid = self.repository.lookup_foreign_revision_id(peeled)
155
source_revid = self.repository.lookup_foreign_revision_id(
149
157
target_revid = target_repo.lookup_foreign_revision_id(
150
target_repo._git.refs[ref_name])
158
target_repo._git.refs[ref_name])
152
160
trace.warning('%s does not point to a valid object',
163
171
if getattr(target_repo, "_git", None):
164
return self._merge_to_local_git(target_repo, source_tag_refs, overwrite)
172
return self._merge_to_local_git(
173
target_repo, source_tag_refs, overwrite)
166
return self._merge_to_remote_git(target_repo, source_tag_refs, overwrite)
175
return self._merge_to_remote_git(
176
target_repo, source_tag_refs, overwrite)
168
178
to_tags.branch._tag_refs = None
185
195
result[tag_name] = bzr_revid
186
196
updates[tag_name] = bzr_revid
188
conflicts.append((tag_name, bzr_revid, result[n]))
198
conflicts.append((tag_name, bzr_revid, result[tag_name]))
189
199
to_tags._set_tag_dict(result)
190
200
if len(unpeeled_map) > 0:
191
201
map_file = UnpeelMap.from_repository(to_tags.branch.repository)
211
221
if master is not None:
212
222
master.lock_write()
214
updates, conflicts = self._merge_to_non_git(to_tags, source_tag_refs,
224
updates, conflicts = self._merge_to_non_git(
225
to_tags, source_tag_refs, overwrite=overwrite)
216
226
if master is not None:
217
227
extra_updates, extra_conflicts = self.merge_to(
218
228
master.tags, overwrite=overwrite,
219
source_tag_refs=source_tag_refs,
220
ignore_master=ignore_master)
229
source_tag_refs=source_tag_refs,
230
ignore_master=ignore_master)
221
231
updates.update(extra_updates)
222
232
conflicts += extra_conflicts
223
233
return updates, conflicts
329
340
from .dir import LocalGitDir
330
341
if not isinstance(a_controldir, LocalGitDir):
331
342
raise errors.IncompatibleFormat(self, a_controldir._format)
332
return a_controldir.create_branch(repository=repository, name=name,
343
return a_controldir.create_branch(
344
repository=repository, name=name,
333
345
append_revisions_only=append_revisions_only)
401
413
if getattr(self.repository, '_git', None):
402
414
cs = self.repository._git.get_config_stack()
404
return cs.get((b"branch", self.name.encode('utf-8')), b"nick").decode("utf-8")
416
return cs.get((b"branch", self.name.encode('utf-8')),
417
b"nick").decode("utf-8")
407
420
return self.name or u"HEAD"
409
422
def _set_nick(self, nick):
410
423
cf = self.repository._git.get_config()
411
cf.set((b"branch", self.name.encode('utf-8')), b"nick", nick.encode("utf-8"))
424
cf.set((b"branch", self.name.encode('utf-8')),
425
b"nick", nick.encode("utf-8"))
413
427
cf.write_to_file(f)
414
428
self.repository._git._put_named_file('config', f.getvalue())
418
432
def __repr__(self):
419
433
return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
422
def generate_revision_history(self, revid, last_rev=None, other_branch=None):
436
def generate_revision_history(self, revid, last_rev=None,
423
438
if last_rev is not None:
424
439
graph = self.repository.get_graph()
425
440
if not graph.is_ancestor(last_rev, revid):
617
632
def __init__(self, controldir, repository, ref):
618
633
super(LocalGitBranch, self).__init__(controldir, repository, ref,
619
LocalGitBranchFormat())
634
LocalGitBranchFormat())
621
636
def create_checkout(self, to_location, revision_id=None, lightweight=False,
622
accelerator_tree=None, hardlink=False):
637
accelerator_tree=None, hardlink=False):
623
638
t = transport.get_transport(to_location)
625
640
format = self._get_checkout_format(lightweight=lightweight)
628
643
from_branch = checkout.set_branch_reference(target_branch=self)
630
645
policy = checkout.determine_repository_policy()
631
repo = policy.acquire_repository()[0]
646
policy.acquire_repository()
633
647
checkout_branch = checkout.create_branch()
634
648
checkout_branch.bind(self)
635
649
checkout_branch.pull(self, stop_revision=revision_id)
636
650
from_branch = None
637
return checkout.create_workingtree(revision_id,
638
from_branch=from_branch, hardlink=hardlink)
651
return checkout.create_workingtree(
652
revision_id, from_branch=from_branch, hardlink=hardlink)
640
654
def _lock_ref(self):
641
655
self._ref_lock = self.repository._git.refs.lock_ref(self.ref)
656
670
last_revid = self.last_revision()
657
671
graph = self.repository.get_graph()
659
ret = list(graph.iter_lefthand_ancestry(last_revid,
660
(revision.NULL_REVISION, )))
673
ret = list(graph.iter_lefthand_ancestry(
674
last_revid, (revision.NULL_REVISION, )))
661
675
except errors.RevisionNotPresent as e:
662
676
raise errors.GhostRevisionsHaveNoRevno(last_revid, e.revision_id)
673
687
last_revid = self.last_revision()
674
688
graph = self.repository.get_graph()
676
revno = graph.find_distance_to_null(last_revid,
677
[(revision.NULL_REVISION, 0)])
690
revno = graph.find_distance_to_null(
691
last_revid, [(revision.NULL_REVISION, 0)])
678
692
except errors.GhostRevisionsHaveNoRevno:
680
694
return revno, last_revid
747
762
def create_memorytree(self):
748
763
from .memorytree import GitMemoryTree
749
return GitMemoryTree(self, self.repository._git.object_store, self.head)
764
return GitMemoryTree(self, self.repository._git.object_store,
751
767
def reference_parent(self, path, file_id=None, possible_transports=None):
752
768
"""Return the parent branch for a tree-reference file_id
758
774
# FIXME should provide multiple branches, based on config
759
775
url = urlutils.join(self.user_url, path)
760
776
return branch.Branch.open(
762
possible_transports=possible_transports)
778
possible_transports=possible_transports)
766
781
def _quick_lookup_revno(local_branch, remote_branch, revid):
773
788
except errors.NoSuchRevision:
774
789
graph = local_branch.repository.get_graph()
776
return graph.find_distance_to_null(revid,
777
[(revision.NULL_REVISION, 0)])
791
return graph.find_distance_to_null(
792
revid, [(revision.NULL_REVISION, 0)])
778
793
except errors.GhostRevisionsHaveNoRevno:
779
794
# FIXME: Check using graph.find_distance_to_null() ?
780
795
with remote_branch.lock_read():
795
810
to_file.write('No revisions to pull.\n')
796
811
elif self.new_git_head is not None:
797
812
to_file.write('Now on revision %d (git sha: %s).\n' %
798
(self.new_revno, self.new_git_head))
813
(self.new_revno, self.new_git_head))
800
815
to_file.write('Now on revision %d.\n' % (self.new_revno,))
801
816
self._show_tag_conficts(to_file)
803
818
def _lookup_revno(self, revid):
804
819
return _quick_lookup_revno(self.target_branch, self.source_branch,
807
822
def _get_old_revno(self):
808
823
if self._old_revno is not None:
863
878
def _get_interrepo(self, source, target):
864
return _mod_repository.InterRepository.get(source.repository, target.repository)
879
return _mod_repository.InterRepository.get(
880
source.repository, target.repository)
867
883
def is_compatible(cls, source, target):
870
886
if isinstance(target, GitBranch):
871
887
# InterLocalGitRemoteGitBranch or InterToGitBranch should be used
873
if getattr(cls._get_interrepo(source, target), "fetch_objects", None) is None:
889
if (getattr(cls._get_interrepo(source, target), "fetch_objects", None)
874
891
# fetch_objects is necessary for this to work
899
918
pack_hint, head, refs = interrepo.fetch_objects(
900
919
determine_wants, self.source.mapping, limit=limit)
901
920
if (pack_hint is not None and
902
self.target.repository._format.pack_compresses):
921
self.target.repository._format.pack_compresses):
903
922
self.target.repository.pack(hint=pack_hint)
904
923
return head, refs
909
928
prev_last_revid = None
911
930
prev_last_revid = self.target.last_revision()
912
self.target.generate_revision_history(self._last_revid,
913
last_rev=prev_last_revid, other_branch=self.source)
931
self.target.generate_revision_history(
932
self._last_revid, last_rev=prev_last_revid,
933
other_branch=self.source)
914
934
return head, refs
916
936
def _basic_pull(self, stop_revision, overwrite, run_hooks,
917
_override_hook_target, _hook_master):
937
_override_hook_target, _hook_master):
918
938
if overwrite is True:
919
939
overwrite = set(["history", "tags"])
920
940
elif not overwrite:
932
952
self.target.last_revision_info()
933
953
result.new_git_head, remote_refs = self._update_revisions(
934
954
stop_revision, overwrite=("history" in overwrite))
935
tags_ret = self.source.tags.merge_to(
936
self.target.tags, ("tags" in overwrite), ignore_master=True)
955
tags_ret = self.source.tags.merge_to(
956
self.target.tags, ("tags" in overwrite), ignore_master=True)
937
957
if isinstance(tags_ret, tuple):
938
958
result.tag_updates, result.tag_conflicts = tags_ret
989
1009
if master_branch:
990
1010
# pull from source into master.
991
1011
master_branch.pull(self.source, overwrite, stop_revision,
993
1013
result = self._basic_pull(stop_revision, overwrite, run_hooks,
994
_override_hook_target, _hook_master=master_branch)
1014
_override_hook_target,
1015
_hook_master=master_branch)
996
1017
self.source.unlock()
1010
1031
result.old_revno, result.old_revid = self.target.last_revision_info()
1011
1032
result.new_git_head, remote_refs = self._update_revisions(
1012
1033
stop_revision, overwrite=("history" in overwrite))
1013
tags_ret = self.source.tags.merge_to(self.target.tags,
1014
"tags" in overwrite, ignore_master=True)
1034
tags_ret = self.source.tags.merge_to(
1035
self.target.tags, "tags" in overwrite, ignore_master=True)
1015
1036
(result.tag_updates, result.tag_conflicts) = tags_ret
1016
1037
result.new_revno, result.new_revid = self.target.last_revision_info()
1045
1066
result.target_branch = self.target
1046
1067
if stop_revision is None:
1047
1068
stop_revision = self.source.last_revision()
1048
1070
def get_changed_refs(old_refs):
1049
1071
old_ref = old_refs.get(self.target.ref, None)
1050
1072
if old_ref is None:
1051
1073
result.old_revid = revision.NULL_REVISION
1053
result.old_revid = self.target.lookup_foreign_revision_id(old_ref)
1054
new_ref = self.source.repository.lookup_bzr_revision_id(stop_revision)[0]
1075
result.old_revid = self.target.lookup_foreign_revision_id(
1077
new_ref = self.source.repository.lookup_bzr_revision_id(
1055
1079
if not overwrite:
1056
if remote_divergence(old_ref, new_ref, self.source.repository._git.object_store):
1080
if remote_divergence(
1082
self.source.repository._git.object_store):
1057
1083
raise errors.DivergedBranches(self.source, self.target)
1058
refs = { self.target.ref: new_ref }
1084
refs = {self.target.ref: new_ref}
1059
1085
result.new_revid = stop_revision
1060
for name, sha in viewitems(self.source.repository._git.refs.as_dict(b"refs/tags")):
1086
for name, sha in viewitems(
1087
self.source.repository._git.refs.as_dict(b"refs/tags")):
1061
1088
refs[tag_name_to_ref(name)] = sha
1063
self.target.repository.send_pack(get_changed_refs,
1090
self.target.repository.send_pack(
1064
1092
self.source.repository._git.object_store.generate_pack_data)
1083
1111
def fetch(self, stop_revision=None, fetch_tags=None, limit=None):
1084
1112
interrepo = _mod_repository.InterRepository.get(self.source.repository,
1085
self.target.repository)
1113
self.target.repository)
1086
1114
if stop_revision is None:
1087
1115
stop_revision = self.source.last_revision()
1088
1116
determine_wants = interrepo.get_determine_wants_revids(
1099
1127
result.target_branch = self.target
1100
1128
result.old_revid = self.target.last_revision()
1101
1129
refs, stop_revision = self.update_refs(stop_revision)
1102
self.target.generate_revision_history(stop_revision,
1103
(result.old_revid if ("history" not in overwrite) else None),
1104
other_branch=self.source)
1105
tags_ret = self.source.tags.merge_to(self.target.tags,
1130
self.target.generate_revision_history(
1132
(result.old_revid if ("history" not in overwrite) else None),
1133
other_branch=self.source)
1134
tags_ret = self.source.tags.merge_to(
1106
1136
source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1107
1137
overwrite=("tags" in overwrite))
1108
1138
if isinstance(tags_ret, tuple):
1115
1145
def update_refs(self, stop_revision=None):
1116
1146
interrepo = _mod_repository.InterRepository.get(
1117
self.source.repository, self.target.repository)
1147
self.source.repository, self.target.repository)
1118
1148
c = self.source.get_config_stack()
1119
1149
fetch_tags = c.get('branch.fetch_tags')
1128
1158
stop_revision = self.target.lookup_foreign_revision_id(head)
1130
refs = interrepo.fetch(revision_id=stop_revision, include_tags=fetch_tags)
1160
refs = interrepo.fetch(
1161
revision_id=stop_revision, include_tags=fetch_tags)
1131
1162
return refs, stop_revision
1133
1164
def pull(self, stop_revision=None, overwrite=False,
1146
1177
with self.target.lock_write(), self.source.lock_read():
1147
1178
result.old_revid = self.target.last_revision()
1148
1179
refs, stop_revision = self.update_refs(stop_revision)
1149
self.target.generate_revision_history(stop_revision,
1150
(result.old_revid if ("history" not in overwrite) else None),
1151
other_branch=self.source)
1152
tags_ret = self.source.tags.merge_to(self.target.tags,
1153
overwrite=("tags" in overwrite),
1180
self.target.generate_revision_history(
1182
(result.old_revid if ("history" not in overwrite) else None),
1183
other_branch=self.source)
1184
tags_ret = self.source.tags.merge_to(
1185
self.target.tags, overwrite=("tags" in overwrite),
1154
1186
source_tag_refs=remote_refs_dict_to_tag_refs(refs))
1155
1187
if isinstance(tags_ret, tuple):
1156
1188
(result.tag_updates, result.tag_conflicts) = tags_ret
1168
1200
class InterToGitBranch(branch.GenericInterBranch):
1169
"""InterBranch implementation that pulls from a non-bzr into a Git branch."""
1201
"""InterBranch implementation that pulls into a Git branch."""
1171
1203
def __init__(self, source, target):
1172
1204
super(InterToGitBranch, self).__init__(source, target)
1173
1205
self.interrepo = _mod_repository.InterRepository.get(source.repository,
1177
1209
def _get_branch_formats_to_test():
1199
1231
if not isinstance(stop_revision, bytes):
1200
1232
raise TypeError(stop_revision)
1201
1233
main_ref = self.target.ref
1202
refs = { main_ref: (None, stop_revision) }
1234
refs = {main_ref: (None, stop_revision)}
1203
1235
if fetch_tags is None:
1204
1236
c = self.source.get_config_stack()
1205
1237
fetch_tags = c.get('branch.fetch_tags')
1229
1262
if (value[0] is not None and
1230
1263
git_sha is not None and
1231
value[0] == git_sha):
1264
value[0] == git_sha):
1233
1266
if (value[1] is not None and
1234
1267
revid is not None and
1237
# FIXME: If one side only has the git sha available and the other only
1238
# has the bzr revid, then this will cause us to show a tag as updated
1239
# that hasn't actually been updated.
1270
# FIXME: If one side only has the git sha available and the other
1271
# only has the bzr revid, then this will cause us to show a tag as
1272
# updated that hasn't actually been updated.
1241
1274
# FIXME: Check for diverged branches
1242
1275
for ref, (git_sha, revid) in viewitems(new_refs):
1264
1297
except ValueError:
1267
result.tag_conflicts.append((name, revid, ret[name][1]))
1300
result.tag_conflicts.append(
1301
(name, revid, ret[name][1]))
1269
1303
ret[ref] = (git_sha, revid)
1272
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False, limit=None):
1306
def fetch(self, stop_revision=None, fetch_tags=None, lossy=False,
1273
1308
if stop_revision is None:
1274
1309
stop_revision = self.source.last_revision()
1290
1325
with self.source.lock_read(), self.target.lock_write():
1291
1326
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1293
1329
def update_refs(old_refs):
1294
1330
return self._update_refs(result, old_refs, new_refs, overwrite)
1296
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1297
update_refs, lossy=False)
1332
result.revidmap, old_refs, new_refs = (
1333
self.interrepo.fetch_refs(update_refs, lossy=False))
1298
1334
except NoPushSupport:
1299
1335
raise errors.NoRoundtrippingSupport(self.source, self.target)
1300
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1336
(old_sha1, result.old_revid) = old_refs.get(
1337
main_ref, (ZERO_SHA, NULL_REVISION))
1301
1338
if result.old_revid is None:
1302
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1339
result.old_revid = self.target.lookup_foreign_revision_id(
1303
1341
result.new_revid = new_refs[main_ref][1]
1304
1342
result.local_branch = None
1305
1343
result.master_branch = self.target
1316
1354
result.local_branch = None
1317
1355
result.master_branch = result.target_branch
1318
1356
with self.source.lock_read(), self.target.lock_write():
1319
new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
1357
new_refs, main_ref, stop_revinfo = self._get_new_refs(
1320
1360
def update_refs(old_refs):
1321
1361
return self._update_refs(result, old_refs, new_refs, overwrite)
1323
result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
1324
update_refs, lossy=lossy, overwrite=overwrite)
1363
result.revidmap, old_refs, new_refs = (
1364
self.interrepo.fetch_refs(
1365
update_refs, lossy=lossy, overwrite=overwrite))
1325
1366
except NoPushSupport:
1326
1367
raise errors.NoRoundtrippingSupport(self.source, self.target)
1327
(old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
1368
(old_sha1, result.old_revid) = old_refs.get(
1369
main_ref, (ZERO_SHA, NULL_REVISION))
1328
1370
if result.old_revid is None:
1329
result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
1371
result.old_revid = self.target.lookup_foreign_revision_id(
1330
1373
result.new_revid = new_refs[main_ref][1]
1331
(result.new_original_revno, result.new_original_revid) = stop_revinfo
1374
(result.new_original_revno,
1375
result.new_original_revid) = stop_revinfo
1332
1376
for hook in branch.Branch.hooks['post_push']: