diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php
@@ -43,17 +43,26 @@
     $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
 
     $v_default = $repository->getHumanReadableDetail('default-branch');
-    $v_track = $repository->getHumanReadableDetail(
+    $v_track = $repository->getDetail(
       'branch-filter',
       array());
-    $v_autoclose = $repository->getHumanReadableDetail(
+    $v_track = array_keys($v_track);
+    $v_autoclose = $repository->getDetail(
       'close-commits-filter',
       array());
+    $v_autoclose = array_keys($v_autoclose);
 
+    $e_track = null;
+    $e_autoclose = null;
+
+    $validation_exception = null;
     if ($request->isFormPost()) {
       $v_default = $request->getStr('default');
-      $v_track = $request->getStrList('track');
-      $v_autoclose = $request->getStrList('autoclose');
+
+      $v_track = $this->processBranches($request->getStr('track'));
+      if (!$is_hg) {
+        $v_autoclose = $this->processBranches($request->getStr('autoclose'));
+      }
 
       $xactions = array();
       $template = id(new PhabricatorRepositoryTransaction());
@@ -76,13 +85,20 @@
           ->setNewValue($v_autoclose);
       }
 
-      id(new PhabricatorRepositoryEditor())
+      $editor = id(new PhabricatorRepositoryEditor())
         ->setContinueOnNoEffect(true)
         ->setContentSourceFromRequest($request)
-        ->setActor($viewer)
-        ->applyTransactions($repository, $xactions);
+        ->setActor($viewer);
+
+      try {
+        $editor->applyTransactions($repository, $xactions);
+        return id(new AphrontRedirectResponse())->setURI($edit_uri);
+      } catch (PhabricatorApplicationTransactionValidationException $ex) {
+        $validation_exception = $ex;
 
-      return id(new AphrontRedirectResponse())->setURI($edit_uri);
+        $e_track = $validation_exception->getShortMessage($type_track);
+        $e_autoclose = $validation_exception->getShortMessage($type_autoclose);
+      }
     }
 
     $content = array();
@@ -97,44 +113,107 @@
       ->setObject($repository)
       ->execute();
 
+    $rows = array();
+    $rows[] = array(
+      array(
+        'master',
+      ),
+      pht('Select only master.'),
+    );
+    $rows[] = array(
+      array(
+        'master',
+        'develop',
+        'release',
+      ),
+      pht('Select master, develop, and release.'),
+    );
+    $rows[] = array(
+      array(
+        'master',
+        'regexp(/^release-/)',
+      ),
+      pht('Select master, and all branches which start with "release-".'),
+    );
+    $rows[] = array(
+      array(
+        'regexp(/^(?!temp-)/)',
+      ),
+      pht('Select all branches which do not start with "temp-".'),
+    );
+
+    foreach ($rows as $k => $row) {
+      $rows[$k][0] = phutil_tag(
+        'pre',
+        array(),
+        implode("\n", $row[0]));
+    }
+
+    $example_table = id(new AphrontTableView($rows))
+      ->setHeaders(
+        array(
+          pht('Example'),
+          pht('Effect'),
+        ))
+      ->setColumnClasses(
+        array(
+          '',
+          'wide',
+        ));
+
+    $v_track = implode("\n", $v_track);
+    $v_autoclose = implode("\n", $v_autoclose);
+
     $form = id(new AphrontFormView())
       ->setUser($viewer)
       ->appendRemarkupInstructions(
         pht(
-          'You can choose a **Default Branch** for viewing this repository.'.
-          "\n\n".
-          'If you want to import only some branches into Diffusion, you can '.
-          'list them in **Track Only**. Other branches will be ignored. If '.
-          'you do not specify any branches, all branches are tracked.'.
-          "\n\n".
-          'If you have **Autoclose** enabled, Phabricator can close tasks and '.
-          'revisions when corresponding commits are pushed to the repository. '.
-          'If you want to autoclose objects only when commits appear on '.
-          'specific branches, you can list those branches in **Autoclose '.
-          'Only**. By default, all branches autoclose objects.'))
+          'You can choose a **Default Branch** for viewing this repository.'))
       ->appendChild(
         id(new AphrontFormTextControl())
           ->setName('default')
           ->setLabel(pht('Default Branch'))
-          ->setValue($v_default)
-          ->setCaption(
-            pht('Example: %s', phutil_tag('tt', array(), 'develop'))))
+          ->setValue($v_default))
+      ->appendRemarkupInstructions(
+        pht(
+          'If you want to import only some branches into Diffusion, you can '.
+          'list them in **Track Only**. Other branches will be ignored. If '.
+          'you do not specify any branches, all branches are tracked.'));
+
+    if (!$is_hg) {
+      $form->appendRemarkupInstructions(
+        pht(
+          'If you have **Autoclose** enabled for this repository, Phabricator '.
+          'can close tasks and revisions when corresponding commits are '.
+          'pushed to the repository. If you want to autoclose objects only '.
+          'when commits appear on specific branches, you can list those '.
+          'branches in **Autoclose Only**. By default, all tracked branches '.
+          'will autoclose objects.'));
+    }
+
+    $form
+      ->appendRemarkupInstructions(
+        pht(
+          'When specifying branches, you should enter one branch name per '.
+          'line. You can use regular expressions to match branches by '.
+          'wrapping an expression in `regexp(...)`. For example:'))
       ->appendChild(
-        id(new AphrontFormTextControl())
+        id(new AphrontFormMarkupControl())
+          ->setValue($example_table))
+      ->appendChild(
+        id(new AphrontFormTextAreaControl())
           ->setName('track')
           ->setLabel(pht('Track Only'))
-          ->setValue($v_track)
-          ->setCaption(
-            pht('Example: %s', phutil_tag('tt', array(), 'master, develop'))));
+          ->setError($e_track)
+          ->setValue($v_track));
 
     if (!$is_hg) {
       $form->appendChild(
-        id(new AphrontFormTextControl())
+        id(new AphrontFormTextAreaControl())
           ->setName('autoclose')
           ->setLabel(pht('Autoclose Only'))
-          ->setValue($v_autoclose)
-          ->setCaption(
-            pht('Example: %s', phutil_tag('tt', array(), 'master, release'))));
+          ->setError($e_autoclose)
+          ->setValue($v_autoclose));
     }
 
     $form->appendChild(
@@ -143,6 +222,7 @@
         ->addCancelButton($edit_uri));
 
     $form_box = id(new PHUIObjectBoxView())
