/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

  • Committer: Jelmer Vernooij
  • Date: 2010-05-13 12:34:24 UTC
  • mto: (0.200.912 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20100513123424-c1sk9vcg2ekrcsol
Some refactoring, support proper file ids in revision deltas.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2007 Canonical Ltd
2
 
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
 
2
# Copyright (C) 2009-2010 Jelmer Vernooij <jelmer@samba.org>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
27
27
    bzrdir,
28
28
    config,
29
29
    errors,
30
 
    foreign,
31
30
    repository,
32
31
    revision,
33
32
    tag,
51
50
    NoPushSupport,
52
51
    NoSuchRef,
53
52
    )
54
 
 
55
 
try:
56
 
    from bzrlib.foreign import ForeignBranch
57
 
except ImportError:
58
 
    class ForeignBranch(branch.Branch):
59
 
        def __init__(self, mapping):
60
 
            self.mapping = mapping
61
 
            super(ForeignBranch, self).__init__()
62
 
 
63
 
 
64
 
def extract_tags(refs, mapping):
65
 
    ret = {}
66
 
    for k,v in refs.iteritems():
67
 
        if k.startswith("refs/tags/") and not k.endswith("^{}"):
68
 
            v = refs.get(k+"^{}", v)
69
 
            ret[k[len("refs/tags/"):]] = mapping.revision_id_foreign_to_bzr(v)
70
 
    return ret
 
53
from bzrlib.plugins.git.refs import (
 
54
    ref_to_branch_name,
 
55
    extract_tags,
 
56
    tag_name_to_ref,
 
57
    )
 
58
 
 
59
from bzrlib.foreign import ForeignBranch
71
60
 
72
61
 
73
62
class GitPullResult(branch.PullResult):
95
84
 
96
85
    def get_tag_dict(self):
97
86
        ret = {}
98
 
        for k,v in self.repository._git.refs.as_dict("refs/tags").iteritems():
99
 
            obj = self.repository._git.get_object(v)
 
87
        for k,v in extract_tags(self.repository._git.get_refs()).iteritems():
 
88
            try:
 
89
                obj = self.repository._git[v]
 
90
            except KeyError:
 
91
                mutter("Tag %s points at unknown object %s, ignoring", v, obj)
 
92
                continue
100
93
            while isinstance(obj, Tag):
101
94
                v = obj.object[1]
102
 
                obj = self.repository._git.get_object(v)
 
95
                obj = self.repository._git[v]
103
96
            if not isinstance(obj, Commit):
104
97
                mutter("Tag %s points at object %r that is not a commit, "
105
98
                       "ignoring", k, obj)
