/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/git/branch.py

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 19:12:43 UTC
  • mfrom: (7490.7.6 work)
  • mto: (7490.7.7 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200322191243-yx8ils8lvfmfh7rq
Merge lp:brz/3.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    lock,
43
43
    repository as _mod_repository,
44
44
    revision,
45
 
    tag,
46
45
    trace,
47
46
    transport,
48
47
    urlutils,
55
54
    text_type,
56
55
    viewitems,
57
56
    )
 
57
from ..tag import (
 
58
    Tags,
 
59
    InterTags,
 
60
    )
58
61
from ..trace import (
59
62
    is_quiet,
60
63
    mutter,
116
119
        return self._lookup_revno(self.new_revid)
117
120
 
118
121
 
119
 
class GitTags(tag.BasicTags):
120
 
    """Ref-based tag dictionary."""
121
 
 
122
 
    def __init__(self, branch):
123
 
        self.branch = branch
124
 
        self.repository = branch.repository
125
 
 
126
 
    def _merge_to_remote_git(self, target_repo, source_tag_refs,
127
 
                             overwrite=False):
 
122
class InterTagsFromGitToRemoteGit(InterTags):
 
123
 
 
124
    @classmethod
 
125
    def is_compatible(klass, source, target):
 
126
        if not isinstance(source, GitTags):
 
127
            return False
 
128
        if not isinstance(target, GitTags):
 
129
            return False
 
130
        if getattr(target.branch.repository, "_git", None) is not None:
 
131
            return False
 
132
        return True
 
133
 
 
134
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
135
        if self.source.branch.repository.has_same_location(self.target.branch.repository):
 
136
            return {}, []
128
137
        updates = {}
129
138
        conflicts = []
 
139
        source_tag_refs = self.source.branch.get_tag_refs()
130
140
 
131
141
        def get_changed_refs(old_refs):
132
142
            ret = dict(old_refs)
133
143
            for ref_name, tag_name, peeled, unpeeled in (
134
144
                    source_tag_refs.iteritems()):
 
145
                if selector and not selector(tag_name):
 
146
                    continue
135
147
                if old_refs.get(ref_name) == unpeeled:
136
148
                    pass
137
149
                elif overwrite or ref_name not in old_refs:
138
150
                    ret[ref_name] = unpeeled
139
 
                    updates[tag_name] = target_repo.lookup_foreign_revision_id(
 
151
                    updates[tag_name] = self.target.branch.repository.lookup_foreign_revision_id(
140
152
                        peeled)
 
153
                    self.target.branch._tag_refs = None
141
154
                else:
142
155
                    conflicts.append(
143
156
                        (tag_name,
144
157
                         self.repository.lookup_foreign_revision_id(peeled),
145
 
                         target_repo.lookup_foreign_revision_id(
 
158
                         self.target.branch.repository.lookup_foreign_revision_id(
146
159
                             old_refs[ref_name])))
147
160
            return ret
148
 
        target_repo.controldir.send_pack(
 
161
        self.target.branch.repository.controldir.send_pack(
149
162
            get_changed_refs, lambda have, want: [])
150
 
        return updates, conflicts
151
 
 
152
 
    def _merge_to_local_git(self, target_repo, source_tag_refs,
153
 
                            overwrite=False):
 
163
        return updates, set(conflicts)
 
164
 
 
165
 
 
166
class InterTagsFromGitToLocalGit(InterTags):
 
167
 
 
168
    @classmethod
 
169
    def is_compatible(klass, source, target):
 
170
        if not isinstance(source, GitTags):
 
171
            return False
 
172
        if not isinstance(target, GitTags):
 
173
            return False
 
174
        if getattr(target.branch.repository, "_git", None) is None:
 
175
            return False
 
176
        return True
 
177
 
 
178
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
179
        if self.source.branch.repository.has_same_location(self.target.branch.repository):
 
180
            return {}, []
 
181
 
154
182
        conflicts = []
155
183
        updates = {}
 
184
        source_tag_refs = self.source.branch.get_tag_refs()
 
185
 
 
186
        target_repo = self.target.branch.repository
 
187
 
156
188
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
 
189
            if selector and not selector(tag_name):
 
190
                continue
157
191
            if target_repo._git.refs.get(ref_name) == unpeeled:
158
192
                pass
159
193
            elif overwrite or ref_name not in target_repo._git.refs:
169
203
                                  tag_name)
170
204
                    continue
171
205
                target_repo._git.refs[ref_name] = unpeeled or peeled
 
206
                self.target.branch._tag_refs = None
172
207
            else:
173
208
                try:
174
 
                    source_revid = self.repository.lookup_foreign_revision_id(
 
209
                    source_revid = self.source.branch.repository.lookup_foreign_revision_id(
175
210
                        peeled)
176
211
                    target_revid = target_repo.lookup_foreign_revision_id(
177
212
                        target_repo._git.refs[ref_name])
184
219
                                  tag_name)
185
220
                    continue
186
221
                conflicts.append((tag_name, source_revid, target_revid))
187
 
        return updates, conflicts
188
 
 
189
 
    def _merge_to_git(self, to_tags, source_tag_refs, overwrite=False):
190
 
        target_repo = to_tags.repository
191
 
        if self.repository.has_same_location(target_repo):
192
 
            return {}, []
193
 
        try:
194
 
            if getattr(target_repo, "_git", None):
195
 
                return self._merge_to_local_git(
196
 
                    target_repo, source_tag_refs, overwrite)
197
 
            else:
198
 
                return self._merge_to_remote_git(
199
 
                    target_repo, source_tag_refs, overwrite)
200
 
        finally:
201
 
            to_tags.branch._tag_refs = None
202
 
 
203
 
    def _merge_to_non_git(self, to_tags, source_tag_refs, overwrite=False):
 
222
        return updates, set(conflicts)
 
223
 
 
224
 
 
225
class InterTagsFromGitToNonGit(InterTags):
 
226
 
 
227
    @classmethod
 
228
    def is_compatible(klass, source, target):
 
229
        if not isinstance(source, GitTags):
 
230
            return False
 
231
        if isinstance(target, GitTags):
 
232
            return False
 
233
        return True
 
234
 
 
235
    def merge(self, overwrite=False, ignore_master=False, selector=None):
 
236
        """See Tags.merge_to."""
 
237
        source_tag_refs = self.source.branch.get_tag_refs()
 
238
        if ignore_master:
 
239
            master = None
 
240
        else:
 
241
            master = self.target.branch.get_master_branch()
 
242
        with cleanup.ExitStack() as es:
 
243
            if master is not None:
 
244
                es.enter_context(master.lock_write())
 
245
            updates, conflicts = self._merge_to(
 
246
                self.target, source_tag_refs, overwrite=overwrite,
 
247
                selector=selector)
 
248
            if master is not None:
 
249
                extra_updates, extra_conflicts = self._merge_to(
 
250
                    master.tags, overwrite=overwrite,
 
251
                    source_tag_refs=source_tag_refs,
 
252
                    ignore_master=ignore_master, selector=selector)
 
253
                updates.update(extra_updates)
 
254
                conflicts.update(extra_conflicts)
 
255
            return updates, conflicts
 
256
 
 
257
    def _merge_to(self, to_tags, source_tag_refs, overwrite=False,
 
258
                  selector=None):
204
259
        unpeeled_map = defaultdict(set)
205
260
        conflicts = []
206
261
        updates = {}
207
262
        result = dict(to_tags.get_tag_dict())
208
263
        for ref_name, tag_name, peeled, unpeeled in source_tag_refs:
 
264
            if selector and not selector(tag_name):
 
265
                continue
209
266
            if unpeeled is not None:
210
267
                unpeeled_map[peeled].add(unpeeled)
211
268
            try:
212
 
                bzr_revid = self.branch.lookup_foreign_revision_id(peeled)
 
269
                bzr_revid = self.source.branch.lookup_foreign_revision_id(peeled)
213
270
            except NotCommitError:
214
271
                continue
215
272
            if result.get(tag_name) == bzr_revid:
224
281
            map_file = UnpeelMap.from_repository(to_tags.branch.repository)
225
282
            map_file.update(unpeeled_map)
226
283
            map_file.save_in_repository(to_tags.branch.repository)
227
 
        return updates, conflicts
228
 
 
229
 
    def merge_to(self, to_tags, overwrite=False, ignore_master=False,
230
 
                 source_tag_refs=None):
231
 
        """See Tags.merge_to."""
232
 
        if source_tag_refs is None:
233
 
            source_tag_refs = self.branch.get_tag_refs()
234
 
        if self == to_tags:
235
 
            return {}, []
236
 
        if isinstance(to_tags, GitTags):
237
 
            return self._merge_to_git(to_tags, source_tag_refs,
238
 
                                      overwrite=overwrite)
239
 
        else:
240
 
            if ignore_master:
241
 
                master = None
242
 
            else:
243
 
                master = to_tags.branch.get_master_branch()
244
 
            with cleanup.ExitStack() as es:
245
 
                if master is not None:
246
 
                    es.enter_context(master.lock_write())
247
 
                updates, conflicts = self._merge_to_non_git(
248
 
                    to_tags, source_tag_refs, overwrite=overwrite)
249
 
                if master is not None:
250
 
                    extra_updates, extra_conflicts = self.merge_to(
251
 
                        master.tags, overwrite=overwrite,
252
 
                        source_tag_refs=source_tag_refs,
253
 
                        ignore_master=ignore_master)
254
 
                    updates.update(extra_updates)
255
 
                    conflicts += extra_conflicts
256
 
                return updates, conflicts
 
284
        return updates, set(conflicts)
 
285
 
 
286
 
 
287
InterTags.register_optimiser(InterTagsFromGitToRemoteGit)
 
288
InterTags.register_optimiser(InterTagsFromGitToLocalGit)
 
289
InterTags.register_optimiser(InterTagsFromGitToNonGit)
 
290
 
 
291
 
 
292
class GitTags(Tags):
 
293
    """Ref-based tag dictionary."""
 
294
 
 
295
    def __init__(self, branch):
 
296
        self.branch = branch
 
297
        self.repository = branch.repository
257
298
 
258
299
    def get_tag_dict(self):
259
300
        ret = {}
267
308
                ret[tag_name] = bzr_revid
268
309
        return ret
269
310
 
 
311
    def lookup_tag(self, tag_name):
 
312
        """Return the referent string of a tag"""
 
313
        # TODO(jelmer): Replace with something more efficient for local tags.
 
314
        td = self.get_tag_dict()
 
315
        try:
 
316
            return td[tag_name]
 
317
        except KeyError:
 
318
            raise errors.NoSuchTag(tag_name)
 
319
 
270
320
 
271
321
class LocalGitTagDict(GitTags):
272
322
    """Dictionary with tags in a local repository."""
617
667
                return revision.NULL_REVISION
618
668
            return self.lookup_foreign_revision_id(self.head)
619
669
 
620
 
    def _basic_push(self, target, overwrite=False, stop_revision=None):
 
670
    def _basic_push(self, target, overwrite=False, stop_revision=None,
 
671
                    tag_selector=None):
621
672
        return branch.InterBranch.get(self, target)._basic_push(
622
 
            overwrite, stop_revision)
 
673
            overwrite, stop_revision, tag_selector=tag_selector)
623
674
 
624
675
    def lookup_foreign_revision_id(self, foreign_revid):
625
676
        try:
939
990
            stop_revision, fetch_tags=fetch_tags, limit=limit, lossy=lossy)
940
991
        return _mod_repository.FetchResult()
941
992
 
942
 
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False):
 
