/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 branch.py

Fix revision_history test when no DeprecationWarning is printed and bzr 2.5
is used.

Older prereleases of bzr 2.5 didn't deprecate Branch.revision_history.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""An adapter between a Git Branch and a Bazaar Branch"""
19
19
 
 
20
from collections import defaultdict
 
21
 
20
22
from dulwich.objects import (
21
23
    Commit,
22
24
    Tag,
 
25
    ZERO_SHA,
23
26
    )
 
27
from dulwich.repo import check_ref_format
24
28
 
25
29
from bzrlib import (
26
30
    branch,
27
31
    bzrdir,
28
32
    config,
29
33
    errors,
30
 
    repository,
 
34
    repository as _mod_repository,
31
35
    revision,
32
36
    tag,
33
37
    transport,
 
38
    urlutils,
34
39
    )
35
40
from bzrlib.decorators import (
36
41
    needs_read_lock,
41
46
from bzrlib.trace import (
42
47
    is_quiet,
43
48
    mutter,
 
49
    warning,
44
50
    )
45
51
 
46
52
from bzrlib.plugins.git.config import (
51
57
    NoSuchRef,
52
58
    )
53
59
from bzrlib.plugins.git.refs import (
 
60
    extract_tags,
 
61
    gather_peeled,
 
62
    is_tag,
54
63
    ref_to_branch_name,
55
 
    extract_tags,
 
64
    ref_to_tag_name,
56
65
    tag_name_to_ref,
57
66
    )
 
67
from bzrlib.plugins.git.unpeel_map import (
 
68
    UnpeelMap,
 
69
    )
58
70
 
59
71
from bzrlib.foreign import ForeignBranch
60
72
 
65
77
    def _lookup_revno(self, revid):
66
78
        assert isinstance(revid, str), "was %r" % revid
67
79
        # Try in source branch first, it'll be faster
68
 
        return self.target_branch.revision_id_to_revno(revid)
 
80
        self.target_branch.lock_read()
 
81
        try:
 
82
            return self.target_branch.revision_id_to_revno(revid)
 
83
        finally:
 
84
            self.target_branch.unlock()
69
85
 
70
86
    @property
71
87
    def old_revno(self):
76
92
        return self._lookup_revno(self.new_revid)
77
93
 
78
94
 
79
 
class LocalGitTagDict(tag.BasicTags):
80
 
    """Dictionary with tags in a local repository."""
 
95
class GitTags(tag.BasicTags):
 
96
    """Ref-based tag dictionary."""
81
97
 
82
98
    def __init__(self, branch):
83
99
        self.branch = branch
84
100
        self.repository = branch.repository
85
101
 
 
102
    def get_refs(self):
 
103
        raise NotImplementedError(self.get_refs)
 
104
 
 
105
    def _iter_tag_refs(self, refs):
 
106
        raise NotImplementedError(self._iter_tag_refs)
 
107
 
 
108
    def _merge_to_remote_git(self, target_repo, new_refs, overwrite=False):
 
109
        updates = {}
 
110
        conflicts = []
 
111
        def get_changed_refs(old_refs):
 
112
            ret = dict(old_refs)
 
113
            for k, v in new_refs.iteritems():
 
114
                if not is_tag(k):
 
115
                    continue
 
116
                name = ref_to_tag_name(k)
 
117
                if old_refs.get(k) == v:
 
118
                    pass
 
119
                elif overwrite or not k in old_refs:
 
120
                    ret[k] = v
 
121
                    updates[name] = target_repo.lookup_foreign_revision_id(v)
 
122
                else:
 
123
                    conflicts.append((name, v, old_refs[k]))
 
124
            return ret
 
125
        target_repo.bzrdir.send_pack(get_changed_refs, lambda have, want: [])
 
126
        return updates, conflicts
 
127
 
 
128
    def _merge_to_local_git(self, target_repo, refs, overwrite=False):
 
129
        conflicts = []
 
130
        updates = {}
 
131
        for k, (peeled, unpeeled) in gather_peeled(refs).iteritems():
 
132
            if not is_tag(k):
 
133
                continue
 
134
            name = ref_to_tag_name(k)
 
135
            if target_repo._git.refs.get(k) in (peeled, unpeeled):
 
136
                pass
 
137
            elif overwrite or not k in target_repo._git.refs:
 
138
                target_repo._git.refs[k] = unpeeled or peeled
 
139
                updates[name] = target_repo.lookup_foreign_revision_id(peeled)
 
140
            else:
 
141
                conflicts.append((name, peeled, target_repo.refs[k]))
 
142
        return updates, conflicts
 
143
 
 
144
    def _merge_to_git(self, to_tags, refs, overwrite=False):
 
145
        target_repo = to_tags.repository
 
146
        if self.repository.has_same_location(target_repo):
 
147
            return {}, []
 
148
        if getattr(target_repo, "_git", None):
 
149
            return self._merge_to_local_git(target_repo, refs, overwrite)
 
150
        else:
 
151
            return self._merge_to_remote_git(target_repo, refs, overwrite)
 
152
 
 
153
    def _merge_to_non_git(self, to_tags, refs, overwrite=False):
 
154
        unpeeled_map = defaultdict(set)
 
155
        conflicts = []
 
156
        updates = {}
 
157
        result = dict(to_tags.get_tag_dict())
 
158
        for n, peeled, unpeeled, bzr_revid in self._iter_tag_refs(refs):
 
159
            if unpeeled is not None:
 
160
                unpeeled_map[peeled].add(unpeeled)
 
161
            if result.get(n) == bzr_revid:
 
162
                pass
 
163
            elif n not in result or overwrite:
 
164
                result[n] = bzr_revid
 
165
                updates[n] = bzr_revid
 
166
            else:
 
167
                conflicts.append((n, result[n], bzr_revid))
 
168
        to_tags._set_tag_dict(result)
 
169
        if len(unpeeled_map) > 0:
 
170
            map_file = UnpeelMap.from_repository(to_tags.branch.repository)
 
171
            map_file.update(unpeeled_map)
 
172
            map_file.save_in_repository(to_tags.branch.repository)
 
173
        return updates, conflicts
 
174
 
 
175
    def merge_to(self, to_tags, overwrite=False, ignore_master=False,
 
176
                 source_refs=None):
 
177
        """See Tags.merge_to."""
 
178
        if source_refs is None:
 
179
            source_refs = self.get_refs()
 
180
        if self == to_tags:
 
181
            return {}, []
 
182
        if isinstance(to_tags, GitTags):
 
183
            return self._merge_to_git(to_tags, source_refs,
 
184
                                      overwrite=overwrite)
 
185
        else:
 
186
            if ignore_master:
 
187
                master = None
 
188
            else:
 
189
                master = to_tags.branch.get_master_branch()
 
190
            updates, conflicts = self._merge_to_non_git(to_tags, source_refs,
 
191
                                              overwrite=overwrite)
 
192
            if master is not None:
 
193
                extra_updates, extra_conflicts = self.merge_to(
 
194
                    master.tags, overwrite=overwrite,
 
195
                                           source_refs=source_refs,
 
196
                                           ignore_master=ignore_master)
 
197
                updates.update(extra_updates)
 
198
                conflicts += extra_conflicts
 
199
            return updates, conflicts
 
200
 
86
201
    def get_tag_dict(self):
87
202
        ret = {}
88
 
        for k,v in extract_tags(self.repository._git.get_refs()).iteritems():
 
203
        refs = self.get_refs()
 
204
        for (name, peeled, unpeeled, bzr_revid) in self._iter_tag_refs(refs):
 
205
            ret[name] = bzr_revid
 
206
        return ret
 
207
 
 
208
 
 
209
class LocalGitTagDict(GitTags):
 
210
    """Dictionary with tags in a local repository."""
 
211
 
 
212
    def __init__(self, branch):
 
213
        super(LocalGitTagDict, self).__init__(branch)
 
214
        self.refs = self.repository.bzrdir._git.refs
 
215
 
 
216
    def get_refs(self):
 
217
        return self.refs.as_dict()
 
218
 
 
219
    def _iter_tag_refs(self, refs):
 
220
        """Iterate over the tag refs.
 
221
 
 
222
        :param refs: Refs dictionary (name -> git sha1)
 
223
        :return: iterator over (name, peeled_sha1, unpeeled_sha1, bzr_revid)
 
224
        """
 
225
        for k, (peeled, unpeeled) in extract_tags(refs).iteritems():
89
226
            try:
90
 
                obj = self.repository._git[v]
 
227
                obj = self.repository._git[peeled]
91
228
            except KeyError:
92
 
                mutter("Tag %s points at unknown object %s, ignoring", v, obj)
 
229
                mutter("Tag %s points at unknown object %s, ignoring", peeled,
 
230
                       peeled)
93
231
                continue
 
232
            # FIXME: this shouldn't really be necessary, the repository
 
233
            # already should have these unpeeled.
94
234
            while isinstance(obj, Tag):
95
 
                v = obj.object[1]
96
 
                obj = self.repository._git[v]
 
235
                peeled = obj.object[1]
 
236
                obj = self.repository._git[peeled]
97
237
            if not isinstance(obj, Commit):
98
238
                mutter("Tag %s points at object %r that is not a commit, "
99
239
                       "ignoring", k, obj)
100
240
                continue
101
 
            ret[k] = self.branch.lookup_foreign_revision_id(v)
102
 
        return ret
 
241
            yield (k, peeled, unpeeled,
 
242
                   self.branch.lookup_foreign_revision_id(peeled))
103
243
 
104
244
    def _set_tag_dict(self, to_dict):
105
 
        extra = set(self.repository._git.get_refs().keys())
 
245
        extra = set(self.get_refs().keys())
106
246
        for k, revid in to_dict.iteritems():
107
247
            name = tag_name_to_ref(k)
108
248
            if name in extra:
109
249
                extra.remove(name)
110
250
            self.set_tag(k, revid)
111
251
        for name in extra:
112
 
            if name.startswith("refs/tags/"):
 
252
            if is_tag(name):
113
253
                del self.repository._git[name]
114
254
 
115
255
    def set_tag(self, name, revid):
116
 
        self.repository._git.refs[tag_name_to_ref(name)], _ = \
117
 
            self.branch.lookup_bzr_revision_id(revid)
118
 
 
119
 
 
120
 
class DictTagDict(LocalGitTagDict):
 
256
        try:
 
257
            git_sha, mapping = self.branch.lookup_bzr_revision_id(revid)
 
258
        except errors.NoSuchRevision:
 
259
            raise errors.GhostTagsNotSupported(self)
 
260
        self.refs[tag_name_to_ref(name)] = git_sha
 
261
 
 
262
 
 
263
class DictTagDict(tag.BasicTags):
121
264
 
122
265
    def __init__(self, branch, tags):
123
266
        super(DictTagDict, self).__init__(branch)
127
270
        return self._tags
128
271
 
129
272
 
 
273
class GitSymrefBranchFormat(branch.BranchFormat):
 
274
 
 
275
    def get_format_description(self):
 
276
        return 'Git Symbolic Reference Branch'
 
277
 
 
278
    def network_name(self):
 
279
        return "git"
 
280
 
 
281
    def get_reference(self, controldir, name=None):
 
282
        return controldir.get_branch_reference(name)
 
283
 
 
284
    def set_reference(self, controldir, name, target):
 
285
        return controldir.set_branch_reference(name, target)
 
286
 
 
287
 
130
288
class GitBranchFormat(branch.BranchFormat):
131
289
 
132
290
    def get_format_description(self):
138
296
    def supports_tags(self):
139
297
        return True
140
298
 
 
299
    def supports_leaving_lock(self):
 
300
        return False
 
301
 
 
302
    def supports_tags_referencing_ghosts(self):
 
303
        return False
 
304
 
 
305
    def tags_are_versioned(self):
 
306
        return False
 
307
 
 
308
    @property
 
309
    def _matchingbzrdir(self):
 
310
        from bzrlib.plugins.git.dir import LocalGitControlDirFormat
 
311
        return LocalGitControlDirFormat()
 
312
 
141
313
    def get_foreign_tests_branch_factory(self):
142
314
        from bzrlib.plugins.git.tests.test_branch import ForeignTestsBranchFactory
143
315
        return ForeignTestsBranchFactory()
144
316
 
145
317
    def make_tags(self, branch):
146
 
        if getattr(branch.repository, "get_refs", None) is not None:
 
318
        if getattr(branch.repository, "_git", None) is None:
147
319
            from bzrlib.plugins.git.remote import RemoteGitTagDict
148
320
            return RemoteGitTagDict(branch)
149
321
        else:
150
322
            return LocalGitTagDict(branch)
151
323
 
 
324
    def initialize(self, a_bzrdir, name=None, repository=None,
 
325
                   append_revisions_only=None):
 
326
        from bzrlib.plugins.git.dir import LocalGitDir
 
327
        if not isinstance(a_bzrdir, LocalGitDir):
 
328
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
 
329
        return a_bzrdir.create_branch(repository=repository, name=name,
 
330
            append_revisions_only=append_revisions_only)
 
331
 
152
332
 
153
333
class GitReadLock(object):
154
334
 
159
339
class GitWriteLock(object):
160
340
 
161
341
    def __init__(self, unlock):
 
342
        self.branch_token = None
162
343
        self.unlock = unlock
163
344
 
164
345
 
165
346
class GitBranch(ForeignBranch):
166
347
    """An adapter to git repositories for bzr Branch objects."""
167
348
 
168
 
    def __init__(self, bzrdir, repository, ref, lockfiles, tagsdict=None):
 
349
    @property
 
350
    def control_transport(self):
 
351
        return self.bzrdir.control_transport
 
352
 
 
353
    def __init__(self, bzrdir, repository, ref, tagsdict=None):
 
354
        self.base = bzrdir.root_transport.base
169
355
        self.repository = repository
170
356
        self._format = GitBranchFormat()
171
 
        self.control_files = lockfiles
172
357
        self.bzrdir = bzrdir
 
358
        self._lock_mode = None
 
359
        self._lock_count = 0
173
360
        super(GitBranch, self).__init__(repository.get_mapping())
174
361
        if tagsdict is not None:
175
362
            self.tags = DictTagDict(self, tagsdict)
176
363
        self.ref = ref
177
 
        self.name = ref_to_branch_name(ref)
 
364
        try:
 
365
            self.name = ref_to_branch_name(ref)
 
366
        except ValueError:
 
367
            self.name = None
178
368
        self._head = None
179
 
        self.base = bzrdir.root_transport.base
180
369
 
181
 
    def _get_checkout_format(self):
 
370
    def _get_checkout_format(self, lightweight=False):
182
371
        """Return the most suitable metadir for a checkout of this branch.
183
372
        Weaves are used if this branch's repository uses weaves.
184
373
        """
191
380
            return ret
192
381
        return "git"
193
382
 
 
383
    def get_config(self):
 
384
        return GitBranchConfig(self)
 
385
 
194
386
    def _get_nick(self, local=False, possible_master_transports=None):
195
387
        """Find the nick name for this branch.
196
388
 
205
397
 
206
398
    def __repr__(self):
207
399
        return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
208
 
            self.ref or "HEAD")
 
400
            self.name)
209
401
 
210
402
    def generate_revision_history(self, revid, old_revid=None):
211
 
        # FIXME: Check that old_revid is in the ancestry of revid
212
 
        newhead, self.mapping = self.mapping.revision_id_bzr_to_foreign(revid)
 
403
        if revid == NULL_REVISION:
 
404
            newhead = ZERO_SHA
 
405
        else:
 
406
            # FIXME: Check that old_revid is in the ancestry of revid
 
407
            newhead, self.mapping = self.repository.lookup_bzr_revision_id(revid)
 
408
            if self.mapping is None:
 
409
                raise AssertionError
213
410
        self._set_head(newhead)
214
411
 
215
 
    def lock_write(self):
216
 
        self.control_files.lock_write()
 
412
    def lock_write(self, token=None):
 
413
        if token is not None:
 
414
            raise errors.TokenLockingNotSupported(self)
 
415
        if self._lock_mode:
 
416
            if self._lock_mode == 'r':
 
417
                raise errors.ReadOnlyError(self)
 
418
            self._lock_count += 1
 
419
        else:
 
420
            self._lock_mode = 'w'
 
421
            self._lock_count = 1
 
422
        self.repository.lock_write()
217
423
        return GitWriteLock(self.unlock)
218
424
 
 
425
    def leave_lock_in_place(self):
 
426
        raise NotImplementedError(self.leave_lock_in_place)
 
427
 
 
428
    def dont_leave_lock_in_place(self):
 
429
        raise NotImplementedError(self.dont_leave_lock_in_place)
 
430
 
219
431
    def get_stacked_on_url(self):
220
432
        # Git doesn't do stacking (yet...)
221
433
        raise errors.UnstackableBranchFormat(self._format, self.base)
229
441
        # FIXME: Set "origin" url in .git/config ?
230
442
        pass
231
443
 
 
444
    def break_lock(self):
 
445
        raise NotImplementedError(self.break_lock)
 
446
 
232
447
    def lock_read(self):
233
 
        self.control_files.lock_read()
 
448
        if self._lock_mode:
 
449
            assert self._lock_mode in ('r', 'w')
 
450
            self._lock_count += 1
 
451
        else:
 
452
            self._lock_mode = 'r'
 
453
            self._lock_count = 1
 
454
        self.repository.lock_read()
234
455
        return GitReadLock(self.unlock)
235
456
 
 
457
    def peek_lock_mode(self):
 
458
        return self._lock_mode
 
459
 
236
460
    def is_locked(self):
237
 
        return self.control_files.is_locked()
 
461
        return (self._lock_mode is not None)
238
462
 
239
463
    def unlock(self):
240
 
        self.control_files.unlock()
 
464
        """See Branch.unlock()."""
 
465
        self._lock_count -= 1
 
466
        if self._lock_count == 0:
 
467
            self._lock_mode = None
 
468
            self._clear_cached_state()
 
469
        self.repository.unlock()
241
470
 
242
471
    def get_physical_lock_status(self):
243
472
        return False
265
494
class LocalGitBranch(GitBranch):
266
495
    """A local Git branch."""
267
496
 
268
 
    def __init__(self, bzrdir, repository, name, lockfiles, tagsdict=None):
269
 
        super(LocalGitBranch, self).__init__(bzrdir, repository, name,
270
 
              lockfiles, tagsdict)
271
 
        refs = repository._git.get_refs()
272
 
        if not (name in refs.keys() or "HEAD" in refs.keys()):
 
497
    def __init__(self, bzrdir, repository, ref, tagsdict=None):
 
498
        super(LocalGitBranch, self).__init__(bzrdir, repository, ref,
 
499
              tagsdict)
 
500
        refs = bzrdir.get_refs()
 
501
        if not (ref in refs.keys() or "HEAD" in refs.keys()):
273
502
            raise errors.NotBranchError(self.base)
274
503
 
275
504
    def create_checkout(self, to_location, revision_id=None, lightweight=False,
277
506
        if lightweight:
278
507
            t = transport.get_transport(to_location)
279
508
            t.ensure_base()
280
 
            format = self._get_checkout_format()
 
509
            format = self._get_checkout_format(lightweight=True)
281
510
            checkout = format.initialize_on_transport(t)
282
511
            from_branch = branch.BranchReferenceFormat().initialize(checkout,
283
512
                self)
298
527
        :return: WorkingTree object of checkout.
299
528
        """
300
529
        checkout_branch = bzrdir.BzrDir.create_branch_convenience(
301
 
            to_location, force_new_tree=False)
 
530
            to_location, force_new_tree=False,
 
531
            format=self._get_checkout_format(lightweight=False))