+      ->setValidationException($validation_exception)
       ->setHeaderText($title)
       ->setForm($form);
 
@@ -156,4 +236,16 @@
       ));
   }
 
+  private function processBranches($string) {
+    $lines = phutil_split_lines($string, $retain_endings = false);
+    foreach ($lines as $key => $line) {
+      $lines[$key] = trim($line);
+      if (!strlen($lines[$key])) {
+        unset($lines[$key]);
+      }
+    }
+
+    return array_values($lines);
+  }
+
 }
diff --git a/src/applications/repository/editor/PhabricatorRepositoryEditor.php b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
--- a/src/applications/repository/editor/PhabricatorRepositoryEditor.php
+++ b/src/applications/repository/editor/PhabricatorRepositoryEditor.php
@@ -325,6 +325,30 @@
     $errors = parent::validateTransaction($object, $type, $xactions);
 
     switch ($type) {
+      case PhabricatorRepositoryTransaction::TYPE_AUTOCLOSE:
+      case PhabricatorRepositoryTransaction::TYPE_TRACK_ONLY:
+        foreach ($xactions as $xaction) {
+          foreach ($xaction->getNewValue() as $pattern) {
+            $matches = null;
+            $regexp = PhabricatorRepository::extractBranchRegexp($pattern);
+            if ($regexp !== null) {
+              $ok = @preg_match($regexp, '');
+              if ($ok === false) {
+                $error = new PhabricatorApplicationTransactionValidationError(
+                  $type,
+                  pht('Invalid'),
+                  pht(
+                    'Expression "%s" is not a valid regular expression. Note '.
+                    'that you must include delimiters.',
+                    $regexp),
+                  $xaction);
+                $errors[] = $error;
+              }
+            }
+          }
+        }
+        break;
+
       case PhabricatorRepositoryTransaction::TYPE_REMOTE_URI:
         foreach ($xactions as $xaction) {
           $new_uri = $xaction->getNewValue();
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -577,16 +577,47 @@
     $is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
 
     $use_filter = ($is_git);
+    if (!$use_filter) {
+      // If this VCS doesn't use filters, pass everything through.
+      return true;
+    }
 
-    if ($use_filter) {
-      $filter = $this->getDetail($filter_key, array());
-      if ($filter && empty($filter[$branch])) {
-        return false;
+
+    $filter = $this->getDetail($filter_key, array());
+
+    // If there's no filter set, let everything through.
+    if (!$filter) {
+      return true;
+    }
+
+    // If this branch isn't literally named `regexp(...)`, and it's in the
+    // filter list, let it through.
+    if (isset($filter[$branch])) {
+      if (self::extractBranchRegexp($branch) === null) {
+        return true;
       }
     }
 
-    // By default, all branches pass.
-    return true;
+    // If the branch matches a regexp, let it through.
+    foreach ($filter as $pattern => $ignored) {
+      $regexp = self::extractBranchRegexp($pattern);
+      if ($regexp !== null) {
+        if (preg_match($regexp, $branch)) {
+          return true;
+        }
+      }
+    }
+
+    // Nothing matched, so filter this branch out.
+    return false;
+  }
+
+  public static function extractBranchRegexp($pattern) {
+    $matches = null;
+    if (preg_match('/^regexp\\((.*)\\)\z/', $pattern, $matches)) {
+      return $matches[1];
+    }
+    return null;
   }
 
   public function shouldTrackBranch($branch) {