/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 13:36:47 UTC
  • mto: (0.200.912 trunk)
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@samba.org-20100513133647-9vmseyj0oe3z0n3s
Finish fetching roundtripped revisions back into bzr.

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)
106
99
                continue
107
 
            ret[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
 
100
            ret[k] = self.branch.lookup_foreign_revision_id(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()
194
246
        # perhaps should escape this ?
195
247
        if self.head is None:
196
248
            return revision.NULL_REVISION
197
 
        return self.mapping.revision_id_foreign_to_bzr(self.head)
 
249
        return self.lookup_foreign_revision_id(self.head)
198
250
 
199
251
    def _basic_push(self, target, overwrite=False, stop_revision=None):
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)
291
340
    def supports_tags(self):
292
341
        return True
293
342
 
 
343
    def lookup_foreign_revision_id(self, foreign_revid):
 
344
        return self.repository.lookup_foreign_revision_id(foreign_revid, 
 
345
            self.mapping)
 
346
    
294
347
 
295
348
class GitBranchPullResult(branch.PullResult):
296
349
 
 
350
    def __init__(self):
 
351
        super(GitBranchPullResult, self).__init__()
 
352
        self.new_git_head = None
 
353
        self._old_revno = None
 
354
        self._new_revno = None
 
355
 
297
356
    def report(self, to_file):
298
357
        if not is_quiet():
299
358
            if self.old_revid == self.new_revid:
300
359
                to_file.write('No revisions to pull.\n')
301
 
            else:
302
 
                to_file.write('Now on revision %d (git sha: %s).\n' % 
 
360
            elif self.new_git_head is not None:
 
361
                to_file.write('Now on revision %d (git sha: %s).\n' %
303
362
                        (self.new_revno, self.new_git_head))
 
363
            else:
 
364
                to_file.write('Now on revision %d.\n' % (self.new_revno,))
304
365
        self._show_tag_conficts(to_file)
305
366
 
 
367
    def _lookup_revno(self, revid):
 
368
        assert isinstance(revid, str), "was %r" % revid
 
369
        # Try in source branch first, it'll be faster
 
370
        try:
 
371
            return self.source_branch.revision_id_to_revno(revid)
 
372
        except errors.NoSuchRevision:
 
373
            # FIXME: Check using graph.find_distance_to_null() ?
 
374
            return self.target_branch.revision_id_to_revno(revid)
 
375
 
 
376
    def _get_old_revno(self):
 
377
        if self._old_revno is not None:
 
378
            return self._old_revno
 
379
        return self._lookup_revno(self.old_revid)
 
380
 
 
381
    def _set_old_revno(self, revno):
 
382
        self._old_revno = revno
 
383
 
 
384
    old_revno = property(_get_old_revno, _set_old_revno)
 
385
 
 
386
    def _get_new_revno(self):
 
387
        if self._new_revno is not None:
 
388
            return self._new_revno
 
389
        return self._lookup_revno(self.new_revid)
 
390
 
 
391
    def _set_new_revno(self, revno):
 
392
        self._new_revno = revno
 
393
    
 
394
    new_revno = property(_get_new_revno, _set_new_revno)
 
395
 
306
396
 
307
397
class GitBranchPushResult(branch.BranchPushResult):
308
398
 
328
418
    """InterBranch implementation that pulls from Git into bzr."""
329
419
 
330
420
    @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
 
421
    def _get_interrepo(self, source, target):
 
422
        return repository.InterRepository.get(source.repository,
 
423
            target.repository)
 
424
 
 
425
    @classmethod
 
426
    def is_compatible(cls, source, target):
 
427
        return (isinstance(source, GitBranch) and
 
428
                not isinstance(target, GitBranch) and
 
429
                (getattr(cls._get_interrepo(source, target), "fetch_objects", None) is not None))
 
430
 
 
431
    def _update_revisions(self, stop_revision=None, overwrite=False,
 
432
        graph=None, limit=None):
 
433
        """Like InterBranch.update_revisions(), but with additions.
 
434
 
 
435
        Compared to the `update_revisions()` below, this function takes a
 
436
        `limit` argument that limits how many git commits will be converted
 
437
        and returns the new git head.
 
438
        """
 
439
        interrepo = self._get_interrepo(self.source, self.target)
342
440
        def determine_wants(heads):
343
 
            if not self.source.name in heads:
344
 
                raise NoSuchRef(self.source.name, heads.keys())
 
441
            if not self.source.ref in heads:
 
442
                raise NoSuchRef(self.source.ref, heads.keys())
345
443
            if stop_revision is not None:
346
444
                self._last_revid = stop_revision
347
 
                self._head, mapping = self.source.repository.lookup_git_revid(
 
445
                head, mapping = self.source.lookup_bzr_revision_id(
348
446
                    stop_revision)
349
447
            else:
350
 
                self._head = heads[self.source.name]
351
 
                self._last_revid = \
352
 
                    self.source.mapping.revision_id_foreign_to_bzr(self._head)
 
448
                head = heads[self.source.ref]
 
449
                self._last_revid = self.source.lookup_foreign_revision_id(head)
353
450
            if self.target.repository.has_revision(self._last_revid):
354
451
                return []
355
 
            return [self._head]
356
 
        interrepo.fetch_objects(determine_wants, self.source.mapping)
 
452
            return [head]
 
453
        pack_hint, head = interrepo.fetch_objects(
 
454
            determine_wants, self.source.mapping, limit=limit)
 
455
        if (pack_hint is not None and
 
456
            self.target.repository._format.pack_compresses):
 
457
            self.target.repository.pack(hint=pack_hint)
 
458
        if head is not None:
 
459
            self._last_revid = self.source.lookup_foreign_revision_id(head)
357
460
        if overwrite:
358
461
            prev_last_revid = None
359
462
        else:
360
463
            prev_last_revid = self.target.last_revision()
361
 
        self.target.generate_revision_history(self._last_revid, prev_last_revid)
 
464
        self.target.generate_revision_history(self._last_revid,
 
465
            prev_last_revid)
 
466
        return head
 
467
 
 
468
    def update_revisions(self, stop_revision=None, overwrite=False,
 
469
                         graph=None):
 
470
        """See InterBranch.update_revisions()."""
 
471
        self._update_revisions(stop_revision, overwrite, graph)
362
472
 
363
473
    def pull(self, overwrite=False, stop_revision=None,
364
474
             possible_transports=None, _hook_master=None, run_hooks=True,
365
 
             _override_hook_target=None, local=False):
 
475
             _override_hook_target=None, local=False, limit=None):
366
476
        """See Branch.pull.
367
477
 
368
478
        :param _hook_master: Private parameter - set the branch to
372
482
            so it should not run its hooks.
373
483
        :param _override_hook_target: Private parameter - set the branch to be
374
484
            supplied as the target_branch to pull hooks.
 
485
        :param limit: Only import this many revisons.  `None`, the default,
 
486
            means import all revisions.
375
487
        """
376
488
        # This type of branch can't be bound.
377
489
        if local:
387
499
            # We assume that during 'pull' the target repository is closer than
388
500
            # the source one.
389
501
            graph = self.target.repository.get_graph(self.source.repository)
390
 
            result.old_revno, result.old_revid = \
 
502
            (result.old_revno, result.old_revid) = \
391
503
                self.target.last_revision_info()
392
 
            self.update_revisions(stop_revision, overwrite=overwrite, 
393
 
                graph=graph)
394
 
            result.new_git_head = self._head
 
504
            result.new_git_head = self._update_revisions(
 
505
                stop_revision, overwrite=overwrite, graph=graph, limit=limit)
395
506
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
396
507
                overwrite)
397
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
508
            (result.new_revno, result.new_revid) = \
 
509
                self.target.last_revision_info()
398
510
            if _hook_master:
399
511
                result.master_branch = _hook_master
400
512
                result.local_branch = result.target_branch
414
526
        result.target_branch = self.target
415
527
        graph = self.target.repository.get_graph(self.source.repository)
416
528
        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
 
529
        result.new_git_head = self._update_revisions(
 
530
            stop_revision, overwrite=overwrite, graph=graph)
420
531
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
421
532
            overwrite)
