diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -688,7 +688,6 @@
     'DiffusionBranchListView' => 'applications/diffusion/view/DiffusionBranchListView.php',
     'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php',
     'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php',
-    'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php',
     'DiffusionBrowseController' => 'applications/diffusion/controller/DiffusionBrowseController.php',
     'DiffusionBrowseQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBrowseQueryConduitAPIMethod.php',
     'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php',
@@ -4408,6 +4407,7 @@
     'PhabricatorRepositoryOldRef' => 'applications/repository/storage/PhabricatorRepositoryOldRef.php',
     'PhabricatorRepositoryParsedChange' => 'applications/repository/data/PhabricatorRepositoryParsedChange.php',
     'PhabricatorRepositoryPermanentRefsTransaction' => 'applications/repository/xaction/PhabricatorRepositoryPermanentRefsTransaction.php',
+    'PhabricatorRepositoryPublisher' => 'applications/repository/query/PhabricatorRepositoryPublisher.php',
     'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php',
     'PhabricatorRepositoryPullEvent' => 'applications/repository/storage/PhabricatorRepositoryPullEvent.php',
     'PhabricatorRepositoryPullEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPullEventPHIDType.php',
@@ -6352,7 +6352,6 @@
     'DiffusionBranchListView' => 'DiffusionView',
     'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
     'DiffusionBranchTableController' => 'DiffusionController',
-    'DiffusionBranchTableView' => 'DiffusionView',
     'DiffusionBrowseController' => 'DiffusionController',
     'DiffusionBrowseQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
     'DiffusionBrowseResultSet' => 'Phobject',
@@ -10690,6 +10689,7 @@
     ),
     'PhabricatorRepositoryParsedChange' => 'Phobject',
     'PhabricatorRepositoryPermanentRefsTransaction' => 'PhabricatorRepositoryTransactionType',
