diff --git a/reviewboard/scmtools/svn/__init__.py b/reviewboard/scmtools/svn/__init__.py
index 60c55df28ffda51f8806206398d26af03c51fbde..98ea6d51230fbc894ef1e5048e6ff9f458623674 100644
--- a/reviewboard/scmtools/svn/__init__.py
+++ b/reviewboard/scmtools/svn/__init__.py
@@ -12,8 +12,8 @@ from django.utils.translation import ugettext as _
 
 from reviewboard.diffviewer.parser import DiffParser
 from reviewboard.scmtools.certs import Certificate
-from reviewboard.scmtools.core import (Commit, SCMTool, HEAD, PRE_CREATION,
-                                       UNKNOWN)
+from reviewboard.scmtools.core import (Branch, Commit, SCMTool, HEAD,
+                                       PRE_CREATION, UNKNOWN)
 from reviewboard.scmtools.errors import (AuthenticationError,
                                          RepositoryNotFoundError,
                                          SCMError,
@@ -122,8 +122,45 @@ class SVNTool(SCMTool):
     def get_branches(self):
         """Returns a list of branches.
 
-        This assumes the standard layout in the repository."""
-        return self.client.branches
+        This assumes the standard layout in the repository.
+        """
+        results = []
+
+        try:
+            root_dirents = self.client.list_dir('/')
+        except Exception as e:
+            raise SCMError(e)
+
+        if 'trunk' in root_dirents:
+            # Looks like the standard layout. Adds trunk and any branches.
+            results.append(Branch(name='trunk',
+                                  commit=root_dirents['trunk']['created_rev'],
+                                  default=True))
+
+            if 'branches' in root_dirents:
+                try:
+                    dirents = self.client.list_dir('branches')
+
+                    results += [
+                        Branch(name=name, commit=dirents[name]['created_rev'])
+                        for name in sorted(six.iterkeys(dirents))
+                    ]
+                except Exception as e:
+                    raise SCMError(e)
+        else:
+            # If the repository doesn't use the standard layout, just use a
+            # listing of the root directory as the "branches". This probably
+            # corresponds to a list of projects instead of branches, but it
+            # will at least give people a useful result.
+            default = True
+
+            for name in sorted(six.iterkeys(root_dirents)):
+                results.append(Branch(name=name,
+                                      commit=dirents[name]['created_rev'],
+                                      default=default))
+                default = False
+
+        return results
 
     def get_commits(self, start):
         """Return a list of commits."""
diff --git a/reviewboard/scmtools/svn/base.py b/reviewboard/scmtools/svn/base.py
index 00ee20a07979c8248e0fc9afdea3bfb59796f316..ca54bc5e864329e1639aa2ff1d1992927a486478 100644
--- a/reviewboard/scmtools/svn/base.py
+++ b/reviewboard/scmtools/svn/base.py
@@ -80,6 +80,18 @@ class Client(object):
         """
         raise NotImplementedError
 
+    def list_dir(self, path):
+        """Lists the contents of the specified path.
+
+        The result will be an ordered dictionary of contents, mapping
+        filenames or directory names with a dictionary containing:
+
+        * ``path``        - The full path of the file or directory.
+        * ``created_rev`` - The revision where the file or directory was
+                            created.
+        """
+        raise NotImplementedError
+
     def collapse_keywords(self, data, keyword_str):
         """
         Collapse SVN keywords in string.
diff --git a/reviewboard/scmtools/svn/pysvn.py b/reviewboard/scmtools/svn/pysvn.py
index ccaedf3a0de03572dfdffb59e9cbe54be42faa47..cd01fdb041865ba0932dfd7e6fc1a9335acc4b25 100644
--- a/reviewboard/scmtools/svn/pysvn.py
+++ b/reviewboard/scmtools/svn/pysvn.py
@@ -9,8 +9,7 @@ from tempfile import mkdtemp
 
 try:
     import pysvn
-    from pysvn import (ClientError, Revision, opt_revision_kind,
-                       SVN_DIRENT_CREATED_REV)
+    from pysvn import ClientError, Revision, opt_revision_kind
     has_svn_backend = True
 except ImportError:
     # This try-except block is here for the sole purpose of avoiding
@@ -24,8 +23,7 @@ from django.utils.datastructures import SortedDict
 from django.utils.six.moves.urllib.parse import (urlsplit, urlunsplit, quote)
 from django.utils.translation import ugettext as _
 
-from reviewboard.scmtools.core import (Branch, Commit,
-                                       HEAD, PRE_CREATION)
+from reviewboard.scmtools.core import Commit, HEAD, PRE_CREATION
 from reviewboard.scmtools.errors import (AuthenticationError,
                                          FileNotFoundError,
                                          SCMError)
@@ -91,56 +89,6 @@ class Client(base.Client):
             else:
                 raise SCMError(e)
 
-    @property
-    def branches(self):
-        """Returns a list of branches.
-
-        This assumes the standard layout in the repository."""
-        results = []
-
-        try:
-            root_dirents = self.client.list(
-                self.normalize_path('/'),
-                dirent_fields=SVN_DIRENT_CREATED_REV,
-                recurse=False)[1:]
-        except ClientError as e:
-            raise SCMError(e)
-
-        root_entries = SortedDict()
-        for dirent, unused in root_dirents:
-            name = dirent['path'].split('/')[-1]
-            rev = six.text_type(dirent['created_rev'].number)
-            root_entries[name] = rev
-
-        if 'trunk' in root_entries:
-            # Looks like the standard layout. Adds trunks and any branches
-            results.append(
-                Branch('trunk', root_entries['trunk'], True))
-
-            try:
-                branches = self.client.list(
-                    self.normalize_path('branches'),
-                    dirent_fields=SVN_DIRENT_CREATED_REV)[1:]
-                for branch, unused in branches:
-                    results.append(Branch(
-                        branch['path'].split('/')[-1],
-                        six.text_type(branch['created_rev'].number)))
-            except ClientError:
-                # It's possible there aren't any branches. Ignore errors for
-                # this part.
-                pass
-        else:
-            # If the repository doesn't use the standard layout, just use a
-            # listing of the root directory as the "branches". This probably
-            # corresponds to a list of projects instead of branches, but it
-            # will at least give people a useful result.
-            default = True
-            for name, rev in six.iteritems(root_entries):
-                results.append(Branch(name, rev, default))
-                default = False
-
-        return results
-
     def get_change(self, revision, cache_key):
         """Get an individual change.
 
@@ -324,3 +272,27 @@ class Client(base.Client):
                 commit['date'] = datetime.utcfromtimestamp(commit['date'])
 
         return commits
+
+    def list_dir(self, path):
+        """Lists the contents of the specified path.
+
+        The result will be an ordered dictionary of contents, mapping
+        filenames or directory names with a dictionary containing:
+
+        * ``path``        - The full path of the file or directory.
+        * ``created_rev`` - The revision where the file or directory was
+                            created.
+        """
+        result = SortedDict()
+        dirents = self.client.list(self.normalize_path(path),
+                                   recurse=False)[1:]
+
+        for dirent, unused in dirents:
+            name = dirent['path'].split('/')[-1]
+
+            result[name] = {
+                'path': dirent['path'],
+                'created_rev': six.text_type(dirent['created_rev'].number),
+            }
+
+        return result
diff --git a/reviewboard/scmtools/svn/subvertpy.py b/reviewboard/scmtools/svn/subvertpy.py
index 8fc0a9f619108e98c6a019f634b0be335c70dade..662d88eae6c9a9ab6beb1ea50754d5add6cbca0d 100644
--- a/reviewboard/scmtools/svn/subvertpy.py
+++ b/reviewboard/scmtools/svn/subvertpy.py
@@ -7,7 +7,7 @@ from datetime import datetime
 
 try:
     from subvertpy import ra, SubversionException, __version__
-    from subvertpy.client import Client as SVNClient, get_config
+    from subvertpy.client import Client as SVNClient, api_version, get_config
 
     has_svn_backend = (__version__ >= (0, 9, 1))
 except ImportError:
@@ -18,11 +18,10 @@ except ImportError:
 
 from django.core.cache import cache
 from django.utils import six
+from django.utils.datastructures import SortedDict
 
-from reviewboard.scmtools.core import (Branch, Commit, Revision,
-                                       HEAD, PRE_CREATION)
-from reviewboard.scmtools.errors import (FileNotFoundError,
-                                         SCMError)
+from reviewboard.scmtools.core import Commit, Revision, HEAD, PRE_CREATION
+from reviewboard.scmtools.errors import FileNotFoundError, SCMError
 from reviewboard.scmtools.svn import base
 
 B = six.binary_type
@@ -79,54 +78,6 @@ class Client(base.Client):
             self._ra = ra.RemoteAccess(self.repopath, auth=self.auth)
         return self._ra
 
-    @property
-    def branches(self):
-        """Returns a list of branches.
-
-        This assumes the standard layout in the repository."""
-        results = []
-        try:
-            root_dirents = \
-                self.ra.get_dir(B('.'), -1, ra.DIRENT_CREATED_REV)[0]
-        except SubversionException as e:
-            raise SCMError(e)
-
-        trunk = B('trunk')
-        if trunk in root_dirents:
-            # Looks like the standard layout. Adds trunk and any branches.
-            created_rev = root_dirents[trunk]['created_rev']
-            results.append(Branch('trunk', six.text_type(created_rev), True))
-
-            try:
-                dirents = self.ra.get_dir(B('branches'), -1,
-                                          ra.DIRENT_CREATED_REV)[0]
-
-                branches = {}
-                for name, dirent in six.iteritems(dirents):
-                    branches[six.text_type(name)] = six.text_type(
-                        dirent['created_rev'])
-
-                for name in sorted(six.iterkeys(branches)):
-                    results.append(Branch(name, branches[name]))
-            except SubversionException as e:
-                pass
-        else:
-            # If the repository doesn't use the standard layout, just use a
-            # listing of the root directory as the "branches". This probably
-            # corresponds to a list of projects instead of branches, but it
-            # will at least give people a useful result.
-            branches = {}
-            for name, dirent in six.iteritems(root_dirents):
-                branches[six.text_type(name)] = six.text_type(
-                    dirent['created_rev'])
-
-            default = True
-            for name in sorted(six.iterkeys(branches)):
-                results.append(Branch(name, branches[name], default))
-                default = False
-
-        return results
-
     def get_change(self, revision, cache_key):
         """Get an individual change.
 
@@ -359,3 +310,31 @@ class Client(base.Client):
                         strict_node_history=limit_to_path)
 
         return commits
+
+    def list_dir(self, path):
+        """Lists the contents of the specified path.
+
+        The result will be an ordered dictionary of contents, mapping
+        filenames or directory names with a dictionary containing:
+
+        * ``path``        - The full path of the file or directory.
+        * ``created_rev`` - The revision where the file or directory was
+                            created.
+        """
+        result = SortedDict()
+
+        if api_version()[:2] >= (1, 5):
+            depth = 2  # Immediate files in this path. Only in 1.5+.
+        else:
+            depth = 0  # This will trigger recurse=False for SVN < 1.5.
+
+        dirents = self.client.list(B(self.normalize_path(path)), None, depth)
+
+        for name, dirent in six.iteritems(dirents):
+            if name:
+                result[six.text_type(name)] = {
+                    'path': '%s/%s' % (path.strip('/'), name),
+                    'created_rev': six.text_type(dirent['created_rev']),
+                }
+
+        return result