302
532
        checkout = checkout_branch.bzrdir
303
533
        checkout_branch.bind(self)
304
534
        # pull up to the specified revision_id to set the initial
309
539
    def _gen_revision_history(self):
310
540
        if self.head is None:
311
541
            return []
312
 
        ret = list(self.repository.iter_reverse_revision_history(
313
 
            self.last_revision()))
 
542
        graph = self.repository.get_graph()
 
543
        ret = list(graph.iter_lefthand_ancestry(self.last_revision(),
 
544
            (revision.NULL_REVISION, )))
314
545
        ret.reverse()
315
546
        return ret
316
547
 
320
551
        except KeyError:
321
552
            return None
322
553
 
323
 
    def set_last_revision_info(self, revno, revid):
324
 
        self.set_last_revision(revid)
 
554
    def _read_last_revision_info(self):
 
555
        last_revid = self.last_revision()
 
556
        graph = self.repository.get_graph()
 
557
        revno = graph.find_distance_to_null(last_revid,
 
558
            [(revision.NULL_REVISION, 0)])
 
559
        return revno, last_revid
 
560
 
 
561
    def set_last_revision_info(self, revno, revision_id):
 
562
        self.set_last_revision(revision_id)
 
563
        self._last_revision_info_cache = revno, revision_id