107
100
            ret[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
108
101
        return ret
109
102
 
 
103
    def _set_tag_dict(self, to_dict):
 
104
        extra = set(self.repository._git.get_refs().keys())
 
105
        for k, revid in to_dict.iteritems():
 
106
            name = tag_name_to_ref(k)
 
107
            if name in extra:
 
108
                extra.remove(name)
 
109
            self.set_tag(k, revid)
 
110
        for name in extra:
 
111
            if name.startswith("refs/tags/"):
 
112
                del self.repository._git[name]
 
113
        
110
114
    def set_tag(self, name, revid):
111
 
        self.repository._git.refs["refs/tags/%s" % name], _ = \
 
115
        self.repository._git.refs[tag_name_to_ref(name)], _ = \
112
116
            self.branch.mapping.revision_id_bzr_to_foreign(revid)
113
117
 
114
118
 
 
119
class DictTagDict(LocalGitTagDict):
 
120
 
 
121
    def __init__(self, branch, tags):
 
122
        super(DictTagDict, self).__init__(branch)
 
123
        self._tags = tags
 
124
 
 
125
    def get_tag_dict(self):
 
126
        return self._tags
 
127
 
 
128
 
115
129
class GitBranchFormat(branch.BranchFormat):
116
130
 
117
131
    def get_format_description(self):
118
132
        return 'Git Branch'
119
133
 
 
134
    def network_name(self):
 
135
        return "git"
 
136
 
120
137
    def supports_tags(self):
121
138
        return True
122
139
 
 
140
    def get_foreign_tests_branch_factory(self):
 
141
        from bzrlib.plugins.git.tests.test_branch import ForeignTestsBranchFactory
 
142
        return ForeignTestsBranchFactory()
 
143
 
123
144
    def make_tags(self, branch):
124
145
        if getattr(branch.repository, "get_refs", None) is not None:
125
146
            from bzrlib.plugins.git.remote import RemoteGitTagDict
128
149
            return LocalGitTagDict(branch)
129
150
 
130
151
 
 
152
class GitReadLock(object):
 
153
 
 
154
    def __init__(self, unlock):
 
155
        self.unlock = unlock
 
156
 
 
157
 
 
158
class GitWriteLock(object):
 
159
 
 
160
    def __init__(self, unlock):
 
161
        self.unlock = unlock
 
162
 
 
163
 
131
164
class GitBranch(ForeignBranch):
132
165
    """An adapter to git repositories for bzr Branch objects."""
133
166
 
134
 
    def __init__(self, bzrdir, repository, name, lockfiles):
 
167
    def __init__(self, bzrdir, repository, ref, lockfiles, tagsdict=None):
135
168
        self.repository = repository
136
169
        self._format = GitBranchFormat()
137
170
        self.control_files = lockfiles
138
171
        self.bzrdir = bzrdir
139
172
        super(GitBranch, self).__init__(repository.get_mapping())
140
 
        self.name = name
 
173
        if tagsdict is not None:
 
174
            self.tags = DictTagDict(self, tagsdict)
 
175
        self.ref = ref
 
176
        self.name = ref_to_branch_name(ref)
141
177
        self._head = None
142
 
        self.base = bzrdir.transport.base
 
178
        self.base = bzrdir.root_transport.base
 
179
 
 
180
    def _get_checkout_format(self):
 
181
        """Return the most suitable metadir for a checkout of this branch.
 
182
        Weaves are used if this branch's repository uses weaves.
 
183
        """
 
184
        return get_rich_root_format()
 
185
 
 
186
    def get_child_submit_format(self):
 
187
        """Return the preferred format of submissions to this branch."""
 
188
        ret = self.get_config().get_user_option("child_submit_format")
 
189
        if ret is not None:
 
190
            return ret
 
191
        return "git"
143
192
 
144
193
    def _get_nick(self, local=False, possible_master_transports=None):
145
194
        """Find the nick name for this branch.
154
203
    nick = property(_get_nick, _set_nick)
155
204
 
156
205
    def __repr__(self):
157
 
        return "%s(%r, %r)" % (self.__class__.__name__, self.repository.base, self.name)
 
206
        return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
 
207
            self.ref)
158
208
 
159
209
    def generate_revision_history(self, revid, old_revid=None):
160
210
        # FIXME: Check that old_revid is in the ancestry of revid
163
213
 
164
214
    def lock_write(self):
165
215
        self.control_files.lock_write()
 
216
        return GitWriteLock(self.unlock)
166
217
 
167
218
    def get_stacked_on_url(self):
168
219
        # Git doesn't do stacking (yet...)
169
 
        return None
 
220
        raise errors.UnstackableBranchFormat(self._format, self.base)
170
221
 
171
222
    def get_parent(self):
172
223
        """See Branch.get_parent()."""
179
230
 
180
231
    def lock_read(self):
181
232
        self.control_files.lock_read()
 
233
        return GitReadLock(self.unlock)
182
234
 
183
235
    def is_locked(self):
184
236
        return self.control_files.is_locked()
200
252
        return branch.InterBranch.get(self, target)._basic_push(
201
253
            overwrite, stop_revision)
202
254
 
203
 
 
 
255
 
204
256
class LocalGitBranch(GitBranch):
205
257
    """A local Git branch."""
206
258
 
207
 
    def _get_checkout_format(self):
208
 
        """Return the most suitable metadir for a checkout of this branch.
209
 
        Weaves are used if this branch's repository uses weaves.
210
 
        """
211
 
        format = self.repository.bzrdir.checkout_metadir()
212
 
        format.set_branch_format(self._format)
213
 
        return format
 
259
    def __init__(self, bzrdir, repository, name, lockfiles, tagsdict=None):
 
260
        super(LocalGitBranch, self).__init__(bzrdir, repository, name, 
 
261
              lockfiles, tagsdict)
 
262
        if not name in repository._git.get_refs().keys():
 
263
            raise errors.NotBranchError(self.base)
214
264
 
215
265
    def create_checkout(self, to_location, revision_id=None, lightweight=False,
216
266
        accelerator_tree=None, hardlink=False):
219
269
            t.ensure_base()
220
270
            format = self._get_checkout_format()
221
271
            checkout = format.initialize_on_transport(t)
222
 
            from_branch = branch.BranchReferenceFormat().initialize(checkout, 
 
272
            from_branch = branch.BranchReferenceFormat().initialize(checkout,
223
273
                self)
224
274
            tree = checkout.create_workingtree(revision_id,
225
275
                from_branch=from_branch, hardlink=hardlink)
228
278
            return self._create_heavyweight_checkout(to_location, revision_id,
229
279
            hardlink)
230
280
 
231
 
    def _create_heavyweight_checkout(self, to_location, revision_id=None, 
 
281
    def _create_heavyweight_checkout(self, to_location, revision_id=None,
232
282
                                     hardlink=False):
233
283
        """Create a new heavyweight checkout of this branch.
234
284
 
241
291
            to_location, force_new_tree=False, format=get_rich_root_format())
