/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

Set refs/heads/master if no ref is set yet.

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