993
    def fetch_objects(self, stop_revision, fetch_tags, limit=None, lossy=False, tag_selector=None):
943
994
        interrepo = self._get_interrepo(self.source, self.target)
944
995
        if fetch_tags is None:
945
996
            c = self.source.get_config_stack()
957
1008
            else:
958
1009
                self._last_revid = stop_revision
959
1010
            real = interrepo.get_determine_wants_revids(
960
 
                [self._last_revid], include_tags=fetch_tags)
 
1011
                [self._last_revid], include_tags=fetch_tags, tag_selector=tag_selector)
961
1012
            return real(heads)
962
1013
        pack_hint, head, refs = interrepo.fetch_objects(
963
1014
            determine_wants, self.source.mapping, limit=limit,
967
1018
            self.target.repository.pack(hint=pack_hint)
968
1019
        return head, refs
969
1020
 
970
 
    def _update_revisions(self, stop_revision=None, overwrite=False):
971
 
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None)
 
1021
    def _update_revisions(self, stop_revision=None, overwrite=False, tag_selector=None):
 
1022
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None, tag_selector=tag_selector)
972
1023
        if overwrite:
973
1024
            prev_last_revid = None
974
1025
        else:
993
1044
            pass
994
1045
 
995
1046
    def _basic_pull(self, stop_revision, overwrite, run_hooks,
996
 
                    _override_hook_target, _hook_master):
 