+    'PhabricatorRepositoryPublisher' => 'Phobject',
     'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine',
     'PhabricatorRepositoryPullEvent' => array(
       'PhabricatorRepositoryDAO',
diff --git a/src/applications/audit/editor/PhabricatorAuditEditor.php b/src/applications/audit/editor/PhabricatorAuditEditor.php
--- a/src/applications/audit/editor/PhabricatorAuditEditor.php
+++ b/src/applications/audit/editor/PhabricatorAuditEditor.php
@@ -718,7 +718,8 @@
       switch ($xaction->getTransactionType()) {
         case PhabricatorAuditTransaction::TYPE_COMMIT:
           $repository = $object->getRepository();
-          if (!$repository->shouldPublishCommit($object)) {
+          $publisher = $repository->newPublisher();
+          if (!$publisher->shouldPublishCommit($object)) {
             return false;
           }
           return true;
@@ -779,7 +780,8 @@
     // TODO: They should, and then we should simplify this.
     $repository = $object->getRepository($assert_attached = false);
     if ($repository != PhabricatorLiskDAO::ATTACHABLE) {
-      if (!$repository->shouldPublishCommit($object)) {
+      $publisher = $repository->newPublisher();
+      if (!$publisher->shouldPublishCommit($object)) {
         return false;
       }
     }
diff --git a/src/applications/diffusion/controller/DiffusionCommitController.php b/src/applications/diffusion/controller/DiffusionCommitController.php
--- a/src/applications/diffusion/controller/DiffusionCommitController.php
+++ b/src/applications/diffusion/controller/DiffusionCommitController.php
@@ -243,7 +243,7 @@
       if (!$commit->isPermanentCommit()) {
         $nonpermanent_tag = id(new PHUITagView())
           ->setType(PHUITagView::TYPE_SHADE)
-          ->setName(pht('Not Permanent'))
+          ->setName(pht('Unpublished'))
           ->setColor(PHUITagView::COLOR_ORANGE);
 
         $header->addTag($nonpermanent_tag);
diff --git a/src/applications/diffusion/editor/DiffusionCommitEditEngine.php b/src/applications/diffusion/editor/DiffusionCommitEditEngine.php
--- a/src/applications/diffusion/editor/DiffusionCommitEditEngine.php
+++ b/src/applications/diffusion/editor/DiffusionCommitEditEngine.php
@@ -113,28 +113,14 @@
       ->setConduitTypeDescription(pht('New auditors.'))
       ->setValue($object->getAuditorPHIDsForEdit());
 
-    $reason = $data->getCommitDetail('autocloseReason', false);
-    if ($reason !== false) {
-      switch ($reason) {
-        case PhabricatorRepository::BECAUSE_REPOSITORY_IMPORTING:
-          $desc = pht('No, Repository Importing');
-          break;
-        case PhabricatorRepository::BECAUSE_AUTOCLOSE_DISABLED:
-          $desc = pht('No, Repository Publishing Disabled');
-          break;
-        case PhabricatorRepository::BECAUSE_NOT_ON_AUTOCLOSE_BRANCH:
-          $desc = pht('No, Not Reachable from Permanent Ref');
-          break;
-        // Old commits which were manually reparsed with "--force-autoclose"
-        // may have this constant. This flag is no longer supported.
-        case 'auto/forced':
-        case null:
-          $desc = pht('Yes');
-          break;
-        default:
-          $desc = pht('Unknown');
-          break;
+    $holds = $data->getPublisherHoldReasons();
+    if ($holds) {
+      $hold_names = array();
+      foreach ($holds as $hold) {
+        $hold_names[] = id(new PhabricatorRepositoryPublisher())
+          ->getHoldName($hold);
       }
+      $desc = implode('; ', $hold_names);
 
       $doc_href = PhabricatorEnv::getDoclink(
         'Diffusion User Guide: Permanent Refs');
@@ -147,7 +133,7 @@
         pht('Learn More'));
 
         $fields[] = id(new PhabricatorStaticEditField())
-          ->setLabel(pht('Published?'))
+          ->setLabel(pht('Unpublished'))
           ->setValue(array($desc, " \xC2\xB7 ", $doc_link));
     }
 
diff --git a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php
--- a/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php
+++ b/src/applications/diffusion/management/DiffusionRepositoryBranchesManagementPanel.php
@@ -129,10 +129,12 @@
       $branches = $pager->sliceResults($branches);
       $can_close_branches = ($repository->isHg());
 
+      $publisher = $repository->newPublisher();
+
       $rows = array();
       foreach ($branches as $branch) {
         $branch_name = $branch->getShortName();
-        $permanent = $repository->shouldAutocloseBranch($branch_name);
+        $permanent = $publisher->shouldPublishRef($branch);
 
         $default = $repository->getDefaultBranch();
         $icon = null;
diff --git a/src/applications/diffusion/view/DiffusionBranchTableView.php b/src/applications/diffusion/view/DiffusionBranchTableView.php
deleted file mode 100644
--- a/src/applications/diffusion/view/DiffusionBranchTableView.php
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-
-final class DiffusionBranchTableView extends DiffusionView {
-
-  private $branches;
-  private $commits = array();
-
-  public function setBranches(array $branches) {
-    assert_instances_of($branches, 'DiffusionRepositoryRef');
-    $this->branches = $branches;
-    return $this;
-  }
-
-  public function setCommits(array $commits) {
-    assert_instances_of($commits, 'PhabricatorRepositoryCommit');
-    $this->commits = mpull($commits, null, 'getCommitIdentifier');
-    return $this;
-  }
-
-  public function render() {
-    $drequest = $this->getDiffusionRequest();
-    $current_branch = $drequest->getBranch();
-    $repository = $drequest->getRepository();
-    $commits = $this->commits;
-    $viewer = $this->getUser();
-
-    $buildables = $this->loadBuildables($commits);
-    $have_builds = false;
-
-    $can_close_branches = ($repository->isHg());
-
-    Javelin::initBehavior('phabricator-tooltips');
-
-    $doc_href = PhabricatorEnv::getDoclink(
-      'Diffusion User Guide: Permanent Refs');
-
-    $rows = array();
-    $rowc = array();
-    foreach ($this->branches as $branch) {
-      $commit = idx($commits, $branch->getCommitIdentifier());
-      if ($commit) {
-        $details = $commit->getSummary();
-        $datetime = $viewer->formatShortDateTime($commit->getEpoch());
-        $buildable = idx($buildables, $commit->getPHID());
-        if ($buildable) {
-          $build_status = $this->renderBuildable($buildable);
-          $have_builds = true;
-        } else {
-          $build_status = null;
-        }
-      } else {
-        $datetime = null;
-        $details = null;
-        $build_status = null;
-      }
-
-      switch ($repository->shouldSkipAutocloseBranch($branch->getShortName())) {
-        case PhabricatorRepository::BECAUSE_REPOSITORY_IMPORTING:
-          $icon = 'fa-times bluegrey';
-          $tip = pht('Repository Importing');
-          break;
-        case PhabricatorRepository::BECAUSE_AUTOCLOSE_DISABLED:
-          $icon = 'fa-times bluegrey';
-          $tip = pht('Repository Publishing Disabled');
-          break;
-        case PhabricatorRepository::BECAUSE_BRANCH_UNTRACKED:
-          $icon = 'fa-times bluegrey';
-          $tip = pht('Branch Untracked');
-          break;
-        case PhabricatorRepository::BECAUSE_BRANCH_NOT_AUTOCLOSE:
-          $icon = 'fa-times bluegrey';
-          $tip = pht('Branch Not Permanent');
-          break;
-        case null:
-          $icon = 'fa-check bluegrey';
-          $tip = pht('Permanent Branch');
-          break;
-        default:
-          $icon = 'fa-question';
-          $tip = pht('Status Unknown');
-          break;
-      }
-
-      $status_icon = id(new PHUIIconView())
-        ->setIcon($icon)
-        ->addSigil('has-tooltip')
-        ->setHref($doc_href)
-        ->setMetadata(
-          array(
-            'tip' => $tip,
-            'size' => 200,
-          ));
-
-      $fields = $branch->getRawFields();
-      $closed = idx($fields, 'closed');
-      if ($closed) {
-        $status = pht('Closed');
-      } else {
-        $status = pht('Open');
-      }
-
-      $rows[] = array(
-        $this->linkBranchHistory($branch->getShortName()),
-        phutil_tag(
-          'a',
-          array(
-            'href' => $drequest->generateURI(
-              array(
-                'action' => 'browse',
-                'branch' => $branch->getShortName(),
-              )),
-          ),
-          $branch->getShortName()),
-        self::linkCommit(
-          $drequest->getRepository(),
-          $branch->getCommitIdentifier()),
-        $build_status,
-        $status,
-        AphrontTableView::renderSingleDisplayLine($details),
-        $status_icon,
-        $datetime,
-      );
-      if ($branch->getShortName() == $current_branch) {
-        $rowc[] = 'highlighted';
-      } else {
-        $rowc[] = null;
-      }
-    }
-
-    $view = new AphrontTableView($rows);
-    $view->setHeaders(
-      array(
-        null,
-        pht('Branch'),
-        pht('Head'),
-        null,
-        pht('State'),
-        pht('Details'),
-        null,
-        pht('Committed'),
-      ));
-    $view->setColumnClasses(
-      array(
-        '',
-        'pri',
-        '',
-        'icon',
-        '',
-        'wide',
-        '',
-        'right',
-      ));
-    $view->setColumnVisibility(
-      array(
-        true,
-        true,
-        true,
-        $have_builds,
-        $can_close_branches,
-      ));
-    $view->setRowClasses($rowc);
-    return $view->render();
-  }
-
-
-}
diff --git a/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php b/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php
--- a/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php
@@ -127,6 +127,7 @@
    */
   private function discoverGitCommits() {
     $repository = $this->getRepository();
+    $publisher = $repository->newPublisher();
 
     $heads = id(new DiffusionLowLevelGitRefQuery())
       ->setRepository($repository)
@@ -185,7 +186,7 @@
       $head_refs = $this->discoverStreamAncestry(
         new PhabricatorGitGraphStream($repository, $commit),
         $commit,
-        $repository->shouldAutocloseRef($ref));
+        $publisher->shouldPublishRef($ref));
 
       $this->didDiscoverRefs($head_refs);
 
@@ -514,11 +515,12 @@
    */
   private function sortRefs(array $refs) {
     $repository = $this->getRepository();
+    $publisher = $repository->newPublisher();
 
     $head_refs = array();
     $tail_refs = array();
     foreach ($refs as $ref) {
-      if ($repository->shouldAutocloseRef($ref)) {
+      if ($publisher->shouldPublishRef($ref)) {
         $head_refs[] = $ref;
       } else {
         $tail_refs[] = $ref;
diff --git a/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php b/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php
--- a/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php
+++ b/src/applications/repository/engine/PhabricatorRepositoryRefEngine.php
@@ -347,7 +347,7 @@
       return false;
     }
 
-    return $this->getRepository()->shouldAutocloseBranch($ref_name);
+    return $this->getRepository()->isBranchPermanentRef($ref_name);
   }
 
   /**
diff --git a/src/applications/repository/query/PhabricatorRepositoryPublisher.php b/src/applications/repository/query/PhabricatorRepositoryPublisher.php
new file mode 100644
--- /dev/null
+++ b/src/applications/repository/query/PhabricatorRepositoryPublisher.php
@@ -0,0 +1,120 @@
+<?php
+
+final class PhabricatorRepositoryPublisher
+  extends Phobject {
+
+  private $repository;
+
+  const HOLD_IMPORTING = 'auto/importing';
+  const HOLD_PUBLISHING_DISABLED = 'auto/disabled';
+  const HOLD_REF_NOT_BRANCH = 'not-branch';
+  const HOLD_NOT_REACHABLE_FROM_PERMANENT_REF = 'auto/nobranch';
+  const HOLD_UNTRACKED = 'auto/notrack';
+  const HOLD_NOT_PERMANENT_REF = 'auto/noclose';
+
+  public function setRepository(PhabricatorRepository $repository) {
+    $this->repository = $repository;
+    return $this;
+  }
+
+  public function getRepository() {
+    if (!$this->repository) {
+      throw new PhutilInvalidStateException('setRepository');
+    }
+    return $this->repository;
+  }
+
+/* -(  Publishing  )--------------------------------------------------------- */
+
+  public function shouldPublishRepository() {
+    return !$this->getRepositoryHoldReasons();
+  }
+
+  public function shouldPublishRef(DiffusionRepositoryRef $ref) {
+    return !$this->getRefHoldReasons($ref);
+  }
+
+  public function shouldPublishCommit(PhabricatorRepositoryCommit $commit) {
+    return !$this->getCommitHoldReasons($commit);
+  }
+
+/* -(  Hold Reasons  )------------------------------------------------------- */
+
+  public function getRepositoryHoldReasons() {
+    $repository = $this->getRepository();
+
+    $reasons = array();
+    if ($repository->isImporting()) {
+      $reasons[] = self::HOLD_IMPORTING;
+    }
+
+    if ($repository->isPublishingDisabled()) {
+      $reasons[] = self::HOLD_PUBLISHING_DISABLED;
+    }
+
+    return $reasons;
+  }
+
+  public function getRefHoldReasons(DiffusionRepositoryRef $ref) {
+    $repository = $this->getRepository();
+    $reasons = $this->getRepositoryHoldReasons();
+
+    if (!$ref->isBranch()) {
+      $reasons[] = self::HOLD_REF_NOT_BRANCH;
+    } else {
+      $branch_name = $ref->getShortName();
+
+      if (!$repository->shouldTrackBranch($branch_name)) {
+        $reasons[] = self::HOLD_UNTRACKED;
+      }
+
+      if (!$repository->isBranchPermanentRef($branch_name)) {
+        $reasons[] = self::HOLD_NOT_PERMANENT_REF;
+      }
+    }
+
+    return $reasons;
+  }
+
+  public function getCommitHoldReasons(PhabricatorRepositoryCommit $commit) {
+    $repository = $this->getRepository();
+    $reasons = $this->getRepositoryHoldReasons();
+
+    if ($repository->isGit()) {
+      if (!$commit->isPermanentCommit()) {
+        $reasons[] = self::HOLD_NOT_REACHABLE_FROM_PERMANENT_REF;
+      }
+    }
+
+    return $reasons;
+  }
+
+/* -(  Rendering  )---------------------------------------------------------- */
+
+  public function getHoldName($hold) {
+    $map = array(
+      self::HOLD_IMPORTING => array(
+        'name' => pht('Repository Importing'),
+      ),
+      self::HOLD_PUBLISHING_DISABLED => array(
+        'name' => pht('Repository Publishing Disabled'),
+      ),
+      self::HOLD_REF_NOT_BRANCH => array(
+        'name' => pht('Not a Branch'),
+      ),
+      self::HOLD_NOT_REACHABLE_FROM_PERMANENT_REF => array(
+        'name' => pht('Not Reachable from Permanent Ref'),
+      ),
+      self::HOLD_UNTRACKED => array(
+        'name' => pht('Untracked Ref'),
+      ),
+      self::HOLD_NOT_PERMANENT_REF => array(
+        'name' => pht('Not a Permanent Ref'),
+      ),
+    );
+
+    $spec = idx($map, $hold, array());
+    return idx($spec, 'name', pht('Unknown ("%s")', $hold));
+  }
+
+}
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
@@ -2,7 +2,7 @@
 
 /**
  * @task uri        Repository URI Management
- * @task autoclose  Autoclose
+ * @task publishing Publishing
  * @task sync       Cluster Synchronization
  */
 final class PhabricatorRepository extends PhabricatorRepositoryDAO
@@ -42,12 +42,6 @@
   const TABLE_PARENTS = 'repository_parents';
   const TABLE_COVERAGE = 'repository_coverage';
 
-  const BECAUSE_REPOSITORY_IMPORTING = 'auto/importing';
-  const BECAUSE_AUTOCLOSE_DISABLED = 'auto/disabled';
-  const BECAUSE_NOT_ON_AUTOCLOSE_BRANCH = 'auto/nobranch';
-  const BECAUSE_BRANCH_UNTRACKED = 'auto/notrack';
-  const BECAUSE_BRANCH_NOT_AUTOCLOSE = 'auto/noclose';
-
   const STATUS_ACTIVE = 'active';
   const STATUS_INACTIVE = 'inactive';
 
@@ -952,6 +946,10 @@
     return $this->isBranchInFilter($branch, 'branch-filter');
   }
 
+  public function isBranchPermanentRef($branch) {
+    return $this->isBranchInFilter($branch, 'close-commits-filter');
+  }
+
   public function formatCommitName($commit_identifier, $local = false) {
     $vcs = $this->getVersionControlSystem();
 
@@ -1036,166 +1034,17 @@
     return $ratio;
   }
 
-  /**
-   * Should this repository publish feed, notifications, audits, and email?
-   *
-   * We do not publish information about repositories during initial import,
-   * or if the repository has been set not to publish.
-   */
-  public function shouldPublish() {
-    if ($this->isImporting()) {
-      return false;
-    }
-
-    if ($this->isPublishingDisabled()) {
-      return false;
-    }
+/* -(  Publishing  )--------------------------------------------------------- */
 
-    return true;
+  public function newPublisher() {
+    return id(new PhabricatorRepositoryPublisher())
+      ->setRepository($this);
   }
 
   public function isPublishingDisabled() {
     return $this->getDetail('herald-disabled');
   }
 
-  public function shouldPublishCommit(PhabricatorRepositoryCommit $commit) {
-    if (!$this->shouldPublish()) {
-      return false;
-    }
-
-    if (!$commit->isPermanentCommit()) {
-      return false;
-    }
-
-    return true;
-  }
-
-
-/* -(  Autoclose  )---------------------------------------------------------- */
-
-
-  public function shouldAutocloseRef(DiffusionRepositoryRef $ref) {
-    if (!$ref->isBranch()) {
-      return false;
-    }
-
-    return $this->shouldAutocloseBranch($ref->getShortName());
-  }
-
-  /**
-   * Determine if autoclose is active for a branch.
-   *
-   * For more details about why, use @{method:shouldSkipAutocloseBranch}.
-   *
-   * @param string Branch name to check.
-   * @return bool True if autoclose is active for the branch.
-   * @task autoclose
-   */
-  public function shouldAutocloseBranch($branch) {
-    return ($this->shouldSkipAutocloseBranch($branch) === null);
-  }
-
-  /**
-   * Determine if autoclose is active for a commit.
-   *
-   * For more details about why, use @{method:shouldSkipAutocloseCommit}.
-   *
-   * @param PhabricatorRepositoryCommit Commit to check.
-   * @return bool True if autoclose is active for the commit.
-   * @task autoclose
-   */
-  public function shouldAutocloseCommit(PhabricatorRepositoryCommit $commit) {
-    return ($this->shouldSkipAutocloseCommit($commit) === null);
-  }
-
-
-  /**
-   * Determine why autoclose should be skipped for a branch.
-   *
-   * This method gives a detailed reason why autoclose will be skipped. To
-   * perform a simple test, use @{method:shouldAutocloseBranch}.
-   *
-   * @param string Branch name to check.
-   * @return const|null Constant identifying reason to skip this branch, or null
-   *   if autoclose is active.
-   * @task autoclose
-   */
-  public function shouldSkipAutocloseBranch($branch) {
-    $all_reason = $this->shouldSkipAllAutoclose();
-    if ($all_reason) {
-      return $all_reason;
-    }
-
-    if (!$this->shouldTrackBranch($branch)) {
-      return self::BECAUSE_BRANCH_UNTRACKED;
-    }
-
-    if (!$this->isBranchInFilter($branch, 'close-commits-filter')) {
-      return self::BECAUSE_BRANCH_NOT_AUTOCLOSE;
-    }
-
-    return null;
-  }
-
-
-  /**
-   * Determine why autoclose should be skipped for a commit.
-   *
-   * This method gives a detailed reason why autoclose will be skipped. To
-   * perform a simple test, use @{method:shouldAutocloseCommit}.
-   *
-   * @param PhabricatorRepositoryCommit Commit to check.
-   * @return const|null Constant identifying reason to skip this commit, or null
-   *   if autoclose is active.
-   * @task autoclose
-   */
-  public function shouldSkipAutocloseCommit(
-    PhabricatorRepositoryCommit $commit) {
-
-    $all_reason = $this->shouldSkipAllAutoclose();
-    if ($all_reason) {
-      return $all_reason;
-    }
-
-    switch ($this->getVersionControlSystem()) {
-      case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
-      case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
-        return null;
-      case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
-        break;
-      default:
-        throw new Exception(pht('Unrecognized version control system.'));
-    }
-
-    if (!$commit->isPermanentCommit()) {
-      return self::BECAUSE_NOT_ON_AUTOCLOSE_BRANCH;
-    }
-
-    return null;
-  }
-
-
-  /**
-   * Determine why all autoclose operations should be skipped for this
-   * repository.
-   *
-   * @return const|null Constant identifying reason to skip all autoclose
-   *   operations, or null if autoclose operations are not blocked at the
-   *   repository level.
-   * @task autoclose
-   */
-  private function shouldSkipAllAutoclose() {
-    if ($this->isImporting()) {
-      return self::BECAUSE_REPOSITORY_IMPORTING;
-    }
-
-    if ($this->isPublishingDisabled()) {
-      return self::BECAUSE_AUTOCLOSE_DISABLED;
-    }
-
-    return null;
-  }
-
   public function getPermanentRefRules() {
     return array_keys($this->getDetail('close-commits-filter', array()));
   }
diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommitData.php b/src/applications/repository/storage/PhabricatorRepositoryCommitData.php
--- a/src/applications/repository/storage/PhabricatorRepositoryCommitData.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryCommitData.php
@@ -68,4 +68,23 @@
       ->loadFromArray($dict);
   }
 
+  public function getPublisherHoldReasons() {
+    $holds = $this->getCommitDetail('holdReasons');
+
+    // Look for the legacy "autocloseReason" if we don't have a modern list
+    // of hold reasons.
+    if (!$holds) {
+      $old_hold = $this->getCommitDetail('autocloseReason');
+      if ($old_hold) {
+        $holds = array($old_hold);
+      }
+    }
+
+    if (!$holds) {
+      $holds = array();
+    }
+
+    return $holds;
+  }
+
 }
diff --git a/src/applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php b/src/applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php
--- a/src/applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php
+++ b/src/applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php
@@ -30,7 +30,8 @@
     PhabricatorRepositoryCommit $commit) {
     $viewer = PhabricatorUser::getOmnipotentUser();
 
-    if (!$repository->shouldPublishCommit($commit)) {
+    $publisher = $repository->newPublisher();
+    if (!$publisher->shouldPublishCommit($commit)) {
       return;
     }
 
diff --git a/src/applications/repository/worker/PhabricatorRepositoryPushMailWorker.php b/src/applications/repository/worker/PhabricatorRepositoryPushMailWorker.php
--- a/src/applications/repository/worker/PhabricatorRepositoryPushMailWorker.php
+++ b/src/applications/repository/worker/PhabricatorRepositoryPushMailWorker.php
@@ -22,7 +22,9 @@
       ->executeOne();
 
     $repository = $event->getRepository();
-    if (!$repository->shouldPublish()) {
+
+    $publisher = $repository->newPublisher();
+    if (!$publisher->shouldPublishRepository()) {
       // If the repository is still importing, don't send email.
       return;
     }
diff --git a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
--- a/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
+++ b/src/applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php
@@ -157,19 +157,18 @@
     $commit->setSummary($data->getSummary());
     $commit->save();
 
-    // Figure out if we're going to try to "autoclose" related objects (e.g.,
-    // close linked tasks and related revisions) and, if not, record why we
-    // aren't. Autoclose can be disabled for various reasons at the repository
-    // or commit levels.
+    // If we're publishing this commit, we're going to queue tasks to update
+    // referenced objects (like tasks and revisions). Otherwise, record some
+    // details about why we are not publishing it yet.
 
-    $autoclose_reason = $repository->shouldSkipAutocloseCommit($commit);
-    $data->setCommitDetail('autocloseReason', $autoclose_reason);
-    $should_autoclose = $repository->shouldAutocloseCommit($commit);
-
-    if ($should_autoclose) {
+    $publisher = $repository->newPublisher();
+    if ($publisher->shouldPublishCommit($commit)) {
       $actor = PhabricatorUser::getOmnipotentUser();
       $this->closeRevisions($actor, $ref, $commit, $data);
       $this->closeTasks($actor, $ref, $commit, $data);
+    } else {
+      $hold_reasons = $publisher->getCommitHoldReasons($commit);
+      $data->setCommitDetail('holdReasons', $hold_reasons);
     }
 
     $data->save();