*** modified file 'bzrlib/branch.py'
--- bzrlib/branch.py
+++ bzrlib/branch.py
@@ -16,7 +16,7 @@


 import sys, os, os.path, random, time, sha, sets, types, re, shutil, tempfile
-import traceback, socket, fnmatch, difflib, time
+import traceback, socket, fnmatch, difflib, time, weakref
 from binascii import hexlify

 import bzrlib
@@ -82,7 +82,7 @@
 ######################################################################
 # branch objects

-class Branch(object):
+class _Branch(object):
     """Branch holding a history of revisions.

     base
@@ -132,6 +132,7 @@
     __repr__ = __str__

     def __del__(self):
+        mutter('Deconstructing the branch at %r' % self.base)
         self.unlock()


@@ -141,6 +142,9 @@
         if self._lockfile:
             if self._lockmode == mode:
                 return
+            if self._lockmode == 'w' and mode=='r':
+                return # Don't downgrade the current lock mode
+
             # On some platforms (*cough* win32 *cough*), upgrading a lock requires unlocking it first
             if sys.platform in ('win32', 'cygwin'):
                 self.unlock()
@@ -714,10 +718,61 @@
         self._write_inventory(inv)


-
-
-class ScratchBranch(Branch):
+class Branch(object):
+    """This is the wrapper around the Branch() object which ensures they are singletons."""
+    _branches = weakref.WeakValueDictionary()
+    _locked_branch = None
+
+    def __init__(self, base, init=False, find_root=True, lock_mode='w'):
+        if not init and find_root:
+            self.__dict__['base'] = find_branch_root(base)
+        else:
+            self.__dict__['base'] = os.path.realpath(base)
+
+        self.__dict__['_init'] = init
+        self.__dict__['_find_root'] = find_root
+        self.__dict__['_lock_mode'] = lock_mode
+        self._get_branch()
+
+    def _get_branch(self):
+        """Look in the weakref dictionary to see if the Branch already exists, otherwise create a new one."""
+
+        if Branch._branches.has_key(self.base):
+            mutter('Branch %r already open' % (self.base))
+            self.__dict__['_locked_branch'] = Branch._branches[self.base]
+            # This is a no-op if we are already locked at the correct level
+            self.__dict__['_locked_branch'].lock(self._lock_mode)
+        else:
+            mutter('Branch %r opened' % (self.base))
+            self._locked_branch = _Branch(self.base, init=self._init,
+                    find_root=self._find_root, lock_mode=self._lock_mode)
+            Branch._branches[self.base] = self._locked_branch
+
+    def __getattr__(self, name):
+        if self.__dict__.has_key(name):
+            return self.__dict__[name]
+        if self.__dict__.has_key('_locked_branch'):
+            if not self.__dict__['_locked_branch']:
+                self.__dict__['_get_branch']()
+            return getattr(self.__dict__['_locked_branch'], name)
+
+    def __setattr__(self, name, value):
+        if name == '_locked_branch':
+            self.__dict__['_locked_branch'] = value
+        return setattr(self.__dict__['_locked_branch'], name, value)
+
+    def unlock(self):
+        """The branch will unlock itself when it is no longer needed by anyone, this just releases this
+        wrappers hold on the locked branch.
+        """
+        self._locked_branch = None
+
+
+class ScratchBranch(_Branch):
     """Special test class: a branch that cleans up after itself.
+
+    This is not contained inside the Branch wrapper, since by definition a scratch branch
+    is not shared. (at least I hope so)

     >>> b = ScratchBranch()
     >>> isdir(b.base)
@@ -734,7 +789,7 @@

         If any files are listed, they are created in the working copy.
         """
-        Branch.__init__(self, tempfile.mkdtemp(), init=True)
+        super(ScratchBranch, self).__init__(tempfile.mkdtemp(), init=True)
         for d in dirs:
             os.mkdir(self.abspath(d))