325
564
 
326
565
    def set_last_revision(self, revid):
327
 
        (newhead, self.mapping) = self.repository.lookup_bzr_revision_id(revid)
328
 
        self.head = newhead
 
566
        if not revid or not isinstance(revid, basestring):
 
567
            raise errors.InvalidRevisionId(revision_id=revid, branch=self)
 
568
        if revid == NULL_REVISION:
 
569
            newhead = ZERO_SHA
 
570
        else:
 
571
            (newhead, self.mapping) = self.repository.lookup_bzr_revision_id(revid)
 
572
            if self.mapping is None:
 
573
                raise AssertionError
 
574
        self._set_head(newhead)
329
575
 
330
576
    def _set_head(self, value):
331
577
        self._head = value
334
580
 
335
581
    head = property(_get_head, _set_head)
336
582
 
337
 
    def get_config(self):
338
 
        return GitBranchConfig(self)
339
 
 
340
583
    def get_push_location(self):
341
584
        """See Branch.get_push_location."""
342
585
        push_loc = self.get_config().get_user_option('push_location')
351
594
        return True
352
595
 
353
596
 
 
597
def _quick_lookup_revno(local_branch, remote_branch, revid):
 
598
    assert isinstance(revid, str), "was %r" % revid
 
599
    # Try in source branch first, it'll be faster
 