242
292
        checkout = checkout_branch.bzrdir
243
293
        checkout_branch.bind(self)
244
 
        # pull up to the specified revision_id to set the initial 
 
294
        # pull up to the specified revision_id to set the initial
245
295
        # branch tip correctly, and seed it with history.
246
296
        checkout_branch.pull(self, stop_revision=revision_id)
247
297
        return checkout.create_workingtree(revision_id, hardlink=hardlink)
256
306
 
257
307
    def _get_head(self):
258
308
        try:
259
 
            return self.repository._git.ref(self.name)
 
309
            return self.repository._git.ref(self.ref)
260
310
        except KeyError:
261
311
            return None
262
312
 
264
314
        self.set_last_revision(revid)
265
315
 
266
316
    def set_last_revision(self, revid):
267
 
        (newhead, self.mapping) = self.mapping.revision_id_bzr_to_foreign(
268
 
                revid)
 
317
        (newhead, self.mapping) = self.repository.lookup_bzr_revision_id(revid)
269
318
        self.head = newhead
270
319
 
271
320
    def _set_head(self, value):
272
321
        self._head = value
273
 
        self.repository._git.refs[self.name] = self._head
 
322
        self.repository._git.refs[self.ref] = self._head
274
323
        self._clear_cached_state()
275
324
 
276
325
    head = property(_get_head, _set_head)
294
343
 
295
344
class GitBranchPullResult(branch.PullResult):
296
345
 
 
346
    def __init__(self):
 
347
        super(GitBranchPullResult, self).__init__()
 
348
        self.new_git_head = None
 
349
        self._old_revno = None
 
350
        self._new_revno = None
 
351
 
297
352
    def report(self, to_file):
298
353
        if not is_quiet():
299
354
            if self.old_revid == self.new_revid:
300
355
                to_file.write('No revisions to pull.\n')
301
 
            else:
