diff --git a/reviewboard/scmtools/svn/pysvn.py b/reviewboard/scmtools/svn/pysvn.py
index 9ca4226fe4e35f1e1a455ab8ec066e0b7b7dc342..9f024ceb48a21d4eea9b5142131e6359898dcc94 100644
--- a/reviewboard/scmtools/svn/pysvn.py
+++ b/reviewboard/scmtools/svn/pysvn.py
@@ -211,8 +211,8 @@ class Client(base.Client):
         commits = self.client.log(
             self.normalize_path(path),
             limit=limit,
-            revision_start=Revision(opt_revision_kind.number, start),
-            revision_end=Revision(opt_revision_kind.number, end),
+            revision_start=self._normalize_revision(start),
+            revision_end=self._normalize_revision(end),
             discover_changed_paths=discover_changed_paths,
             strict_node_history=limit_to_path)
 
diff --git a/reviewboard/static/rb/js/newReviewRequest/views/postCommitView.js b/reviewboard/static/rb/js/newReviewRequest/views/postCommitView.js
index 22869c2a37c57b8de3482aec7ef3dbb7e850cf14..97bbb9c73a04a17d6c3e4073f704d2e4fd365e9c 100644
--- a/reviewboard/static/rb/js/newReviewRequest/views/postCommitView.js
+++ b/reviewboard/static/rb/js/newReviewRequest/views/postCommitView.js
@@ -70,7 +70,9 @@ RB.PostCommitView = Backbone.View.extend({
         }
 
         this._commitsCollection =
-            this.model.get('repository').getCommits(branch.get('commit'));
+            this.model.get('repository').getCommits({
+                branch: branch.id
+            });
         this._commitsCollection.fetch();
         this.listenTo(this._commitsCollection, 'create', this._onCreateReviewRequest);
 
diff --git a/reviewboard/static/rb/js/newReviewRequest/views/tests/postCommitViewTests.js b/reviewboard/static/rb/js/newReviewRequest/views/tests/postCommitViewTests.js
index d2ec03b45693f383d8fde1cd57c36cf843ec3567..d66a0032ee3218076bfcaf542acf42d9e355e10b 100644
--- a/reviewboard/static/rb/js/newReviewRequest/views/tests/postCommitViewTests.js
+++ b/reviewboard/static/rb/js/newReviewRequest/views/tests/postCommitViewTests.js
@@ -35,10 +35,11 @@ suite('rb/newReviewRequest/views/PostCommitView', function() {
             }
         );
 
-        spyOn(repository, 'getCommits').andCallFake(function(start) {
+        spyOn(repository, 'getCommits').andCallFake(function(options) {
             commits = new RB.RepositoryCommits([], {
                 urlBase: _.result(this, 'url') + 'commits/',
-                start: start
+                start: options.start,
+                branch: options.branch
             });
 
             spyOn(commits, 'sync').andCallFake(
diff --git a/reviewboard/static/rb/js/resources/collections/repositoryCommitsCollection.js b/reviewboard/static/rb/js/resources/collections/repositoryCommitsCollection.js
index bdad1e69d636a358748aa145111cba73f6c5e733..1eaac5ec67ae40535da0e419ec2904f6b72d7b1f 100644
--- a/reviewboard/static/rb/js/resources/collections/repositoryCommitsCollection.js
+++ b/reviewboard/static/rb/js/resources/collections/repositoryCommitsCollection.js
@@ -29,7 +29,17 @@ RB.RepositoryCommits = RB.BaseCollection.extend({
      * Get the URL to fetch for the next page of results.
      */
     url: function() {
-        return this.options.urlBase + '?start=' + this.options.start;
+        var args = [];
+
+        if (this.options.start !== undefined) {
+            args.push('start=' + encodeURIComponent(this.options.start));
+        }
+
+        if (this.options.branch !== undefined) {
+            args.push('branch=' + encodeURIComponent(this.options.branch));
+        }
+
+        return this.options.urlBase + '?' + args.join('&');
     },
 
     /*
diff --git a/reviewboard/static/rb/js/resources/models/repositoryBranchModel.js b/reviewboard/static/rb/js/resources/models/repositoryBranchModel.js
index 097ea1657f179cbf7c77e5f3fe18910681bdc84e..155893c0f72dd03a4d69f4d1c9467eca216f8fbe 100644
--- a/reviewboard/static/rb/js/resources/models/repositoryBranchModel.js
+++ b/reviewboard/static/rb/js/resources/models/repositoryBranchModel.js
@@ -13,6 +13,7 @@ RB.RepositoryBranch = Backbone.Model.extend({
      */
     parse: function(response) {
         return {
+            id: response.id,
             name: response.name,
             commit: response.commit,
             isDefault: response['default']
diff --git a/reviewboard/static/rb/js/resources/models/repositoryModel.js b/reviewboard/static/rb/js/resources/models/repositoryModel.js
index f725173038faaebe4f7e27f7818ffbc3e7b16358..6c692826d16ca1406af6bf383945afec38149176 100644
--- a/reviewboard/static/rb/js/resources/models/repositoryModel.js
+++ b/reviewboard/static/rb/js/resources/models/repositoryModel.js
@@ -26,11 +26,18 @@ RB.Repository = RB.BaseResource.extend({
 
     /*
      * Get a collection of commits from a given starting point.
+     *
+     * 'options' may have the following set:
+     *
+     *     * 'start'  - The starting commit (this will be the most recent
+     *                  commit shown).
+     *     * 'branch' - The branch to fetch commits from.
      */
-    getCommits: function(startCommit) {
+    getCommits: function(options) {
         return new RB.RepositoryCommits([], {
             urlBase: _.result(this, 'url') + 'commits/',
-            start: startCommit
+            start: options.start,
+            branch: options.branch
         });
     },
 
diff --git a/reviewboard/webapi/resources/repository_branches.py b/reviewboard/webapi/resources/repository_branches.py
index e55b4d7f7ce35f51687209583199cb006d3f29e0..9545a7b42b3998d5ca43ae41f514da7746a2fa51 100644
--- a/reviewboard/webapi/resources/repository_branches.py
+++ b/reviewboard/webapi/resources/repository_branches.py
@@ -16,6 +16,8 @@ class RepositoryBranchesResource(WebAPIResource):
 
     Returns an array of objects with the following fields:
 
+        'id' is the ID of the branch.
+
         'name' is simply the name of the branch.
 
         'commit' is a string representing the revision identifier of the
@@ -50,6 +52,7 @@ class RepositoryBranchesResource(WebAPIResource):
             branches = []
             for branch in repository.get_branches():
                 branches.append({
+                    'id': branch.id,
                     'name': branch.name,
                     'commit': branch.commit,
                     'default': branch.default,
diff --git a/reviewboard/webapi/resources/repository_commits.py b/reviewboard/webapi/resources/repository_commits.py
index e7cfa6f31cf3b2f5e2c6eb8c0205cdff755f39af..ba657111b7e5d50b873594be076127c63d35da93 100644
--- a/reviewboard/webapi/resources/repository_commits.py
+++ b/reviewboard/webapi/resources/repository_commits.py
@@ -53,13 +53,20 @@ class RepositoryCommitsResource(WebAPIResource):
     @webapi_check_login_required
     @webapi_response_errors(DOES_NOT_EXIST, REPO_NOT_IMPLEMENTED)
     @webapi_request_fields(
-        required={
+        optional={
+            'branch': {
+                'type': six.text_type,
+                "description": "The ID of the branch to limit the commits "
+                               "to, as provided by the 'id' field of the "
+                               "repository branches API.",
+            },
             'start': {
                 'type': six.text_type,
                 'description': 'A commit ID to start listing from.',
             },
-        })
-    def get(self, request, start=None, *args, **kwargs):
+        }
+    )
+    def get(self, request, branch=None, start=None, *args, **kwargs):
         """Retrieves a set of commits from a particular repository.
 
         The ``start`` parameter is a commit ID to use as a starting point. This
@@ -74,7 +81,7 @@ class RepositoryCommitsResource(WebAPIResource):
             return DOES_NOT_EXIST
 
         try:
-            items = repository.get_commits(start=start)
+            items = repository.get_commits(branch=branch, start=start)
         except NotImplementedError:
             return REPO_NOT_IMPLEMENTED
 