600
    local_branch.lock_read()
 
601
    try:
 
602
        try:
 
603
            return local_branch.revision_id_to_revno(revid)
 
604
        except errors.NoSuchRevision:
 
605
            graph = local_branch.repository.get_graph()
 
606
            try:
 
607
                return graph.find_distance_to_null(revid,
 
608
                    [(revision.NULL_REVISION, 0)])
 
609
            except errors.GhostRevisionsHaveNoRevno:
 
610
                # FIXME: Check using graph.find_distance_to_null() ?
 
611
                remote_branch.lock_read()
 
612
                try:
 
613
                    return remote_branch.revision_id_to_revno(revid)
 
614
                finally:
 
615
                    remote_branch.unlock()
 
616
    finally:
 
617
        local_branch.unlock()
 
618
 
 
619
 
354
620
class GitBranchPullResult(branch.PullResult):
355
621
 
356
622
    def __init__(self):
371
637
        self._show_tag_conficts(to_file)
372
638
 
373
639
    def _lookup_revno(self, revid):
374
 
        assert isinstance(revid, str), "was %r" % revid
375
 
        # Try in source branch first, it'll be faster
376
 
        try:
377
 
            return self.source_branch.revision_id_to_revno(revid)
378
 
        except errors.NoSuchRevision:
379
 
            # FIXME: Check using graph.find_distance_to_null() ?
380
 
            return self.target_branch.revision_id_to_revno(revid)
 
640
        return _quick_lookup_revno(self.target_branch, self.source_branch,
 
641
                revid)
381
642
 
382
643
    def _get_old_revno(self):
383
644
        if self._old_revno is not None:
403
664
class GitBranchPushResult(branch.BranchPushResult):
404
665
 
405
666
    def _lookup_revno(self, revid):
406
 
        assert isinstance(revid, str), "was %r" % revid
407
 
        # Try in source branch first, it'll be faster
408
 
        try:
409
 
            return self.source_branch.revision_id_to_revno(revid)
410
 
        except errors.NoSuchRevision:
411
 
            # FIXME: Check using graph.find_distance_to_null() ?
412
 
            return self.target_branch.revision_id_to_revno(revid)
 
667
        return _quick_lookup_revno(self.source_branch, self.target_branch,
 
668
            revid)
413
669
 
414
670
    @property
415
671
    def old_revno(self):
417
673
 
418
674
    @property
419
675
    def new_revno(self):
 
676
        new_original_revno = getattr(self, "new_original_revno", None)
 
677
        if new_original_revno:
 
678
            return new_original_revno
 
679
        if getattr(self, "new_original_revid", None) is not None:
 
680
            return self._lookup_revno(self.new_original_revid)
420
681
        return self._lookup_revno(self.new_revid)
421
682
 
422
683
 
425
686
 
426
687
    @staticmethod
427
688
    def _get_branch_formats_to_test():
428
 
        return []
 
689
        try:
 
690
            default_format = branch.format_registry.get_default()
 
691
        except AttributeError:
 
692
            default_format = branch.BranchFormat._default_format
 
693
        return [
 
694
            (GitBranchFormat(), GitBranchFormat()),
 
695
            (GitBranchFormat(), default_format)]
