private function markReachable(PhabricatorRepository $repository)
 {
     if (!$repository->isGit()) {
         throw new PhutilArgumentUsageException(pht('Only Git repositories are supported, this repository ("%s") is ' . 'not a Git repository.', $repository->getDisplayName()));
     }
     $viewer = $this->getViewer();
     $commits = id(new DiffusionCommitQuery())->setViewer($viewer)->withRepository($repository)->execute();
     $flag = PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE;
     $graph = new PhabricatorGitGraphStream($repository);
     foreach ($commits as $commit) {
         $identifier = $commit->getCommitIdentifier();
         try {
             $graph->getCommitDate($identifier);
             $unreachable = false;
         } catch (Exception $ex) {
             $unreachable = true;
         }
         // The commit has proper reachability, so do nothing.
         if ($commit->isUnreachable() === $unreachable) {
             $this->untouchedCount++;
             continue;
         }
         if ($unreachable) {
             echo tsprintf("%s: %s\n", $commit->getMonogram(), pht('Marking commit unreachable.'));
             $commit->writeImportStatusFlag($flag);
         } else {
             echo tsprintf("%s: %s\n", $commit->getMonogram(), pht('Marking commit reachable.'));
             $commit->clearImportStatusFlag($flag);
         }
     }
 }
 private function markUnreachableFrom(PhabricatorRepository $repository, PhabricatorGitGraphStream $stream, $identifier)
 {
     $unreachable = array();
     $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere('repositoryID = %s AND commitIdentifier = %s', $repository->getID(), $identifier);
     if (!$commit) {
         return;
     }
     $look = array($commit);
     $seen = array();
     while ($look) {
         $target = array_pop($look);
         // If we've already checked this commit (for example, because history
         // branches and then merges) we don't need to check it again.
         $target_identifier = $target->getCommitIdentifier();
         if (isset($seen[$target_identifier])) {
             continue;
         }
         $seen[$target_identifier] = true;
         try {
             $stream->getCommitDate($target_identifier);
             $reachable = true;
         } catch (Exception $ex) {
             $reachable = false;
         }
         if ($reachable) {
             // This commit is reachable, so we don't need to go any further
             // down this road.
             continue;
         }
         $unreachable[] = $target;
         // Find the commit's parents and check them for reachability, too. We
         // have to look in the database since we no may longer have the commit
         // in the repository.
         $rows = queryfx_all($commit->establishConnection('w'), 'SELECT commit.* FROM %T commit
       JOIN %T parents ON commit.id = parents.parentCommitID
       WHERE parents.childCommitID = %d', $commit->getTableName(), PhabricatorRepository::TABLE_PARENTS, $target->getID());
         if (!$rows) {
             continue;
         }
         $parents = id(new PhabricatorRepositoryCommit())->loadAllFromArray($rows);
         foreach ($parents as $parent) {
             $look[] = $parent;
         }
     }
     $unreachable = array_reverse($unreachable);
     $flag = PhabricatorRepositoryCommit::IMPORTED_UNREACHABLE;
     foreach ($unreachable as $unreachable_commit) {
         $unreachable_commit->writeImportStatusFlag($flag);
     }
     // If anything was unreachable, just rebuild the whole summary table.
     // We can't really update it incrementally when a commit becomes
     // unreachable.
     if ($unreachable) {
         $this->rebuildSummaryTable($repository);
     }
 }
 /**
  * @task git
  */
 private function executeGitDiscoverCommit(PhabricatorRepository $repository, $commit, $branch, $autoclose)
 {
     $discover = array($commit);
     $insert = array($commit);
     $seen_parent = array();
     $stream = new PhabricatorGitGraphStream($repository, $commit);
     while (true) {
         $target = array_pop($discover);
         $parents = $stream->getParents($target);
         foreach ($parents as $parent) {
             if (isset($seen_parent[$parent])) {
                 // We end up in a loop here somehow when we parse Arcanist if we
                 // don't do this. TODO: Figure out why and draw a pretty diagram
                 // since it's not evident how parsing a DAG with this causes the
                 // loop to stop terminating.
                 continue;
             }
             $seen_parent[$parent] = true;
             if ($autoclose) {
                 $known = $this->isKnownCommitOnAnyAutocloseBranch($repository, $parent);
             } else {
                 $known = $this->isKnownCommit($repository, $parent);
             }
             if (!$known) {
                 $this->log("Discovered commit '{$parent}'.");
                 $discover[] = $parent;
                 $insert[] = $parent;
             }
         }
         if (empty($discover)) {
             break;
         }
     }
     $n = count($insert);
     if ($autoclose) {
         $this->log("Found {$n} new autoclose commits on branch '{$branch}'.");
     } else {
         $this->log("Found {$n} new commits on branch '{$branch}'.");
     }
     while (true) {
         $target = array_pop($insert);
         $epoch = $stream->getCommitDate($target);
         $epoch = trim($epoch);
         if ($autoclose) {
             $this->updateCommit($repository, $target, $branch);
         } else {
             $this->recordCommit($repository, $target, $epoch, $branch);
         }
         if (empty($insert)) {
             break;
         }
     }
 }