422
533
        result.new_revno, result.new_revid = self.target.last_revision_info()
433
544
    @classmethod
434
545
    def is_compatible(self, source, target):
435
546
        from bzrlib.plugins.git.remote import RemoteGitBranch
436
 
        return (isinstance(source, LocalGitBranch) and 
 
547
        return (isinstance(source, LocalGitBranch) and
437
548
                isinstance(target, RemoteGitBranch))
438
549
 
439
550
    def _basic_push(self, overwrite=False, stop_revision=None):
 
551
        from dulwich.protocol import ZERO_SHA
440
552
        result = GitBranchPushResult()
441
553
        result.source_branch = self.source
442
554
        result.target_branch = self.target
444
556
            stop_revision = self.source.last_revision()
445
557
        # FIXME: Check for diverged branches
446
558
        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] }
 
559
            result.old_revid = self.target.lookup_foreign_revision_id(old_refs.get(self.target.ref, ZERO_SHA))
 
560
            refs = { self.target.ref: self.source.repository.lookup_bzr_revision_id(stop_revision)[0] }
449
561
            result.new_revid = stop_revision
450
562
            for name, sha in self.source.repository._git.refs.as_dict("refs/tags").iteritems():
451
 
                refs["refs/tags/%s" % name] = sha
 
563
                refs[tag_name_to_ref(name)] = sha