429
696
 
430
697
    @classmethod
431
698
    def _get_interrepo(self, source, target):
432
 
        return repository.InterRepository.get(source.repository,
433
 
            target.repository)
 
699
        return _mod_repository.InterRepository.get(source.repository, target.repository)
434
700
 
435
701
    @classmethod
436
702
    def is_compatible(cls, source, target):
437
 
        return (isinstance(source, GitBranch) and
438
 
                not isinstance(target, GitBranch) and
439
 
                (getattr(cls._get_interrepo(source, target), "fetch_objects", None) is not None))
440
 
 
441
 
    def _update_revisions(self, stop_revision=None, overwrite=False,
442
 
        graph=None, limit=None):
443
 
        """Like InterBranch.update_revisions(), but with additions.
444
 
 
445
 
        Compared to the `update_revisions()` below, this function takes a
446
 
        `limit` argument that limits how many git commits will be converted
447
 
        and returns the new git head.
448
 
        """
 
703
        if not isinstance(source, GitBranch):
 
704
            return False
 
705
        if isinstance(target, GitBranch):
 
706
            # InterLocalGitRemoteGitBranch or InterToGitBranch should be used
 
707
            return False
 
708
        if getattr(cls._get_interrepo(source, target), "fetch_objects", None) is None:
 
709
            # fetch_objects is necessary for this to work
 
710
            return False
 
711
        return True
 
712
 
 
713
    def fetch(self, stop_revision=None, fetch_tags=None, limit=None):
 
714
        self.fetch_objects(stop_revision, fetch_tags=fetch_tags, limit=limit)
 
715
 
 
716
    def fetch_objects(self, stop_revision, fetch_tags, limit=None):
449
717
        interrepo = self._get_interrepo(self.source, self.target)
 
718
        if fetch_tags is None:
 
719
            c = self.source.get_config()
 
720
            fetch_tags = c.get_user_option_as_bool('branch.fetch_tags')
450
721
        def determine_wants(heads):
451
722
            if self.source.ref is not None and not self.source.ref in heads:
452
 
                raise NoSuchRef(self.source.ref, heads.keys())
453
 
            if stop_revision is not None:
454
 
                self._last_revid = stop_revision
455
 
                head, mapping = self.source.repository.lookup_bzr_revision_id(
456
 
                    stop_revision)
457
 
            else:
 
723
                raise NoSuchRef(self.source.ref, self.source.user_url, heads.keys())
 
724
 
 
725
            if stop_revision is None:
458
726
                if self.source.ref is not None:
459
727
                    head = heads[self.source.ref]
460
728
                else:
461
729
                    head = heads["HEAD"]
462
730
                self._last_revid = self.source.lookup_foreign_revision_id(head)
463
 
            if self.target.repository.has_revision(self._last_revid):
464
 
                return []
465
 
            return [head]
 
731
            else:
 
732
                self._last_revid = stop_revision
 
733
            real = interrepo.get_determine_wants_revids(
 
734
                [self._last_revid], include_tags=fetch_tags)
 
735
            return real(heads)
466
736
        pack_hint, head, refs = interrepo.fetch_objects(
467
737
            determine_wants, self.source.mapping, limit=limit)
468
738
        if (pack_hint is not None and
469
739
            self.target.repository._format.pack_compresses):
470
740
            self.target.repository.pack(hint=pack_hint)
471
 
        if head is not None:
472
 
            self._last_revid = self.source.lookup_foreign_revision_id(head)
 
741
        return head, refs
 
742
 
 
743
    def _update_revisions(self, stop_revision=None, overwrite=False):
 
744
        head, refs = self.fetch_objects(stop_revision, fetch_tags=None)
473
745
        if overwrite:
474
746
            prev_last_revid = None
475
747
        else:
476
748
            prev_last_revid = self.target.last_revision()
477
749
        self.target.generate_revision_history(self._last_revid,
478
 
            prev_last_revid)
479
 
        return head
 
750
            prev_last_revid, self.source)
 
751
        return head, refs
480
752
 
481
 
    def update_revisions(self, stop_revision=None, overwrite=False,
482
 
                         graph=None):
483
 
        """See InterBranch.update_revisions()."""
484
 
        self._update_revisions(stop_revision, overwrite, graph)
 
753
    def _basic_pull(self, stop_revision, overwrite, run_hooks,
 
754
              _override_hook_target, _hook_master):
 
755
        result = GitBranchPullResult()
 
756
        result.source_branch = self.source
 
757
        if _override_hook_target is None:
 
758
            result.target_branch = self.target
 
759
        else:
 
760
            result.target_branch = _override_hook_target
 
761
        self.source.lock_read()
 
762
        try:
 
763
            self.target.lock_write()
 
764
            try:
 
765
                # We assume that during 'pull' the target repository is closer than
 
766
                # the source one.
 
767
                (result.old_revno, result.old_revid) = \
 
768
                    self.target.last_revision_info()
 
769
                result.new_git_head, remote_refs = self._update_revisions(
 
770
                    stop_revision, overwrite=overwrite)
 
771
                tags_ret  = self.source.tags.merge_to(
 
772
                    self.target.tags, overwrite)
 
773
                if isinstance(tags_ret, tuple):
 
774
                    result.tag_updates, result.tag_conflicts = tags_ret
 
775
                else:
 
776
                    result.tag_conflicts = tags_ret
 
777
                (result.new_revno, result.new_revid) = \
 
778
                    self.target.last_revision_info()
 
779
                if _hook_master:
 
780
                    result.master_branch = _hook_master
 
781
                    result.local_branch = result.target_branch
 
782
                else:
 
783
                    result.master_branch = result.target_branch
 
784
                    result.local_branch = None
 
785
                if run_hooks:
 
786
                    for hook in branch.Branch.hooks['post_pull']:
 
787
                        hook(result)
 
788
                return result
 
789
            finally:
 
790
                self.target.unlock()
 
791
        finally:
 
792
            self.source.unlock()
485
793
 
486
794
    def pull(self, overwrite=False, stop_revision=None,
487
795
             possible_transports=None, _hook_master=None, run_hooks=True,
488
 
             _override_hook_target=None, local=False, limit=None):
 
796
             _override_hook_target=None, local=False):