302
 
                to_file.write('Now on revision %d (git sha: %s).\n' % 
 
356
            elif self.new_git_head is not None:
 
357
                to_file.write('Now on revision %d (git sha: %s).\n' %
303
358
                        (self.new_revno, self.new_git_head))
 
359
            else:
 
360
                to_file.write('Now on revision %d.\n' % (self.new_revno,))
304
361
        self._show_tag_conficts(to_file)
305
362
 
 
363
    def _lookup_revno(self, revid):
 
364
        assert isinstance(revid, str), "was %r" % revid
 
365
        # Try in source branch first, it'll be faster
 
366
        try:
 
367
            return self.source_branch.revision_id_to_revno(revid)
 
368
        except errors.NoSuchRevision:
 
369
            # FIXME: Check using graph.find_distance_to_null() ?
 
370
            return self.target_branch.revision_id_to_revno(revid)
 
371
 
 
372
    def _get_old_revno(self):
 
373
        if self._old_revno is not None:
 
374
            return self._old_revno
 
375
        return self._lookup_revno(self.old_revid)
 
376
 
 
377
    def _set_old_revno(self, revno):
 
378
        self._old_revno = revno
 
379
 
 
380
    old_revno = property(_get_old_revno, _set_old_revno)
 
381
 
 
382
    def _get_new_revno(self):
 
383
        if self._new_revno is not None:
 
384
            return self._new_revno
 
385
        return self._lookup_revno(self.new_revid)
 
386
 
 
387
    def _set_new_revno(self, revno):
 
388
        self._new_revno = revno
 
389
    
 
390
    new_revno = property(_get_new_revno, _set_new_revno)
 
391
 
306
392
 
307
393
class GitBranchPushResult(branch.BranchPushResult):
308
394
 
328
414
    """InterBranch implementation that pulls from Git into bzr."""
329
415
 
330
416
    @classmethod
331
 
    def is_compatible(self, source, target):
332
 
        return (isinstance(source, GitBranch) and 
333
 
                not isinstance(target, GitBranch))
334
 
 
335
 
    def update_revisions(self, stop_revision=None, overwrite=False,
336
 
        graph=None):
337
 
        """See InterBranch.update_revisions()."""
338
 
        interrepo = repository.InterRepository.get(self.source.repository, 
339
 
            self.target.repository)
340
 
        self._head = None
341
 
        self._last_revid = None
 
417
    def _get_interrepo(self, source, target):
 
418
        return repository.InterRepository.get(source.repository,
 
419
            target.repository)
 
420
 
 
421
    @classmethod
 
422
    def is_compatible(cls, source, target):
 
423
        return (isinstance(source, GitBranch) and
 
424
                not isinstance(target, GitBranch) and
 
425
                (getattr(cls._get_interrepo(source, target), "fetch_objects", None) is not None))
 
426
 
 
427
    def _update_revisions(self, stop_revision=None, overwrite=False,
 
428
        graph=None, limit=None):
 
429
        """Like InterBranch.update_revisions(), but with additions.
 
430
 
 
431
        Compared to the `update_revisions()` below, this function takes a
 
432
        `limit` argument that limits how many git commits will be converted
 
433
        and returns the new git head.
 
434
        """
 
435
        interrepo = self._get_interrepo(self.source, self.target)
342
436
        def determine_wants(heads):
343
 
            if not self.source.name in heads:
344
 
                raise NoSuchRef(self.source.name, heads.keys())
 
437
            if not self.source.ref in heads:
 
438
                raise NoSuchRef(self.source.ref, heads.keys())
345
439
            if stop_revision is not None:
346
440
                self._last_revid = stop_revision
347
 
                self._head, mapping = self.source.repository.lookup_git_revid(
 
441
                head, mapping = self.source.repository.lookup_bzr_revision_id(
348
442
                    stop_revision)
349
443
            else:
350
 
                self._head = heads[self.source.name]
351
 
                self._last_revid = \
352
 
                    self.source.mapping.revision_id_foreign_to_bzr(self._head)
 
444
                head = heads[self.source.ref]
 
445
                self._last_revid = self.source.mapping.revision_id_foreign_to_bzr(
 
446
                    head)
353
447
            if self.target.repository.has_revision(self._last_revid):
354
448
                return []
355
 
            return [self._head]
356
 
        interrepo.fetch_objects(determine_wants, self.source.mapping)
 
449
            return [head]
 
450
        pack_hint, head = interrepo.fetch_objects(
 
451
            determine_wants, self.source.mapping, limit=limit)
 
452
        if pack_hint is not None and self.target.repository._format.pack_compresses:
 
453
            self.target.repository.pack(hint=pack_hint)
 
454
        if head is not None:
 
455
            self._last_revid = self.source.mapping.revision_id_foreign_to_bzr(head)
357
456
        if overwrite:
358
457
            prev_last_revid = None
359
458
        else:
360
459
            prev_last_revid = self.target.last_revision()
361
 
        self.target.generate_revision_history(self._last_revid, prev_last_revid)
 
460
        self.target.generate_revision_history(self._last_revid,
 
461
            prev_last_revid)
 
462
        return head
 
463
 
 
464
    def update_revisions(self, stop_revision=None, overwrite=False,
 
465
                         graph=None):
 
466
        """See InterBranch.update_revisions()."""
 
467
        self._update_revisions(stop_revision, overwrite, graph)
362
468
 
363
469
    def pull(self, overwrite=False, stop_revision=None,
364
470
             possible_transports=None, _hook_master=None, run_hooks=True,
365
 
             _override_hook_target=None, local=False):
 
471
             _override_hook_target=None, local=False, limit=None):
366
472
        """See Branch.pull.
367
473
 
368
474
        :param _hook_master: Private parameter - set the branch to
372
478
            so it should not run its hooks.
373
479
        :param _override_hook_target: Private parameter - set the branch to be
374
480
            supplied as the target_branch to pull hooks.
 
481
        :param limit: Only import this many revisons.  `None`, the default,
 
482
            means import all revisions.
375
483
        """
376
484
        # This type of branch can't be bound.
377
485
        if local:
387
495
            # We assume that during 'pull' the target repository is closer than
388
496
            # the source one.
389
497
            graph = self.target.repository.get_graph(self.source.repository)
390
 
            result.old_revno, result.old_revid = \
 
498
            (result.old_revno, result.old_revid) = \
391
499
                self.target.last_revision_info()
392
 
            self.update_revisions(stop_revision, overwrite=overwrite, 
393
 
                graph=graph)
394
 
            result.new_git_head = self._head
 
500
            result.new_git_head = self._update_revisions(
 
501
                stop_revision, overwrite=overwrite, graph=graph, limit=limit)
395
502
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
396
503
                overwrite)