1047
                    _override_hook_target, _hook_master, tag_selector=None):
997
1048
        if overwrite is True:
998
1049
            overwrite = set(["history", "tags"])
999
1050
        elif not overwrite:
1010
1061
            (result.old_revno, result.old_revid) = \
1011
1062
                self.target.last_revision_info()
1012
1063
            result.new_git_head, remote_refs = self._update_revisions(
1013
 
                stop_revision, overwrite=("history" in overwrite))
 
1064
                stop_revision, overwrite=("history" in overwrite),
 
1065
                tag_selector=tag_selector)
1014
1066
            tags_ret = self.source.tags.merge_to(
1015
1067
                self.target.tags, ("tags" in overwrite), ignore_master=True)
1016
1068
            if isinstance(tags_ret, tuple):
1033
1085
 
1034
1086
    def pull(self, overwrite=False, stop_revision=None,
1035
1087
             possible_transports=None, _hook_master=None, run_hooks=True,
1036
 
             _override_hook_target=None, local=False):
 
1088
             _override_hook_target=None, local=False, tag_selector=None):
1037
1089
        """See Branch.pull.
1038
1090
 
1039
1091
        :param _hook_master: Private parameter - set the branch to
1071
1123
                master_branch = None
1072
1124
            return self._basic_pull(stop_revision, overwrite, run_hooks,
1073
1125
                                    _override_hook_target,
1074
 
                                    _hook_master=master_branch)
 
1126
                                    _hook_master=master_branch,
 
1127
                                    tag_selector=tag_selector)
1075
1128
 
1076
 
    def _basic_push(self, overwrite, stop_revision):
 
1129
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
1077
1130
        if overwrite is True:
1078
1131
            overwrite = set(["history", "tags"])
1079
1132
        elif not overwrite:
1083
1136
        result.target_branch = self.target
1084
1137
        result.old_revno, result.old_revid = self.target.last_revision_info()
1085
1138
        result.new_git_head, remote_refs = self._update_revisions(
1086
 
            stop_revision, overwrite=("history" in overwrite))
 
1139
            stop_revision, overwrite=("history" in overwrite),
 
1140
            tag_selector=tag_selector)
1087
1141
        tags_ret = self.source.tags.merge_to(
1088
 
            self.target.tags, "tags" in overwrite, ignore_master=True)
 
1142
            self.target.tags, "tags" in overwrite, ignore_master=True,
 
1143
            selector=tag_selector)
1089
1144
        (result.tag_updates, result.tag_conflicts) = tags_ret
1090
1145
        result.new_revno, result.new_revid = self.target.last_revision_info()
1091
1146
        self.update_references(revid=result.new_revid)
1114
1169
        return (isinstance(source, LocalGitBranch) and
1115
1170
                isinstance(target, RemoteGitBranch))
1116
1171
 
1117
 
    def _basic_push(self, overwrite, stop_revision):
 
1172
    def _basic_push(self, overwrite, stop_revision, tag_selector=None):
1118
1173
        result = GitBranchPushResult()
1119
1174
        result.source_branch = self.source
1120
1175
        result.target_branch = self.target
1139
1194
            result.new_revid = stop_revision
1140
1195
            for name, sha in viewitems(
1141
1196
                    self.source.repository._git.refs.as_dict(b"refs/tags")):
 
1197
                if tag_selector and not tag_selector(name):
 
1198
                    continue
1142
1199
                if sha not in self.source.repository._git:
1143
1200
                    trace.mutter('Ignoring missing SHA: %s', sha)
1144
1201
                    continue
1178
1235
        interrepo.fetch_objects(determine_wants, limit=limit, lossy=lossy)
1179
1236
        return _mod_repository.FetchResult()
1180
1237
 
1181
 
    def _basic_push(self, overwrite=False, stop_revision=None):
 
1238
    def _basic_push(self, overwrite=False, stop_revision=None, tag_selector=None):
1182
1239
        if overwrite is True:
1183
1240
            overwrite = set(["history", "tags"])
1184
1241
        elif not overwrite:
1194
1251
            other_branch=self.source)
1195
1252
        tags_ret = self.source.tags.merge_to(
1196
1253
            self.target.tags,
1197
 
            source_tag_refs=remote_refs_dict_to_tag_refs(refs),
1198
 
            overwrite=("tags" in overwrite))
 
1254
            overwrite=("tags" in overwrite),
 
1255
            selector=tag_selector)
1199
1256
        if isinstance(tags_ret, tuple):
1200
1257
            (result.tag_updates, result.tag_conflicts) = tags_ret
1201
1258
        else:
1223
1280
        return result.refs, stop_revision
1224
1281
 
1225
1282
    def pull(self, stop_revision=None, overwrite=False,
1226
 
             possible_transports=None, run_hooks=True, local=False):
 
1283
             possible_transports=None, run_hooks=True, local=False,
 
1284
             tag_selector=None):
1227
1285
        # This type of branch can't be bound.
1228
1286
        if local:
1229
1287
            raise errors.LocalRequiresBoundBranch()
1244
1302
                other_branch=self.source)
1245
1303
            tags_ret = self.source.tags.merge_to(
1246
1304
                self.target.tags, overwrite=("tags" in overwrite),
1247
 
                source_tag_refs=remote_refs_dict_to_tag_refs(refs))
 
1305
                selector=tag_selector)
1248
1306
            if isinstance(tags_ret, tuple):
1249
1307
                (result.tag_updates, result.tag_conflicts) = tags_ret
1250
1308
            else:
1312
1370
                    refs[ref] = (None, revid)
1313
1371
        return refs, main_ref, (stop_revno, stop_revision)
1314
1372
 
1315
 
    def _update_refs(self, result, old_refs, new_refs, overwrite):
 
1373
    def _update_refs(self, result, old_refs, new_refs, overwrite, tag_selector):
1316
1374
        mutter("updating refs. old refs: %r, new refs: %r",
1317
1375
               old_refs, new_refs)
1318
1376
        result.tag_updates = {}
1351
1409
                except ValueError:
1352
1410
                    pass
1353
1411
                else:
 
1412
                    if tag_selector and not tag_selector(tag_name):
 
1413
                        continue
1354
1414
                    result.tag_updates[tag_name] = revid
1355
1415
                ret[ref] = (git_sha, revid)
1356
1416
            else:
1386
1446
            for (old_revid, (new_sha, new_revid)) in revidmap.items()})
1387
1447
 
1388
1448
    def pull(self, overwrite=False, stop_revision=None, local=False,
1389
 
             possible_transports=None, run_hooks=True, _stop_revno=None):
 
1449
             possible_transports=None, run_hooks=True, _stop_revno=None,
 
1450
             tag_selector=None):
1390
1451
        result = GitBranchPullResult()
1391
1452
        result.source_branch = self.source
1392
1453
        result.target_branch = self.target
1395
1456
                stop_revision, stop_revno=_stop_revno)
1396
1457
 
1397
1458
            def update_refs(old_refs):
1398
 
                return self._update_refs(result, old_refs, new_refs, overwrite)
 
1459
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
1399
1460
            try:
1400
1461
                result.revidmap, old_refs, new_refs = (
1401
1462
                    self.interrepo.fetch_refs(update_refs, lossy=False))
1415
1476
        return result
1416
1477
 
1417
1478
    def push(self, overwrite=False, stop_revision=None, lossy=False,
1418
 
             _override_hook_source_branch=None, _stop_revno=None):
 
1479
             _override_hook_source_branch=None, _stop_revno=None,
 
1480
             tag_selector=None):
1419
1481
        result = GitBranchPushResult()
1420
1482
        result.source_branch = self.source
1421
1483
        result.target_branch = self.target
1426
1488
                stop_revision, stop_revno=_stop_revno)
1427
1489
 
1428
1490
            def update_refs(old_refs):
1429
 
                return self._update_refs(result, old_refs, new_refs, overwrite)
 
1491
                return self._update_refs(result, old_refs, new_refs, overwrite, tag_selector)
1430
1492
            try:
1431
1493
                result.revidmap, old_refs, new_refs = (
1432
1494
                    self.interrepo.fetch_refs(