452
564
            return refs
453
 
        self.target.repository.send_pack(get_changed_refs, 
454
 
                self.source.repository._git.object_store.generate_pack_contents)
 
565
        self.target.repository.send_pack(get_changed_refs,
 
566
            self.source.repository._git.object_store.generate_pack_contents)
455
567
        return result
456
568
 
457
569
 
461
573
    @classmethod
462
574
    def is_compatible(self, source, target):
463
575
        from bzrlib.plugins.git.remote import RemoteGitBranch
464
 
        return (isinstance(source, RemoteGitBranch) and 
 
576
        return (isinstance(source, RemoteGitBranch) and
465
577
                isinstance(target, LocalGitBranch))
466
578
 
467
579
    def _basic_push(self, overwrite=False, stop_revision=None):
476
588
        return result
477
589
 
478
590
    def update_tags(self, refs):
479
 
        for name, revid in extract_tags(refs, self.target.mapping).iteritems():
 
591
        for name, v in extract_tags(refs).iteritems():
 
592
            revid = self.target.lookup_foreign_revision_id(v)
480
593
            self.target.tags.set_tag(name, revid)
481
594
 
482
595
    def update_refs(self, stop_revision=None):
483
 
        interrepo = repository.InterRepository.get(self.source.repository, 
 
596
        interrepo = repository.InterRepository.get(self.source.repository,
484
597
            self.target.repository)
485
598
        if stop_revision is None:
486
599
            refs = interrepo.fetch_refs(branches=["HEAD"])
487
 
            stop_revision = self.target.mapping.revision_id_foreign_to_bzr(refs["HEAD"])
 
600
            stop_revision = self.target.lookup_foreign_revision_id(refs["HEAD"])
488
601
        else:
489
602
            refs = interrepo.fetch_refs(revision_id=stop_revision)
490
603
        return refs, stop_revision
491
604
 
492
 
    def pull(self, stop_revision=None, overwrite=False, 
493
 
        possible_transports=None, local=False):
 
605
    def pull(self, stop_revision=None, overwrite=False,
 
606
        possible_transports=None, run_hooks=True,local=False):
494
607
        # This type of branch can't be bound.
495
608
        if local:
496
609
            raise errors.LocalRequiresBoundBranch()
504
617
        result.new_revid = self.target.last_revision()
505
618
        return result
506
619
 
507
 
    
 
620
 
508
621
class InterToGitBranch(branch.InterBranch):
509
622
    """InterBranch implementation that pulls from Git into bzr."""
510
623
 
 
624
    @staticmethod
 
625
    def _get_branch_formats_to_test():
 
626
        return None, None
 
627
 
511
628
    @classmethod
512
629
    def is_compatible(self, source, target):
513
 
        return (not isinstance(source, GitBranch) and 
 
630
        return (not isinstance(source, GitBranch) and
514
631
                isinstance(target, GitBranch))
515
632
 
516
633
    def update_revisions(self, *args, **kwargs):
517
634
        raise NoPushSupport()
518
635
 
519
 
    def push(self, overwrite=True, stop_revision=None, 
 
636
    def _get_new_refs(self, stop_revision=None):
 
637
        if stop_revision is None:
 
638
            stop_revision = self.source.last_revision()
 
639
        refs = { self.target.ref: stop_revision }
 
640
        for name, revid in self.source.tags.get_tag_dict().iteritems():
 
641
            if self.source.repository.has_revision(revid):
 
642
                refs[tag_name_to_ref(name)] = revid
 
643
        return refs
 
644
 
 
645
    def pull(self, overwrite=False, stop_revision=None, local=False,
 
646
             possible_transports=None):
 
647
        from dulwich.protocol import ZERO_SHA
 
648
        result = GitBranchPullResult()
 
649
        result.source_branch = self.source
 
650
        result.target_branch = self.target
 
651
        # FIXME: Check for diverged branches
 
652
        old_refs = self.target.repository._git.get_refs()
 
653
        refs = dict(old_refs)
 
654
        refs.update(self._get_new_refs(stop_revision))
 
655
        self.target.repository.fetch_refs(self.source.repository, refs)
 
656
        result.old_revid = self.target.lookup_foreign_revision_id(
 
657
            old_refs.get(self.target.ref, ZERO_SHA))
 
658
        result.new_revid = refs[self.target.ref]
 
659
        return result
 
660
 
 
661
    def push(self, overwrite=False, stop_revision=None,
520
662
             _override_hook_source_branch=None):
521
 
        raise NoPushSupport()
 
663
        from dulwich.protocol import ZERO_SHA
 
664
        result = GitBranchPushResult()
 
665
        result.source_branch = self.source
 
666
        result.target_branch = self.target
 
667
        # FIXME: Check for diverged branches
 
668
        old_refs = self.target.repository._git.get_refs()
 
669
        refs = dict(old_refs)
 
670
        refs.update(self._get_new_refs(stop_revision))
 
671
        self.target.repository.fetch_refs(self.source.repository, refs)
 
672
        result.old_revid = self.target.lookup_foreign_revision_id(
 
673
            old_refs.get(self.target.ref, ZERO_SHA))
 
674
        result.new_revid = refs[self.target.ref]
 
675
        return result
522
676
 
523
677
    def lossy_push(self, stop_revision=None):
 
678
        from dulwich.protocol import ZERO_SHA
524
679
        result = GitBranchPushResult()
525
680
        result.source_branch = self.source
526
681
        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
682
        # 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(
 
683
        refs = self._get_new_refs(stop_revision)
 
684
        result.revidmap, old_refs, new_refs = self.target.repository.dfetch_refs(
536
685
            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
 
686
        result.old_revid = self.target.lookup_foreign_revision_id(
 
687
            old_refs.get(self.target.ref, ZERO_SHA))
 
688
        result.new_revid = self.target.lookup_foreign_revision_id(
 
689
            new_refs[self.target.ref])
543
690
        return result
544
691
 
545
692