397
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
504
            (result.new_revno, result.new_revid) = \
 
505
                self.target.last_revision_info()
398
506
            if _hook_master:
399
507
                result.master_branch = _hook_master
400
508
                result.local_branch = result.target_branch
414
522
        result.target_branch = self.target
415
523
        graph = self.target.repository.get_graph(self.source.repository)
416
524
        result.old_revno, result.old_revid = self.target.last_revision_info()
417
 
        self.update_revisions(stop_revision, overwrite=overwrite, 
418
 
            graph=graph)
419
 
        result.new_git_head = self._head
 
525
        result.new_git_head = self._update_revisions(
 
526
            stop_revision, overwrite=overwrite, graph=graph)
420
527
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
421
528
            overwrite)
422
529
        result.new_revno, result.new_revid = self.target.last_revision_info()
433
540
    @classmethod
434
541
    def is_compatible(self, source, target):
435
542
        from bzrlib.plugins.git.remote import RemoteGitBranch
436
 
        return (isinstance(source, LocalGitBranch) and 
 
543
        return (isinstance(source, LocalGitBranch) and
437
544
                isinstance(target, RemoteGitBranch))
438
545
 
439
546
    def _basic_push(self, overwrite=False, stop_revision=None):
 
547
        from dulwich.protocol import ZERO_SHA
440
548
        result = GitBranchPushResult()
441
549
        result.source_branch = self.source
442
550
        result.target_branch = self.target
444
552
            stop_revision = self.source.last_revision()
445
553
        # FIXME: Check for diverged branches
446
554
        def get_changed_refs(old_refs):
447
 
            result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(old_refs.get("refs/heads/master", "0" * 40))
448
 
            refs = { "refs/heads/master": self.source.repository.lookup_git_revid(stop_revision)[0] }
 
555
            result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(old_refs.get(self.target.ref, ZERO_SHA))
 
556
            refs = { self.target.ref: self.source.repository.lookup_bzr_revision_id(stop_revision)[0] }
449
557
            result.new_revid = stop_revision
450
558
            for name, sha in self.source.repository._git.refs.as_dict("refs/tags").iteritems():
451
 
                refs["refs/tags/%s" % name] = sha
 
559
                refs[tag_name_to_ref(name)] = sha
452
560
            return refs
453
 
        self.target.repository.send_pack(get_changed_refs, 
454
 
                self.source.repository._git.object_store.generate_pack_contents)
 
561
        self.target.repository.send_pack(get_changed_refs,
 
562
            self.source.repository._git.object_store.generate_pack_contents)
455
563
        return result
456
564
 
457
565
 
461
569
    @classmethod
462
570
    def is_compatible(self, source, target):
463
571
        from bzrlib.plugins.git.remote import RemoteGitBranch
464
 
        return (isinstance(source, RemoteGitBranch) and 
 
572
        return (isinstance(source, RemoteGitBranch) and
465
573
                isinstance(target, LocalGitBranch))
466
574
 
467
575
    def _basic_push(self, overwrite=False, stop_revision=None):
476
584
        return result
477
585
 
478
586
    def update_tags(self, refs):
479
 
        for name, revid in extract_tags(refs, self.target.mapping).iteritems():
 
587
        for name, v in extract_tags(refs).iteritems():
 
588
            revid = self.target.mapping.revision_id_foreign_to_bzr(v)
480
589
            self.target.tags.set_tag(name, revid)
481
590
 
482
591
    def update_refs(self, stop_revision=None):
483
 
        interrepo = repository.InterRepository.get(self.source.repository, 
 
592
        interrepo = repository.InterRepository.get(self.source.repository,
484
593
            self.target.repository)
485
594
        if stop_revision is None:
486
595
            refs = interrepo.fetch_refs(branches=["HEAD"])
489
598
            refs = interrepo.fetch_refs(revision_id=stop_revision)
490
599
        return refs, stop_revision
491
600
 
492
 
    def pull(self, stop_revision=None, overwrite=False, 
493
 
        possible_transports=None, local=False):
 
601
    def pull(self, stop_revision=None, overwrite=False,
 
602
        possible_transports=None, run_hooks=True,local=False):
494
603
        # This type of branch can't be bound.
495
604
        if local:
496
605
            raise errors.LocalRequiresBoundBranch()
504
613
        result.new_revid = self.target.last_revision()
505
614
        return result
506
615
 
507
 
    
 
616
 
508
617
class InterToGitBranch(branch.InterBranch):
509
618
    """InterBranch implementation that pulls from Git into bzr."""
510
619
 
 
620
    @staticmethod
 
621
    def _get_branch_formats_to_test():
 
622
        return None, None
 
623
 
511
624
    @classmethod
512
625
    def is_compatible(self, source, target):
513
 
        return (not isinstance(source, GitBranch) and 
 
626
        return (not isinstance(source, GitBranch) and
514
627
                isinstance(target, GitBranch))
515
628
 
516
629
    def update_revisions(self, *args, **kwargs):
517
630
        raise NoPushSupport()
518
631
 
519
 
    def push(self, overwrite=True, stop_revision=None, 
 
632
    def _get_new_refs(self, stop_revision=None):
 
633
        if stop_revision is None:
 
634
            stop_revision = self.source.last_revision()
 
635
        refs = { self.target.ref: stop_revision }
 
636
        for name, revid in self.source.tags.get_tag_dict().iteritems():
 
637
            if self.source.repository.has_revision(revid):
 
638
                refs[tag_name_to_ref(name)] = revid
 
639
        return refs
 
640
 
 
641
    def pull(self, overwrite=False, stop_revision=None, local=False,
 
642
             possible_transports=None):
 
643
        from dulwich.protocol import ZERO_SHA
 
644
        result = GitBranchPullResult()
 
645
        result.source_branch = self.source
 
646
        result.target_branch = self.target
 
647
        # FIXME: Check for diverged branches
 
648
        old_refs = self.target.repository._git.get_refs()
 
649
        refs = dict(old_refs)
 
650
        refs.update(self._get_new_refs(stop_revision))
 
651
        self.target.repository.fetch_refs(self.source.repository, refs)
 
652
        result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(
 
653
            old_refs.get(self.target.ref, ZERO_SHA))
 
654
        result.new_revid = refs[self.target.ref]
 
655
        return result
 
656
 
 
657
    def push(self, overwrite=False, stop_revision=None,
520
658
             _override_hook_source_branch=None):
521
 
        raise NoPushSupport()
 
659
        from dulwich.protocol import ZERO_SHA
 
660
        result = GitBranchPushResult()
 
661
        result.source_branch = self.source
 
662
        result.target_branch = self.target
 
663
        # FIXME: Check for diverged branches
 
664
        old_refs = self.target.repository._git.get_refs()
 
665
        refs = dict(old_refs)
 
666
        refs.update(self._get_new_refs(stop_revision))
 
667
        self.target.repository.fetch_refs(self.source.repository, refs)
 
668
        result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(
 
669
            old_refs.get(self.target.ref, ZERO_SHA))
 
670
        result.new_revid = refs[self.target.ref]
 
671
        return result
522
672
 
523
673
    def lossy_push(self, stop_revision=None):
 
674
        from dulwich.protocol import ZERO_SHA
524
675
        result = GitBranchPushResult()
525
676
        result.source_branch = self.source
526
677
        result.target_branch = self.target
527
 
        result.old_revid = self.target.last_revision()
528
 
        if stop_revision is None:
529
 
            stop_revision = self.source.last_revision()
530
678
        # FIXME: Check for diverged branches
531
 
        refs = { "refs/heads/master": stop_revision }
532
 
        for name, revid in self.source.tags.get_tag_dict().iteritems():
533
 
            if self.source.repository.has_revision(revid):
534
 
                refs["refs/tags/%s" % name] = revid
535
 
        revidmap, new_refs = self.target.repository.dfetch_refs(
 
679
        refs = self._get_new_refs(stop_revision)
 
680
        result.revidmap, old_refs, new_refs = self.target.repository.dfetch_refs(
536
681
            self.source.repository, refs)
537
 
        if revidmap != {}:
538
 
            self.target.generate_revision_history(revidmap[stop_revision])
539
 
            result.new_revid = revidmap[stop_revision]
540
 
        else:
541
 
            result.new_revid = result.old_revid
542
 
        result.revidmap = revidmap
 
682
        result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(
 
683
            old_refs.get(self.target.ref, ZERO_SHA))
 
684
        result.new_revid = self.target.mapping.revision_id_foreign_to_bzr(
 
685
            new_refs[self.target.ref])
543
686
        return result
544
687
 
545
688