489
797
        """See Branch.pull.
490
798
 
491
799
        :param _hook_master: Private parameter - set the branch to
495
803
            so it should not run its hooks.
496
804
        :param _override_hook_target: Private parameter - set the branch to be
497
805
            supplied as the target_branch to pull hooks.
498
 
        :param limit: Only import this many revisons.  `None`, the default,
499
 
            means import all revisions.
500
806
        """
501
807
        # This type of branch can't be bound.
502
 
        if local:
 
808
        bound_location = self.target.get_bound_location()
 
809
        if local and not bound_location:
503
810
            raise errors.LocalRequiresBoundBranch()
504
 
        result = GitBranchPullResult()
505
 
        result.source_branch = self.source
506
 
        if _override_hook_target is None:
507
 
            result.target_branch = self.target
508
 
        else:
509
 
            result.target_branch = _override_hook_target
 
811
        master_branch = None
 
812
        source_is_master = False
510
813
        self.source.lock_read()
 
814
        if bound_location:
 
815
            # bound_location comes from a config file, some care has to be
 
816
            # taken to relate it to source.user_url
 
817
            normalized = urlutils.normalize_url(bound_location)
 
818
            try:
 
819
                relpath = self.source.user_transport.relpath(normalized)
 
820
                source_is_master = (relpath == '')
 
821
            except (errors.PathNotChild, errors.InvalidURL):
 
822
                source_is_master = False
 
823
        if not local and bound_location and not source_is_master:
 
824
            # not pulling from master, so we need to update master.
 
825
            master_branch = self.target.get_master_branch(possible_transports)
 
826
            master_branch.lock_write()
511
827
        try:
512
 
            # We assume that during 'pull' the target repository is closer than
513
 
            # the source one.
514
 
            graph = self.target.repository.get_graph(self.source.repository)
515
 
            (result.old_revno, result.old_revid) = \
516
 
                self.target.last_revision_info()
517
 
            result.new_git_head = self._update_revisions(
518
 
                stop_revision, overwrite=overwrite, graph=graph, limit=limit)
519
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
520
 
                overwrite)
521
 
            (result.new_revno, result.new_revid) = \
522
 
                self.target.last_revision_info()
523
 
            if _hook_master:
524
 
                result.master_branch = _hook_master
525
 
                result.local_branch = result.target_branch
526
 
            else:
527
 
                result.master_branch = result.target_branch
528
 
                result.local_branch = None
529
 
            if run_hooks:
530
 
                for hook in branch.Branch.hooks['post_pull']:
531
 
                    hook(result)
 
828
            try:
 
829
                if master_branch:
 
830
                    # pull from source into master.
 
831
                    master_branch.pull(self.source, overwrite, stop_revision,
 
832
                        run_hooks=False)
 
833
                result = self._basic_pull(stop_revision, overwrite, run_hooks,
 
834
                    _override_hook_target, _hook_master=master_branch)
 
835
            finally:
 
836
                self.source.unlock()
532
837
        finally:
533
 
            self.source.unlock()
 
838
            if master_branch:
 
839
                master_branch.unlock()
534
840
        return result
535
841
 
536
842
    def _basic_push(self, overwrite=False, stop_revision=None):
537
843
        result = branch.BranchPushResult()
538
844
        result.source_branch = self.source
539
845
        result.target_branch = self.target
540
 
        graph = self.target.repository.get_graph(self.source.repository)
541
846
        result.old_revno, result.old_revid = self.target.last_revision_info()
542
 
        result.new_git_head = self._update_revisions(
543
 
            stop_revision, overwrite=overwrite, graph=graph)
544
 
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
847
        result.new_git_head, remote_refs = self._update_revisions(
 
848
            stop_revision, overwrite=overwrite)
 
849
        tags_ret = self.source.tags.merge_to(self.target.tags,
545
850
            overwrite)
 
851
        if isinstance(tags_ret, tuple):
 
852
            (result.tag_updates, result.tag_conflicts) = tags_ret
 
853
        else:
 
854
            result.tag_conflicts = tags_ret
546
855
        result.new_revno, result.new_revid = self.target.last_revision_info()
547
856
        return result
548
857
 
551
860
    """InterBranch implementation that pulls between Git branches."""
552
861
 
553
862
 
554
 
class InterGitLocalRemoteBranch(InterGitBranch):
 
863
class InterLocalGitRemoteGitBranch(InterGitBranch):
555
864
    """InterBranch that copies from a local to a remote git branch."""
556
865
 
557
866
    @staticmethod
558
867
    def _get_branch_formats_to_test():
 
868
        # FIXME
559
869
        return []
560
870
 
561
871
    @classmethod
565
875
                isinstance(target, RemoteGitBranch))
566
876
 
567
877
    def _basic_push(self, overwrite=False, stop_revision=None):
568
 
        from dulwich.protocol import ZERO_SHA
569
878
        result = GitBranchPushResult()
570
879
        result.source_branch = self.source
571
880
        result.target_branch = self.target
573
882
            stop_revision = self.source.last_revision()
574
883
        # FIXME: Check for diverged branches
575
884
        def get_changed_refs(old_refs):
576
 
            result.old_revid = self.target.lookup_foreign_revision_id(old_refs.get(self.target.ref, ZERO_SHA))
 
885
            old_ref = old_refs.get(self.target.ref, ZERO_SHA)
 
886
            result.old_revid = self.target.lookup_foreign_revision_id(old_ref)
577
887
            refs = { self.target.ref: self.source.repository.lookup_bzr_revision_id(stop_revision)[0] }
578
888
            result.new_revid = stop_revision
579
889
            for name, sha in self.source.repository._git.refs.as_dict("refs/tags").iteritems():
584
894
        return result
585
895
 
586
896
 
587
 
class InterGitRemoteLocalBranch(InterGitBranch):
 
897
class InterGitLocalGitBranch(InterGitBranch):
588
898
    """InterBranch that copies from a remote to a local git branch."""
589
899
 
590
900
    @staticmethod
591
901
    def _get_branch_formats_to_test():
 
902
        # FIXME
592
903
        return []
593
904
 
594
905
    @classmethod
595
906
    def is_compatible(self, source, target):
596
 
        from bzrlib.plugins.git.remote import RemoteGitBranch
