Index: src/applications/diffusion/conduit/ConduitAPI_diffusion_branchquery_Method.php =================================================================== --- src/applications/diffusion/conduit/ConduitAPI_diffusion_branchquery_Method.php +++ src/applications/diffusion/conduit/ConduitAPI_diffusion_branchquery_Method.php @@ -30,14 +30,22 @@ // We need to add 1 in case we pick up HEAD. $count = $offset + $limit + 1; - list($stdout) = $repository->execxLocalCommand( - 'for-each-ref %C --sort=-creatordate --format=%s refs/remotes', - $count ? '--count='.(int)$count : null, - '%(refname:short) %(objectname)'); - - $branch_list = DiffusionGitBranch::parseRemoteBranchOutput( - $stdout, - $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + if ($repository->isWorkingCopyBare()) { + list($stdout) = $repository->execxLocalCommand( + 'for-each-ref %C --sort=-creatordate --format=%s refs/heads', + $count ? '--count='.(int)$count : null, + '%(refname:short) %(objectname)'); + $branch_list = DiffusionGitBranch::parseLocalBranchOutput( + $stdout); + } else { + list($stdout) = $repository->execxLocalCommand( + 'for-each-ref %C --sort=-creatordate --format=%s refs/remotes', + $count ? '--count='.(int)$count : null, + '%(refname:short) %(objectname)'); + $branch_list = DiffusionGitBranch::parseRemoteBranchOutput( + $stdout, + $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + } $branches = array(); foreach ($branch_list as $name => $head) { Index: src/applications/diffusion/conduit/ConduitAPI_diffusion_commitbranchesquery_Method.php =================================================================== --- src/applications/diffusion/conduit/ConduitAPI_diffusion_commitbranchesquery_Method.php +++ src/applications/diffusion/conduit/ConduitAPI_diffusion_commitbranchesquery_Method.php @@ -25,13 +25,20 @@ $repository = $drequest->getRepository(); $commit = $request->getValue('commit'); - list($contains) = $repository->execxLocalCommand( - 'branch -r --verbose --no-abbrev --contains %s', - $commit); - - return DiffusionGitBranch::parseRemoteBranchOutput( - $contains, - DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + if ($repository->isWorkingCopyBare()) { + list($contains) = $repository->execxLocalCommand( + 'branch --verbose --no-abbrev --contains %s', + $commit); + return DiffusionGitBranch::parseLocalBranchOutput( + $contains); + } else { + list($contains) = $repository->execxLocalCommand( + 'branch -r --verbose --no-abbrev --contains %s', + $commit); + return DiffusionGitBranch::parseRemoteBranchOutput( + $contains, + DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + } } protected function getMercurialResult(ConduitAPIRequest $request) { Index: src/applications/diffusion/data/DiffusionGitBranch.php =================================================================== --- src/applications/diffusion/data/DiffusionGitBranch.php +++ src/applications/diffusion/data/DiffusionGitBranch.php @@ -70,4 +70,31 @@ return $map; } + + /** + * As above, but with no `-r`. Used for bare repositories. + */ + public static function parseLocalBranchOutput($stdout) { + $map = array(); + + $lines = array_filter(explode("\n", $stdout)); + $regex = '/^[* ]*(\(no branch\)|\S+)\s+([a-z0-9]{40})/'; + foreach ($lines as $line) { + $matches = null; + if (!preg_match($regex, $line, $matches)) { + throw new Exception("Failed to parse {$line}!"); + } + + $branch = $matches[1]; + $branch_head = $matches[2]; + if ($branch == '(no branch)') { + continue; + } + + $map[$branch] = $branch_head; + } + + return $map; + } + } Index: src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php =================================================================== --- src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php +++ src/applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php @@ -526,12 +526,18 @@ $repository->getRemoteURI(), $repository->getLocalPath()); - list($stdout) = $repository->execxLocalCommand( - 'branch -r --verbose --no-abbrev'); - - $branches = DiffusionGitBranch::parseRemoteBranchOutput( - $stdout, - $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + if ($repository->isWorkingCopyBare()) { + list($stdout) = $repository->execxLocalCommand( + 'branch --verbose --no-abbrev'); + $branches = DiffusionGitBranch::parseLocalBranchOutput( + $stdout); + } else { + list($stdout) = $repository->execxLocalCommand( + 'branch -r --verbose --no-abbrev'); + $branches = DiffusionGitBranch::parseRemoteBranchOutput( + $stdout, + $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); + } if (!$branches) { // This repository has no branches at all, so we don't need to do Index: src/applications/repository/engine/PhabricatorRepositoryPullEngine.php =================================================================== --- src/applications/repository/engine/PhabricatorRepositoryPullEngine.php +++ src/applications/repository/engine/PhabricatorRepositoryPullEngine.php @@ -177,7 +177,16 @@ $retry = false; do { // This is a local command, but needs credentials. - $future = $repository->getRemoteCommandFuture('fetch --all --prune'); + if ($repository->isWorkingCopyBare()) { + // For bare working copies, we need this magic incantation. + $future = $repository->getRemoteCommandFuture( + 'fetch origin %s --prune', + '+refs/heads/*:refs/heads/*'); + } else { + $future = $repository->getRemoteCommandFuture( + 'fetch --all --prune'); + } + $future->setCWD($path); list($err, $stdout, $stderr) = $future->resolve(); Index: src/applications/repository/storage/PhabricatorRepository.php =================================================================== --- src/applications/repository/storage/PhabricatorRepository.php +++ src/applications/repository/storage/PhabricatorRepository.php @@ -786,6 +786,25 @@ Filesystem::assertReadable($local); } + /** + * Determine if the working copy is bare or not. In Git, this corresponds + * to `--bare`. In Mercurial, `--noupdate`. + */ + public function isWorkingCopyBare() { + switch ($this->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + return false; + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $local = $this->getLocalPath(); + if (Filesystem::pathExists($local.'/.git')) { + return false; + } else { + return true; + } + } + } + /* -( PhabricatorPolicyInterface )----------------------------------------- */