597
 
        return (isinstance(source, RemoteGitBranch) and
 
907
        return (isinstance(source, GitBranch) and
598
908
                isinstance(target, LocalGitBranch))
599
909
 
600
910
    def _basic_push(self, overwrite=False, stop_revision=None):
601
 
        result = branch.BranchPushResult()
 
911
        result = GitBranchPushResult()
602
912
        result.source_branch = self.source
603
913
        result.target_branch = self.target
604
914
        result.old_revid = self.target.last_revision()
605
915
        refs, stop_revision = self.update_refs(stop_revision)
606
916
        self.target.generate_revision_history(stop_revision, result.old_revid)
607
 
        self.update_tags(refs)
 
917
        tags_ret = self.source.tags.merge_to(self.target.tags,
 
918
            source_refs=refs, overwrite=overwrite)
 
919
        if isinstance(tags_ret, tuple):
 
920
            (result.tag_updates, result.tag_conflicts) = tags_ret
 
921
        else:
 
922
            result.tag_conflicts = tags_ret
608
923
        result.new_revid = self.target.last_revision()
609
924
        return result
610
925
 
611
 
    def update_tags(self, refs):
612
 
        for name, v in extract_tags(refs).iteritems():
613
 
            revid = self.target.lookup_foreign_revision_id(v)
614
 
            self.target.tags.set_tag(name, revid)
615
 
 
616
926
    def update_refs(self, stop_revision=None):
617
 
        interrepo = repository.InterRepository.get(self.source.repository,
 
927
        interrepo = _mod_repository.InterRepository.get(self.source.repository,
618
928
            self.target.repository)
619
929
        if stop_revision is None:
620
930
            refs = interrepo.fetch(branches=["HEAD"])
631
941
        result = GitPullResult()
632
942
        result.source_branch = self.source
633
943
        result.target_branch = self.target
634
 
        result.old_revid = self.target.last_revision()
635
 
        refs, stop_revision = self.update_refs(stop_revision)
636
 
        self.target.generate_revision_history(stop_revision, result.old_revid)
637
 
        self.update_tags(refs)
638
 
        result.new_revid = self.target.last_revision()
 
944
        self.source.lock_read()
 
945
        try:
 
946
            self.target.lock_write()
 
947
            try:
 
948
                result.old_revid = self.target.last_revision()
 
949
                refs, stop_revision = self.update_refs(stop_revision)
 
950
                self.target.generate_revision_history(stop_revision, result.old_revid)
 
951
                tags_ret = self.source.tags.merge_to(self.target.tags,
 
952
                    overwrite=overwrite, source_refs=refs)
 
953
                if isinstance(tags_ret, tuple):
 
954
                    (result.tag_updates, result.tag_conflicts) = tags_ret
 
955
                else:
 
956
                    result.tag_conflicts = tags_ret
 
957
                result.new_revid = self.target.last_revision()
 
958
                result.local_branch = None
 
959
                result.master_branch = result.target_branch
 
960
                if run_hooks:
 
961
                    for hook in branch.Branch.hooks['post_pull']:
 
962
                        hook(result)
 
963
            finally:
 
964
                self.target.unlock()
 
965
        finally:
 
966
            self.source.unlock()
639
967
        return result
640
968
 
641
969
 
642
970
class InterToGitBranch(branch.GenericInterBranch):
643
 
    """InterBranch implementation that pulls from Git into bzr."""
 
971
    """InterBranch implementation that pulls into a Git branch."""
644
972
 
645
973
    def __init__(self, source, target):
646
974
        super(InterToGitBranch, self).__init__(source, target)
647
 
        self.interrepo = repository.InterRepository.get(source.repository,
 
975
        self.interrepo = _mod_repository.InterRepository.get(source.repository,
648
976
                                           target.repository)
649
977
 
650
978
    @staticmethod
651
979
    def _get_branch_formats_to_test():
652
 
        return []
 
980
        try:
 
981
            default_format = branch.format_registry.get_default()
 
982
        except AttributeError:
 
983
            default_format = branch.BranchFormat._default_format
 
984
        return [(default_format, GitBranchFormat())]
653
985
 
654
986
    @classmethod
655
987
    def is_compatible(self, source, target):
656
988
        return (not isinstance(source, GitBranch) and
657
989
                isinstance(target, GitBranch))
658
990
 
659
 
    def update_revisions(self, *args, **kwargs):
660
 
        raise NoPushSupport()
661
 
 
662
 
    def _get_new_refs(self, stop_revision=None):
 
991
    def _get_new_refs(self, stop_revision=None, fetch_tags=None):
 
992
        assert self.source.is_locked()
663
993
        if stop_revision is None:
664
 
            stop_revision = self.source.last_revision()
 
994
            (stop_revno, stop_revision) = self.source.last_revision_info()
 
995
        else:
 
996
            stop_revno = self.source.revision_id_to_revno(stop_revision)
665
997
        assert type(stop_revision) is str
666
998
        main_ref = self.target.ref or "refs/heads/master"
667
999
        refs = { main_ref: (None, stop_revision) }
 
1000
        if fetch_tags is None:
 
1001
            c = self.source.get_config()
 
1002
            fetch_tags = c.get_user_option_as_bool('branch.fetch_tags')
668
1003
        for name, revid in self.source.tags.get_tag_dict().iteritems():
669
1004
            if self.source.repository.has_revision(revid):
670
 
                refs[tag_name_to_ref(name)] = (None, revid)
671
 
        return refs, main_ref
 
1005
                ref = tag_name_to_ref(name)
 
1006
                if not check_ref_format(ref):
 
1007
                    warning("skipping tag with invalid characters %s (%s)",
 
1008
                        name, ref)
 
1009
                    continue
 
1010
                if fetch_tags:
 
1011
                    # FIXME: Skip tags that are not in the ancestry
 
1012
                    refs[ref] = (None, revid)
 
1013
        return refs, main_ref, (stop_revno, stop_revision)
 
1014
 
 
1015
    def _update_refs(self, result, old_refs, new_refs, overwrite):
 
1016
        mutter("updating refs. old refs: %r, new refs: %r",
 
1017
               old_refs, new_refs)
 
1018
        result.tag_updates = {}
 
1019
        result.tag_conflicts = []
 
1020
        ret = dict(old_refs)
 
1021
        def ref_equals(refs, ref, git_sha, revid):
 
1022
            try:
 
1023
                value = refs[ref]
 
1024
            except KeyError:
 
1025
                return False
 
1026
            if (value[0] is not None and
 
1027
                git_sha is not None and
 
1028
                value[0] != git_sha):
 
1029
                return False
 
1030
            if (value[1] is not None and
 
1031
                revid is not None and
 
1032
                value[1] != revid):
 
1033
                return False
 
1034
            # FIXME: If one side only has the git sha available and the other only
 
1035
            # has the bzr revid, then this will cause us to show a tag as updated
 
1036
            # that hasn't actually been updated. 
 
1037
            return True
 
1038
        for ref, (git_sha, revid) in new_refs.iteritems():
 
1039
            if ref not in ret or overwrite:
 
1040
                if not ref_equals(ret, ref, git_sha, revid):
 
1041
                    try:
 
1042
                        tag_name = ref_to_tag_name(ref)
 
1043
                    except ValueError:
 
1044
                        pass
 
1045
                    else:
 
1046
                        result.tag_updates[tag_name] = revid
 
1047
                ret[ref] = (git_sha, revid)
 
1048
            elif ref_equals(ret, ref, git_sha, revid):
 
1049
                pass
 
1050
            else:
 
1051
                try:
 
1052
                    name = ref_to_tag_name(ref)
 
1053
                except ValueError:
 
1054
                    pass
 
1055
                else:
 
1056
                    result.tag_conflicts.append((name, revid, ret[name][1]))
 
1057
        # FIXME: Check for diverged branches
 
1058
        ret.update(new_refs)
 
1059
        return ret
672
1060
 
673
1061
    def pull(self, overwrite=False, stop_revision=None, local=False,
674
 
             possible_transports=None):
675
 
        from dulwich.protocol import ZERO_SHA
 
1062
             possible_transports=None, run_hooks=True):
676
1063
        result = GitBranchPullResult()
677
1064
        result.source_branch = self.source
678
1065
        result.target_branch = self.target
679
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
680
 
        def update_refs(old_refs):
681
 
            refs = dict(old_refs)
682
 
            # FIXME: Check for diverged branches
683
 
            refs.update(new_refs)
684
 
            return refs
685
 
        old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
686
 
        result.old_revid = self.target.lookup_foreign_revision_id(
687
 
            old_refs.get(main_ref, ZERO_SHA))
688
 
        result.new_revid = new_refs[main_ref]
 
1066
        self.source.lock_read()
 
1067
        try:
 
1068
            self.target.lock_write()
 
1069
            try:
 
1070
                new_refs, main_ref, stop_revinfo = self._get_new_refs(
 
1071
                    stop_revision)
 
1072
                def update_refs(old_refs):
 
1073
                    return self._update_refs(result, old_refs, new_refs, overwrite)
 
1074
                try:
 
1075
                    result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
 
1076
                        update_refs, lossy=False)
 
1077
                except NoPushSupport:
 
1078
                    raise errors.NoRoundtrippingSupport(self.source, self.target)
 
1079
                (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
 
1080
                if result.old_revid is None:
 
1081
                    result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
 
1082
                result.new_revid = new_refs[main_ref][1]
 
1083
                result.local_branch = None
 
1084
                result.master_branch = self.target
 
1085
                if run_hooks:
 
1086
                    for hook in branch.Branch.hooks['post_pull']:
 
1087
                        hook(result)
 
1088
            finally:
 
1089
                self.target.unlock()
 
1090
        finally:
 
1091
            self.source.unlock()
689
1092
        return result
690
1093
 
691
 
    def push(self, overwrite=False, stop_revision=None,
 
1094
    def push(self, overwrite=False, stop_revision=None, lossy=False,
692
1095
             _override_hook_source_branch=None):
693
 
        from dulwich.protocol import ZERO_SHA
694
1096
        result = GitBranchPushResult()
695
1097
        result.source_branch = self.source
696
1098
        result.target_branch = self.target
697
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
698
 
        def update_refs(old_refs):
699
 
            refs = dict(old_refs)
700
 
            # FIXME: Check for diverged branches
701
 
            refs.update(new_refs)
702
 
            return refs
703
 
        old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
704
 
        (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
705
 
        if result.old_revid is None:
706
 
            result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
707
 
        result.new_revid = new_refs[main_ref]
 
1099
        result.local_branch = None
 
1100
        result.master_branch = result.target_branch
 
1101
        self.source.lock_read()
 
1102
        try:
 
1103
            new_refs, main_ref, stop_revinfo = self._get_new_refs(stop_revision)
 
1104
            def update_refs(old_refs):
 
1105
                return self._update_refs(result, old_refs, new_refs, overwrite)
 
1106
            try:
 
1107
                result.revidmap, old_refs, new_refs = self.interrepo.fetch_refs(
 
1108
                    update_refs, lossy=lossy)
 
1109
            except NoPushSupport:
 
1110
                raise errors.NoRoundtrippingSupport(self.source, self.target)
 
1111
            (old_sha1, result.old_revid) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
 
1112
            if result.old_revid is None:
 
1113
                result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
 
1114
            result.new_revid = new_refs[main_ref][1]
 
1115
            (result.new_original_revno, result.new_original_revid) = stop_revinfo
 
1116
            for hook in branch.Branch.hooks['post_push']:
 
1117
                hook(result)
 
1118
        finally:
 
1119
            self.source.unlock()
708
1120
        return result
709
1121
 
710
1122
    def lossy_push(self, stop_revision=None):
711
 
        result = GitBranchPushResult()
712
 
        result.source_branch = self.source
713
 
        result.target_branch = self.target
714
 
        new_refs, main_ref = self._get_new_refs(stop_revision)
715
 
        def update_refs(old_refs):
716
 
            refs = dict(old_refs)
717
 
            # FIXME: Check for diverged branches
718
 
            refs.update(new_refs)
719
 
            return refs
720
 
        result.revidmap, old_refs, new_refs = self.interrepo.dfetch_refs(
721
 
            update_refs)
722
 
        result.old_revid = old_refs.get(self.target.ref, (None, NULL_REVISION))[1]
723
 
        result.new_revid = new_refs[main_ref][1]
724
 
        return result
725
 
 
726
 
 
727
 
branch.InterBranch.register_optimiser(InterGitRemoteLocalBranch)
 
1123
        # For compatibility with bzr < 2.4
 
1124
        return self.push(lossy=True, stop_revision=stop_revision)
 
1125
 
 
1126
 
 
1127
branch.InterBranch.register_optimiser(InterGitLocalGitBranch)
728
1128
branch.InterBranch.register_optimiser(InterFromGitBranch)
729
1129
branch.InterBranch.register_optimiser(InterToGitBranch)
730
 
branch.InterBranch.register_optimiser(InterGitLocalRemoteBranch)
 
1130
branch.InterBranch.register_optimiser(InterLocalGitRemoteGitBranch)