diff --git a/src/applications/diffusion/editor/DiffusionCommitEditEngine.php b/src/applications/diffusion/editor/DiffusionCommitEditEngine.php index 3cb0a79657..87c1ba2ed8 100644 --- a/src/applications/diffusion/editor/DiffusionCommitEditEngine.php +++ b/src/applications/diffusion/editor/DiffusionCommitEditEngine.php @@ -1,216 +1,217 @@ attachRepository($repository) ->attachCommitData($data) ->attachAudits(array()); } protected function newObjectQuery() { $viewer = $this->getViewer(); return id(new DiffusionCommitQuery()) ->needCommitData(true) ->needAuditRequests(true) ->needAuditAuthority(array($viewer)); } protected function getEditorURI() { return $this->getApplication()->getApplicationURI('commit/edit/'); } protected function newCommentActionGroups() { return array( id(new PhabricatorEditEngineCommentActionGroup()) ->setKey(self::ACTIONGROUP_AUDIT) ->setLabel(pht('Audit Actions')), id(new PhabricatorEditEngineCommentActionGroup()) ->setKey(self::ACTIONGROUP_COMMIT) ->setLabel(pht('Commit Actions')), ); } protected function getObjectCreateTitleText($object) { return pht('Create Commit'); } protected function getObjectCreateShortText() { return pht('Create Commit'); } protected function getObjectEditTitleText($object) { return pht('Edit Commit: %s', $object->getDisplayName()); } protected function getObjectEditShortText($object) { return $object->getDisplayName(); } protected function getObjectName() { return pht('Commit'); } protected function getObjectViewURI($object) { return $object->getURI(); } protected function getCreateNewObjectPolicy() { return PhabricatorPolicies::POLICY_NOONE; } protected function buildCustomEditFields($object) { $viewer = $this->getViewer(); $data = $object->getCommitData(); $fields = array(); $fields[] = id(new PhabricatorDatasourceEditField()) ->setKey('auditors') ->setLabel(pht('Auditors')) ->setDatasource(new DiffusionAuditorDatasource()) ->setUseEdgeTransactions(true) ->setTransactionType( DiffusionCommitAuditorsTransaction::TRANSACTIONTYPE) ->setCommentActionLabel(pht('Change Auditors')) ->setDescription(pht('Auditors for this commit.')) ->setConduitDescription(pht('Change the auditors for this commit.')) ->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; case PhabricatorRepository::BECAUSE_AUTOCLOSE_FORCED: $desc = pht('Yes, Forced Via bin/repository CLI Tool.'); break; case null: $desc = pht('Yes'); break; default: $desc = pht('Unknown'); break; } - $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose'); + $doc_href = PhabricatorEnv::getDoclink( + 'Diffusion User Guide: Permanent Refs'); $doc_link = phutil_tag( 'a', array( 'href' => $doc_href, 'target' => '_blank', ), pht('Learn More')); $fields[] = id(new PhabricatorStaticEditField()) - ->setLabel(pht('Autoclose?')) + ->setLabel(pht('Published?')) ->setValue(array($desc, " \xC2\xB7 ", $doc_link)); } $actions = DiffusionCommitActionTransaction::loadAllActions(); $actions = msortv($actions, 'getCommitActionOrderVector'); foreach ($actions as $key => $action) { $fields[] = $action->newEditField($object, $viewer); } return $fields; } protected function newAutomaticCommentTransactions($object) { $viewer = $this->getViewer(); $xactions = array(); $inlines = PhabricatorAuditInlineComment::loadDraftComments( $viewer, $object->getPHID(), $raw = true); $inlines = msort($inlines, 'getID'); $editor = $object->getApplicationTransactionEditor() ->setActor($viewer); $query_template = id(new DiffusionDiffInlineCommentQuery()) ->withCommitPHIDs(array($object->getPHID())); $xactions = $editor->newAutomaticInlineTransactions( $object, $inlines, PhabricatorAuditActionConstants::INLINE, $query_template); return $xactions; } protected function newCommentPreviewContent($object, array $xactions) { $viewer = $this->getViewer(); $type_inline = PhabricatorAuditActionConstants::INLINE; $inlines = array(); foreach ($xactions as $xaction) { if ($xaction->getTransactionType() === $type_inline) { $inlines[] = $xaction->getComment(); } } $content = array(); if ($inlines) { $inline_preview = id(new PHUIDiffInlineCommentPreviewListView()) ->setViewer($viewer) ->setInlineComments($inlines); $content[] = phutil_tag( 'div', array( 'id' => 'inline-comment-preview', ), $inline_preview); } return $content; } } diff --git a/src/applications/diffusion/view/DiffusionBranchListView.php b/src/applications/diffusion/view/DiffusionBranchListView.php index a2ba34893e..73ad87041a 100644 --- a/src/applications/diffusion/view/DiffusionBranchListView.php +++ b/src/applications/diffusion/view/DiffusionBranchListView.php @@ -1,142 +1,141 @@ 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(); require_celerity_resource('diffusion-css'); $buildables = $this->loadBuildables($commits); $have_builds = false; $can_close_branches = ($repository->isHg()); Javelin::initBehavior('phabricator-tooltips'); - $doc_href = PhabricatorEnv::getDoclink('Diffusion User Guide: Autoclose'); $list = id(new PHUIObjectItemListView()) ->setFlush(true) ->addClass('diffusion-history-list') ->addClass('diffusion-branch-list'); foreach ($this->branches as $branch) { $build_view = null; $button_bar = new PHUIButtonBarView(); $commit = idx($commits, $branch->getCommitIdentifier()); if ($commit) { $details = $commit->getSummary(); $datetime = phabricator_datetime($commit->getEpoch(), $viewer); $buildable = idx($buildables, $commit->getPHID()); if ($buildable) { $build_view = $this->renderBuildable($buildable, 'button'); } } else { $datetime = null; $details = null; } if ($repository->supportsBranchComparison()) { $compare_uri = $drequest->generateURI( array( 'action' => 'compare', 'head' => $branch->getShortName(), )); $can_compare = ($branch->getShortName() != $current_branch); if ($can_compare) { $button_bar->addButton( id(new PHUIButtonView()) ->setTag('a') ->setIcon('fa-balance-scale') ->setToolTip(pht('Compare')) ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE) ->setWorkflow(true) ->setHref($compare_uri)); } } $browse_href = $drequest->generateURI( array( 'action' => 'browse', 'branch' => $branch->getShortName(), )); $button_bar->addButton( id(new PHUIButtonView()) ->setIcon('fa-code') ->setHref($browse_href) ->setTag('a') ->setTooltip(pht('Browse')) ->setButtonType(PHUIButtonView::BUTTONTYPE_SIMPLE)); $commit_link = $repository->getCommitURI( $branch->getCommitIdentifier()); $commit_name = $repository->formatCommitName( $branch->getCommitIdentifier(), $local = true); $commit_tag = id(new PHUITagView()) ->setName($commit_name) ->setHref($commit_link) ->setType(PHUITagView::TYPE_SHADE) ->setColor(PHUITagView::COLOR_INDIGO) ->setBorder(PHUITagView::BORDER_NONE) ->setSlimShady(true); $subhead = array($commit_tag, ' ', $details); $item = id(new PHUIObjectItemView()) ->setHeader($branch->getShortName()) ->setHref($drequest->generateURI( array( 'action' => 'history', 'branch' => $branch->getShortName(), ))) ->setSubhead($subhead) ->setSideColumn(array( $build_view, $button_bar, )); if ($branch->getShortName() == $repository->getDefaultBranch()) { $item->setStatusIcon('fa-code-fork', pht('Default Branch')); } $item->addAttribute(array($datetime)); if ($can_close_branches) { $fields = $branch->getRawFields(); $closed = idx($fields, 'closed'); if ($closed) { $status = pht('Branch Closed'); $item->setDisabled(true); } else { $status = pht('Branch Open'); } $item->addAttribute($status); } $list->addItem($item); } return $list; } } diff --git a/src/applications/diffusion/view/DiffusionBranchTableView.php b/src/applications/diffusion/view/DiffusionBranchTableView.php index bd539e0a25..3e84075a51 100644 --- a/src/applications/diffusion/view/DiffusionBranchTableView.php +++ b/src/applications/diffusion/view/DiffusionBranchTableView.php @@ -1,165 +1,166 @@ 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: Autoclose'); + $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/docs/user/field/repository_imports.diviner b/src/docs/user/field/repository_imports.diviner index 1b1c92bbc0..262874186c 100644 --- a/src/docs/user/field/repository_imports.diviner +++ b/src/docs/user/field/repository_imports.diviner @@ -1,247 +1,247 @@ @title Troubleshooting Repository Imports @group fieldmanual Guide to the troubleshooting repositories which import incompletely. Overview ======== When you first import an external source code repository (or push new commits to a hosted repository), Phabricator imports those commits in the background. While a repository is initially importing, some features won't work. While individual commits are importing, some of their metadata won't be available in the web UI. Sometimes, the import process may hang or fail to complete. This document can help you understand the import process and troubleshoot problems with it. Understanding the Import Pipeline ================================= Phabricator first performs commit discovery on repositories. This examines a repository and identifies all the commits in it at a very shallow level, then creates stub objects for them. These stub objects primarily serve to assign various internal IDs to each commit. Commit discovery occurs in the update phase, and you can learn more about updates in @{article:Diffusion User Guide: Repository Updates}. After commits are discovered, background tasks are queued to actually import commits. These tasks do things like look at commit messages, trigger mentions -and autoclose rules, cache changes, trigger Herald, publish feed stories and -email, and apply Owners rules. You can learn more about some of these steps in -@{article:Diffusion User Guide: Autoclose}. +and update related objects, cache changes, trigger Herald, publish feed stories +and email, and apply Owners rules. You can learn more about some of these steps +in @{article:Diffusion User Guide: Permanent Refs}. Specifically, the import pipeline has four steps: - **Message**: Parses the commit message and author metadata. - **Change**: Caches the paths the commit affected. - **Owners**: Runs Owners rules. - **Herald**: Runs Herald rules and publishes notifications. These steps run in sequence for each commit, but all discovered commits import in parallel. Identifying Missing Steps ========================= There are a few major pieces of information you can look at to understand where the import process is stuck. First, to identify which commits have missing import steps, run this command: ``` phabricator/ $ ./bin/repository importing rXYZ ``` That will show what work remains to be done. Each line shows a commit which is discovered but not imported, and the import steps that are remaining for that commit. Generally, the commit is stuck on the first step in the list. Second, load the Daemon Console (at `/daemon/` in the web UI). This will show what work is currently being done and waiting to complete. The most important sections are "Queued Tasks" (work waiting in queue) and "Leased Tasks" (work currently being done). Third, run this command to look at the daemon logs: ``` phabricator/ $ ./bin/phd log ``` This can show you any errors the daemons have encountered recently. The next sections will walk through how to use this information to understand and resolve the issue. Handling Permanent Failures =========================== Some commits can not be imported, which will permanently stop a repository from fully importing. These are rare, but can be caused by unusual data in a repository, version peculiarities, or bugs in the importer. Permanent failures usually look like a small number of commits stuck on the "Message" or "Change" steps in the output of `repository importing`. If you have a larger number of commits, it is less likely that there are any permanent problems. In the Daemon console, permanent failures usually look like a small number of tasks in "Leased Tasks" with a large failure count. These tasks are retrying until they succeed, but a bug is permanently preventing them from succeeding, so they'll rack up a large number of retries over time. In the daemon log, these commits usually emit specific errors showing why they're failing to import. These failures are the easiest to identify and understand, and can often be resolved quickly. Choose some failing commit from the output of `bin/repository importing` and use this command to re-run any missing steps manually in the foreground: ``` phabricator/ $ ./bin/repository reparse --importing --trace rXYZabcdef012... ``` This command is always safe to run, no matter what the actual root cause of the problem is. If this fails with an error, you've likely identified a problem with Phabricator. Collect as much information as you can about what makes the commit special and file a bug in the upstream by following the instructions in @{article:Contributing Bug Reports}. If the commit imports cleanly, this is more likely to be caused by some other issue. Handling Temporary Failures =========================== Some commits may temporarily fail to import: perhaps the network or services may have briefly been down, or some configuration wasn't quite right, or the daemons were killed halfway through the work. These commits will retry eventually and usually succeed, but some of the retry time limits are very conservative (up to 24 hours) and you might not want to wait that long. In the Daemon console, temporarily failures usually look like tasks in the "Leased Tasks" column with a large "Expires" value but a low "Failures" count (usually 0 or 1). The "Expires" column is showing how long Phabricator is waiting to retry these tasks. In the daemon log, these temporary failures might have created log entries, but might also not have. For example, if the failure was rooted in a network issue that probably will create a log entry, but if the failure was rooted in the daemons being abruptly killed that may not create a log entry. You can follow the instructions from "Handling Permanent Failures" above to reparse steps individually to look for an error that represents a root cause, but sometimes this can happen because of some transient issue which won't be identifiable. The easiest way to fix this is to restart the daemons. When you restart daemons, all task leases are immediately expired, so any tasks waiting for a long time will run right away: ``` phabricator/ $ ./bin/phd restart ``` This command is always safe to run, no matter what the actual root cause of the problem is. After restarting the daemons, any pending tasks should be able to retry immediately. For more information on managing the daemons, see @{article:Managing Daemons with phd}. Forced Parsing ============== In rare cases, the actual tasks may be lost from the task queue. Usually, they have been stolen by gremlins or spirited away by ghosts, or someone may have been too ambitious with running manual SQL commands and deleted a bunch of extra things they shouldn't have. There is no normal set of conditions under which this should occur, but you can force Phabricator to re-queue the tasks to recover from it if it does occur. This will look like missing steps in `repository importing`, but nothing in the "Queued Tasks" or "Leased Tasks" sections of the daemon console. The daemon logs will also be empty, since the tasks have vanished. To re-queue parse tasks for a repository, run this command, which will queue up all of the missing work in `repository importing`: ``` phabricator/ $ ./bin/repository reparse --importing --all rXYZ ``` This command may cause duplicate work to occur if you have misdiagnosed the problem and the tasks aren't actually lost. For example, it could queue a second task to perform publishing, which could cause Phabricator to send a second copy of email about the commit. Other than that, it is safe to run even if this isn't the problem. After running this command, you should see tasks in "Queued Tasks" and "Leased Tasks" in the console which correspond to the commits in `repository importing`, and progress should resume. Forced Imports ============== In some cases, you might want to force a repository to be flagged as imported even though the import isn't complete. The most common and reasonable case where you might want to do this is if you've identified a permanent failure with a small number of commits (maybe just one) and reported it upstream, and are waiting for a fix. You might want to start using the repository immediately, even if a few things can't import yet. You should be cautious about doing this. The "importing" flag controls publishing of notifications and email, so if you flag a repository as imported but it still has a lot of work queued, it may send an enormous amount of email as that work completes. To mark a repository as imported even though it really isn't, run this command: ``` phabricator/ $ ./bin/repository mark-imported rXYZ ``` If you do this by mistake, you can reverse it later by using the `--mark-not-imported` flag. General Tips ============ Broadly, `bin/repository` contains several useful debugging commands which let you figure out where failures are occurring. You can add the `--trace` flag to any command to get more details about what it is doing. For any command, you can use `help` to learn more about what it does and which flag it takes: ``` phabricator/ $ bin/repository help ``` In particular, you can use flags with the `repository reparse` command to manually run parse steps in the foreground, including re-running steps and running steps out of order. Next Steps ========== Continue by: - returning to the @{article:Diffusion User Guide}. diff --git a/src/docs/user/userguide/arcanist_diff.diviner b/src/docs/user/userguide/arcanist_diff.diviner index 3480070b5f..4140deb537 100644 --- a/src/docs/user/userguide/arcanist_diff.diviner +++ b/src/docs/user/userguide/arcanist_diff.diviner @@ -1,209 +1,208 @@ @title Arcanist User Guide: arc diff @group userguide Guide to running `arc diff`, to send changes to Differential for review. This article assumes you have `arc` installed and running; if not, see @{article:Arcanist User Guide} for help getting it set up. Before running `arc diff`, you should create a `.arcconfig` file. If someone set things up for you, they may already have done this. See @{article:Arcanist User Guide: Configuring a New Project} for instructions and information. = Overview = While `arc` has a large number of commands that interface with various Phabricator applications, the primary use of `arc` is to send changes for review in Differential (for more information on Differential, see @{article:Differential User Guide}). If you aren't familiar with Differential, it may be instructive to read that article first to understand the big picture of how the code review workflow works. You send changes for review by running `arc diff`. The rest of this document explains how to use `arc diff`, and how the entire review workflow operates for different version control systems. = Subversion = In Subversion, `arc diff` sends the **uncommitted changes in the working copy** for review. To **create a revision** in SVN: $ nano source_code.c # Make changes. $ arc diff This will prompt you for information about the revision. To later **update an existing revision**, just do the same thing: $ nano source_code.c # Make more changes. $ arc diff This time, `arc` will prompt you to update the revision. Once your revision has been accepted, you can commit it like this: $ arc commit = Git = In Git, `arc diff` sends **all commits in a range** for review. By default, this range is: `git merge-base origin/master HEAD`..HEAD That's a fancy way of saying "all the commits on the current branch that you haven't pushed yet". So, to **create a revision** in Git, run: $ nano source_code.c # Make changes. $ git commit -a # Commit changes. $ arc diff # Creates a new revision out of ALL unpushed commits on # this branch. The `git commit` step is optional. If there are uncommitted changes in the working copy then Arcanist will ask you to create a commit from them. Since it uses **all** the commits on the branch, you can make several commits before sending your changes for review if you prefer. You can specify a different commit range instead by running: $ arc diff This means to use the range: `git merge-base HEAD`..HEAD However, this is a relatively advanced feature. The default is usually correct if you aren't creating branches-on-branches, juggling remotes, etc. To **update a revision**, just do the same thing: $ nano source_code.c # Make more changes. $ git commit -a # Commit them. $ arc diff # This prompts you to update revision information. The `git commit` step is optional. If there are uncommitted changes in the working copy then Arcanist will ask you to amend them to the commit. When your revision has been accepted, you can usually push it like this: $ arc land # Merges into master and pushes. `arc land` makes some assumptions about your workflow which might not be true. Consult the documentation before you use it. You should also look at `arc amend`, which may fit your workflow better. = Mercurial = In Mercurial, `arc diff` sends **all commits in a range** for review. By default, this range is changes between the first non-outgoing parent of any revision in history and the directory state. This is a fancy way of saying "every outgoing change since the last merge". It includes any uncommitted changes in the working copy, although you will be prompted to include these. To **create a revision** in Mercurial, run: $ nano source_code.c # Make changes. $ hg commit # Commit changes. $ arc diff # Creates a new revision out of ALL outgoing commits # on this branch since the last merge. The `hg commit` step is optional. If there are uncommitted changes in the working copy then Arcanist will ask you to create a commit from them. Since it uses **all** the outgoing commits on the branch, you can make several commits before sending your changes for review if you prefer. You can specify a different commit range instead by running: $ arc diff This means to use the range from that commit to the directory state. However, this is an advanced feature and the default is usually correct. To **update a revision**, just do the same thing: $ nano source_code.c # Make changes. $ hg commit # Commit changes. $ arc diff # This prompts you to update revision information. The `hg commit` step is optional. If there are uncommitted changes in the working copy then Arcanist will ask you to create a commit from them (or amend them to the previous commit if supported). When your revision has been accepted, push it normally. (`arc` does not have push integration in Mercurial because it can't force merges and thus can't guarantee it will be able to do anything useful.) = Pushing and Closing Revisions = After changes have been accepted, you generally push them and close the revision. `arc` has several workflows which help with this, by: - squashing or merging changes from a feature branch into a master branch (if relevant); - formatting a good commit message with all the information from Differential; and - automatically closing the revision. You don't need to use any of these workflows: you can just run `git push`, `hg push` or `svn commit` and then manually close the revision from the web. However, these workflows can make common development strategies more convenient, and give you better commit messages in the repository. The workflows `arc` supports are: - `arc land`: Works in Git if you develop in feature branches. Does a merge or squash-merge from your feature branch into some master branch, provides a detailed commit message, pushes master, and then deletes your branch. - `arc amend`: Works in Git if you can't use `arc land`. Amends HEAD with a detailed commit message. - `arc commit`: Works in Subversion. Runs `svn commit` with a detailed commit message. - `arc close-revision`: Works anywhere, closes a revision from the CLI without going through the web UI. You can use `arc help ` for detailed help with any of these. Differential will make a guess about a next step on accepted revisions, but it may not be the best next step for your workflow. -Phabricator will also automatically close revisions, if the changes are pushed +Phabricator will also automatically close revisions if the changes are pushed to a repository that is tracked in Diffusion. Specifically, it will close revisions based on commit and tree hashes, and `Differential Revision` -identifiers in commit messages. (You can disable this feature by disabling -"Autoclose" in the Repository configuration.) +identifiers in commit messages. If you push to an untracked repository (or `arc` can't figure out that it's tracked), `arc land`, `arc amend` and `arc commit` will implicitly run `arc close-revision`. = General Information = This information is not unique to a specific version control system. == Force Diff Only == You can create just a diff (rather than a revision) with `--preview` (or `--only`, but this disables other features). You can later use it to create or update a revision from the web UI. == Other Diff Sources == You can create a diff out of an arbitrary patch file by using `--raw` and piping it to stdin. In most cases this will only create a diff, not a revision. You can use the web UI to create a revision from the diff, or update an existing revision. == Force Create / Update == `arc` uses information about the working copy (like the path, branch name, local commit hashes, and local tree hashes, depending on which version control system you are using) to figure out whether you intend to create or update a revision. If it guesses incorrectly, you can force it to either create or update a revision with: $ arc diff --create # Force "create". $ arc diff --update # Force "update". You can figure out what `arc` believes to be in the working copy with `arc which`. diff --git a/src/docs/user/userguide/diffusion.diviner b/src/docs/user/userguide/diffusion.diviner index 7c48d7a636..8ee66d3f8f 100644 --- a/src/docs/user/userguide/diffusion.diviner +++ b/src/docs/user/userguide/diffusion.diviner @@ -1,94 +1,94 @@ @title Diffusion User Guide @group userguide Guide to Diffusion, the Phabricator application for hosting and browsing repositories. Overview ======== Diffusion allows you to create repositories so that you can browse them from the web and interact with them from other applications. Diffusion can host repositories locally, or observe existing remote repositories which are hosted elsewhere (for example, on GitHub, Bitbucket, or other existing hosting). Both types of repositories can be browsed and interacted with, but hosted repositories support some additional triggers and access controls which are not available for observed repositories. Diffusion is integrated with the other tools in the Phabricator suite. For instance: - when you commit Differential revisions to a tracked repository, they are automatically updated and linked to the corresponding commits; - you can add Herald rules to notify you about commits that match certain rules; - for hosted repositories, Herald can enforce granular access control rules; - in all the tools, commit names are automatically linked. The remainder of this document walks through creating, configuring, and managing repositories. Adding Repositories =================== Repository administration is accomplished through Diffusion. You can use the web interface in Diffusion to observe an external repository or create a new hosted repository. - For hosted repositories, make sure you go through the setup instructions in @{article:Diffusion User Guide: Repository Hosting} first. - For all repositories, you'll need to be running the daemons. If you have not set them up yet, see @{article:Managing Daemons with phd}. By default, you must be an administrator to create a new repository. You can change this in the application settings. Managing Repositories ===================== Diffusion repositories have an array of configurable options and behaviors. For details on the available options and guidance on managing and administrating repositories, see @{article:Diffusion User Guide: Managing Repositories}. Repositories can also be managed via the API. For an overview on using the API to create and edit repositories, see @{article:Diffusion User Guide: Repositories API}. Repository Clustering ===================== Phabricator repository hosts can be set up in a cluster configuration so you can lose hosts with minimal downtime and data loss. This is an advanced feature which most installs do not need to pursue. To get started with clustering, see @{article:Clustering Introduction}. For details on repository clustering, see @{article:Cluster: Repositories}. Next Steps ========== Continue by: - learning how to creating a symbol index at @{article:Diffusion User Guide: Symbol Indexes}; or - setting up repository hosting with @{article:Diffusion User Guide: Repository Hosting}; or - managing repository hooks with @{article:Diffusion User Guide: Commit Hooks}; or - understanding daemons in more detail with @{article:Managing Daemons with phd}. If you're having trouble getting things working, these topic guides may be helpful: - - get details about automatically closing tasks and revisions in response - to commits in @{article:Diffusion User Guide: Autoclose}; or + - get details about automatically taking actions in response to commits in + @{article:Diffusion User Guide: Permanent Refs}; or - understand how Phabricator updates repositories with @{article:Diffusion User Guide: Repository Updates}; or - fix issues with repository imports with @{article:Troubleshooting Repository Imports}. diff --git a/src/docs/user/userguide/diffusion_autoclose.diviner b/src/docs/user/userguide/diffusion_autoclose.diviner deleted file mode 100644 index 796a3b0404..0000000000 --- a/src/docs/user/userguide/diffusion_autoclose.diviner +++ /dev/null @@ -1,84 +0,0 @@ -@title Diffusion User Guide: Autoclose -@group userguide - -Explains when Diffusion will close tasks and revisions upon discovery of related -commits. - -Overview -======== - -Diffusion can close tasks and revisions when related commits appear in a -repository. For example, if you make a commit with `Fixes T123` in the commit -message, Diffusion will close the task `T123`. - -This document explains how autoclose works, how to configure it, and how to -troubleshoot it. - -Troubleshooting Autoclose -========================= - -You can check if a branch is currently configured to autoclose on the -management page for the given repository under the branches menu item. -You should see one of these statuses next to the name of the branch: - - - **Autoclose On** Autoclose is active for this branch. - - **Repository Importing** This repository is still importing. - Autoclose does not activate until a repository finishes importing for the - first time. This prevents situations where you import a repository and - accidentally close hundreds of related objects during import. Autoclose - will activate for new commits after the initial import completes. - - **Tracking Off** This branch is not tracked. Because it - is not tracked, commits on it won't be seen and won't be discovered. - - **Autoclose Off** Autoclose is not enabled for - this branch. You can adjust which branches autoclose in **Edit Repository**. - This option is only available in Git. - -If a branch is in good shape, you can check a specific commit by viewing it -in the web UI and clicking **Edit Commit**. There should be an **Autoclose?** -field visible in the form, with possible values listed below. - -Note that this field records the state of the world at the time the commit was -processed, and does not necessarily reflect the current state of the world. -For example, if a commit did not trigger autoclose because it was processed -during initial import, the field will still show **No, Repository Importing** -even after import completes. This means that the commit did not trigger -autoclose because the repository was importing at the time it was processed, -not necessarily that the repository is still importing. - - - **Yes** At the time the commit was imported, autoclose triggered and - Phabricator attempted to close related objects. - - **No, Repository Importing** At the time the commit was processed, the - repository was still importing. Autoclose does not activate until a - repository fully imports for the first time. - - **No, Autoclose Disabled** At the time the commit was processed, the - repository had autoclose disabled. - - **No, Not On Autoclose Branch** At the time the commit was processed, - no containing branch was configured to autoclose. - - //Field Not Present// This commit was processed before we implemented - this diagnostic feature, and no information is available. - - -Manually Closing Revisions -========================== - -If autoclose didn't activate for some reason and you want to manually close -revisions, you can do so in several ways: - -**Close Revision**: The revision author can use the "Close Revision" action -from the web UI, located in the action dropdown on the revision page (where -reviewers would "Accept Revision" or "Request Changes"). - -`differential.always-allow-close`: If you set this option in {nav Config}, -any user can take the "Close Revision" action in the web UI. - -`arc close-revision`: You can close revisions from the command line by using -`arc close-revision`. - - -Next Steps -========== - -Continue by: - - - troubleshooting in greater depth with - @{article:Troubleshooting Repository Imports}. diff --git a/src/docs/user/userguide/diffusion_managing.diviner b/src/docs/user/userguide/diffusion_managing.diviner index a671b0f09e..aa52c1c475 100644 --- a/src/docs/user/userguide/diffusion_managing.diviner +++ b/src/docs/user/userguide/diffusion_managing.diviner @@ -1,427 +1,452 @@ @title Diffusion User Guide: Managing Repositories @group userguide Guide to configuring and managing repositories in Diffusion. Overview ======== After you create a new repository in Diffusion or select **Manage Repository** from the main screen if an existing repository, you'll be taken to the repository management interface for that repository. On this interface, you'll find many options which allow you to configure the behavior of a repository. This document walks through the options. Basics ====== The **Basics** section of the management interface allows you to configure the repository name, description, and identifiers. You can also activate or deactivate the repository here, and configure a few other miscellaneous settings. Basics: Name ============ The repository name is a human-readable primary name for the repository. It does not need to be unique Because the name is not unique and does not have any meaningful restrictions, it's fairly ambiguous and isn't very useful as an identifier. The other basic information (primarily callsigns and short names) gives you control over repository identifiers. Basics: Callsigns ================= Each repository can optionally be identified by a "callsign", which is a short uppercase string like "P" (for Phabricator) or "ARC" (for Arcanist). The primary goal of callsigns is to namespace commits to SVN repositories: if you use multiple SVN repositories, each repository has a revision 1, revision 2, etc., so referring to them by number alone is ambiguous. However, even for Git and Mercurial they impart additional information to human readers and allow parsers to detect that something is a commit name with high probability (and allow distinguishing between multiple copies of a repository). Configuring a callsign can make interacting with a commonly-used repository easier, but you may not want to bother assigning one to every repository if you have some similar, templated, or rarely-used repositories. If you choose to assign a callsign to a repository, it must be unique within an install but do not need to be globally unique, so you are free to use the single-letter callsigns for brevity. For example, Facebook uses "E" for the Engineering repository, "O" for the Ops repository, "Y" for a Yum package repository, and so on, while Phabricator uses "P", "ARC", "PHU" for libphutil, and "J" for Javelin. Keeping callsigns brief will make them easier to use, and the use of one-character callsigns is encouraged if they are reasonably evocative. If you configure a callsign like `XYZ`, Phabricator will activate callsign URIs and activate the callsign identifier (like `rXYZ`) for the repository. These more human-readable identifiers can make things a little easier to interact with. Basics: Short Name ================== Each repository can optionally have a unique short name. Short names must be unique and have some minor restrictions to make sure they are unambiguous and appropriate for use as directory names and in URIs. Basics: Description =================== You may optionally provide a brief (or, at your discretion, excruciatingly long) human-readable description of the repository. This description will be shown on the main repository page. You can also create a `README` file at the repository root (or in any subdirectory) to provide information about the repository. These formats are supported: | File Name | Rendered As... |-------------------|--------------- | `README` | Plain Text | `README.txt` | Plain Text | `README.remarkup` | Remarkup | `README.md` | Remarkup | `README.rainbow` | Rainbow Basics: Encoding ================ Before content from the repository can be shown in the web UI or embedded in other contexts like email, it must be converted to UTF-8. Most source code is written in UTF-8 or a subset of UTF-8 (like plain ASCII) already, so everything will work fine. The majority of repositories do not need to adjust this setting. If your repository is primarily written in some other encoding, specify it here so Phabricator can convert from it properly when reading content to embed in a webpage or email. Basics: Dangerous Changes ========================= By default, repositories are protected against dangerous changes. Dangerous changes are operations which rewrite or destroy repository history (for example, by deleting or rewriting branches). Normally, these take the form of `git push --force` or similar. It is normally a good idea to leave this protection enabled because most scalable workflows rarely rewrite repository history and it's easy to make mistakes which are expensive to correct if this protection is disabled. If you do occasionally need to rewrite published history, you can treat this option like a safety: disable it, perform required rewrites, then enable it again. If you fully disable this at the repository level, you can still use Herald to selectively protect certain branches or grant this power to a limited set of users. This option is only available in Git and Mercurial, because it is impossible to make dangerous changes in Subversion. This option has no effect if a repository is not hosted because Phabricator can not prevent dangerous changes in a remote repository it is merely observing. +Basics: Disable Publishing +========================== + +You can disable publishing for a repository. For more details on what this +means, see @{article:Diffusion User Guide: Permanent Refs}. + +This is primarily useful if you need to perform major maintenance on a +repository (like rewriting a large part of the repository history) and you +don't want the maintenance to generate a large volume of email and +notifications. You can disable publishing, apply major changes, wait for the +new changes to import, and then reactivate publishing. + + Basics: Deactivate Repository ============================= Repositories can be deactivated. Deactivating a repository has these effects: - the repository will no longer be updated; - users will no longer be able to clone/fetch/checkout the repository; - users will no longer be able to push to the repository; and - the repository will be hidden from view in default queries. When repositories are created for the first time, they are deactivated. This gives you an opportunity to customize settings, like adjusting policies or configuring a URI to observe. You must activate a repository before it will start working normally. Basics: Delete Repository ========================= Repositories can not be deleted from the web UI, so this option is always disabled. Clicking it gives you information about how to delete a repository. Repositories can only be deleted from the command line, with `bin/remove`: ``` $ ./bin/remove destroy ``` WARNING: This command will issue you a dire warning about the severity of the action you are taking. Heed this warning. You are **strongly discouraged** from destroying repositories. Instead, deactivate them. Policies ======== The **Policies** section of the management interface allows you to review and manage repository access policies. You can configure granular access policies for each repository to control who can view, clone, administrate, and push to the repository. Policies: View ============== The view policy for a repository controls who can view the repository from the web UI and clone, fetch, or check it out from Phabricator. Users who can view a repository can also access the "Manage" interface to review information about the repository and examine the edit history, but can not make any changes. Policies: Edit ============== The edit policy for a repository controls who can change repository settings using the "Manage" interface. In essence, this is permission to administrate the repository. You must be able to view a repository to edit it. You do not need this permission to push changes to a repository. Policies: Push ============== The push policy for a repository controls who can push changes to the repository. This policy has no effect if Phabricator is not hosting the repository, because it can not control who is allowed to make changes to a remote repository it is merely observing. You must also be able to view a repository to push to it. You do not need to be able to edit a repository to push to it. Further restrictions on who can push (and what they can push) can be configured for hosted repositories with Herald, which allows you to write more sophisticated rules that evaluate when Phabricator receives a push. To get started with Herald, see @{article:Herald User Guide}. Additionally, Git and Mercurial repositories have a setting which allows you to **Prevent Dangerous Changes**. This setting is enabled by default and will prevent any users from pushing changes which rewrite or destroy history. URIs ==== The **URIs** panel allows you to add and manage URIs which Phabricator will fetch from, serve from, and push to. These options are covered in detail in @{article:Diffusion User Guide: URIs}. Limits ====== The **Limits** panel allows you to configure limits and timeouts. **Filesize Limit**: Allows you to set a maximum filesize for any file in the repository. If a commit creates a larger file (or modifies an existing file so it becomes too large) it will be rejected. This option only applies to hosted repositories. This limit is primarily intended to make it more difficult to accidentally push very large files that shouldn't be version controlled (like logs, binaries, machine learning data, or media assets). Pushing huge datafiles by mistake can make the repository unwieldy by dramatically increasing how much data must be transferred over the network to clone it, and simply reverting the changes doesn't reduce the impact of this kind of mistake. **Clone/Fetch Timeout**: Configure the internal timeout for creating copies of this repository during operations like intracluster synchronization and Drydock working copy construction. This timeout does not affect external users. **Touch Limit**: Apply a limit to the maximum number of paths that any commit may touch. If a commit affects more paths than this limit, it will be rejected. This option only applies to hosted repositories. Users may work around this limit by breaking the commit into several smaller commits which each affect fewer paths. This limit is intended to offer a guard rail against users making silly mistakes that create obviously mistaken changes, like copying an entire repository into itself and pushing the result. This kind of change can take some effort to clean up if it becomes part of repository history. Note that if you move a file, both the old and new locations count as touched paths. You should generally configure this limit to be more than twice the number of files you anticipate any user ever legitimately wanting to move in a single commit. For example, a limit of `20000` will let users move up to 10,000 files in a single commit, but will reject users mistakenly trying to push a copy of another repository or a directory with a million logfiles or whatever other kind of creative nonsense they manage to dream up. Branches ======== The **Branches** panel allows you to configure how Phabricator interacts with branches. This panel is not available for Subversion repositories, because Subversion does not have formal branches. -You can configure **Default Branch**. This controls which branch is shown by +You can configure a **Default Branch**. This controls which branch is shown by default in the UI. If no branch is provided, Phabricator will use `master` in Git and `default` in Mercurial. -If you want Diffusion to ignore some branches in the repository, you can -configure **Track Only**. Other branches will be ignored. If you do not specify -any branches, all branches are tracked. +**Fetch Refs**: In Git, if you are observing a remote repository, you can +specify that you only want to fetch a subset of refs using "Fetch Refs". -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: +Normally, all refs (`refs/*`) are fetched. This means all branches, all tags, +and all other refs. -| Example | Effect | -|---------|--------| -| `master` | Track only `master`. -| `regexp(/^release-/)` | Track all branches which start with `release-`. -| `regexp(/^(?!temp-)/)` | Do not track branches which start with `temp-`. +If you want to fetch only a few specific branches, you can list only those +branches. For example, this will fetch only the branch "master": +``` +refs/heads/master +``` -Actions -====== +You can fetch all branches and tags (but ignore other refs) like this: -The **Actions** panel can configure notifications and publishing behavior. +``` +refs/heads/* +refs/tags/* +``` + +This may be useful if the remote is on a service like GitHub, GitLab, or +Gerrit and uses custom refs (like `refs/pull/` or `refs/changes/`) to store +metadata that you don't want to bring into Phabricator. -Normally, Phabricator publishes notifications when it discovers new commits. -You can disable publishing for a repository by turning off **Publish/Notify**. -This will disable notifications, feed, and Herald (including audits and build -plans) for this repository. +**Permanent Refs**: To learn more about permanent refs, see: -When Phabricator discovers a new commit, it can automatically close associated -revisions and tasks. If you don't want Phabricator to close objects when it -discovers new commits, disable **Autoclose** for the repository. + - @{article:Diffusion User Guide: Permanent Refs} + +By default, Phabricator considers all branches to be permanent refs. If you +only want some branches to be treated as permanent refs, specify them here. + +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: + +| Example | Effect | +|---------|--------| +| `master` | Only the `master` branch is a permanent ref. +| `regexp(/^release-/)` | Branches are permanent if they start with `release-`. +| `regexp(/^(?!temp-)/)` | Branches named `temp-` are not permanent. Staging Area ============ The **Staging Area** panel configures staging areas, used to make proposed changes available to build and continuous integration systems. For more details, see @{article:Harbormaster User Guide}. Automation ========== The **Automation** panel configures support for allowing Phabricator to make writes directly to the repository, so that it can perform operations like automatically landing revisions from the web UI. For details on repository automation, see @{article:Drydock User Guide: Repository Automation}. Symbols ====== The **Symbols** panel allows you to customize how symbols (like class and function names) are linked when viewing code in the repository, and when viewing revisions which propose code changes to the repository. To take advantage of this feature, you need to do additional work to build symbol indexes. For details on configuring and populating symbol indexes, see @{article:User Guide: Symbol Indexes}. Repository Identifiers and Names ================================ Repositories have several short identifiers which you can use to refer to the repository. For example, if you use command-line administrative tools to interact with a repository, you'll provide one of these identifiers: ``` $ ./bin/repository update ``` The identifiers available for a repository depend on which options are configured. Each repository may have several identifiers: - An **ID** identifier, like `R123`. This is available for all repositories. - A **callsign** identifier, like `rXY`. This is available for repositories with a callsign. - A **short name** identifier, like `xylophone`. This is available for repositories with a short name. All three identifiers can be used to refer to the repository in cases where the intent is unambiguous, but only the first two forms work in ambiguous contexts. For example, if you type `R123` or `rXY` into a comment, Phabricator will recognize them as references to the repository. If you type `xylophone`, it assumes you mean the word "xylophone". Only the `R123` identifier is immutable: the others can be changed later by adjusting the callsign or short name for the repository. Commit Identifiers ================== Diffusion uses repository identifiers and information about the commit itself to generate globally unique identifiers for each commit, like `rE12345`. Each commit may have several identifiers: - A repository **ID** identifier, like `R123:abcdef123...`. - A repository **callsign** identifier, like `rXYZabcdef123...`. This only works if a repository has a callsign. - Any unique prefix of the commit hash. Git and Mercurial use commit hashes to identify commits, and Phabricator will recognize a commit if the hash prefix is unique and sufficiently long. Commit hashes qualified with a repository identifier must be at least 5 characters long; unqualified commit hashes must be at least 7 characters long. In Subversion, commit identifiers are sequential integers and prefixes can not be used to identify them. When rendering the name of a Git or Mercurial commit hash, Phabricator tends to shorten it to 12 characters. This "short length" is relatively long compared to Git itself (which often uses 7 characters). See this post on the LKML for a historical explanation of Git's occasional internal use of 7-character hashes: https://lkml.org/lkml/2010/10/28/287 Because 7-character hashes are likely to collide for even moderately large repositories, Diffusion generally uses either a 12-character prefix (which makes collisions very unlikely) or the full 40-character hash (which makes collisions astronomically unlikely). Next Steps ========== Continue by: - returning to the @{article:Diffusion User Guide}. diff --git a/src/docs/user/userguide/diffusion_permanent.diviner b/src/docs/user/userguide/diffusion_permanent.diviner new file mode 100644 index 0000000000..fba4341c0c --- /dev/null +++ b/src/docs/user/userguide/diffusion_permanent.diviner @@ -0,0 +1,81 @@ +@title Diffusion User Guide: Permanent Refs +@group userguide + +Explains when Diffusion will take actions in response to discovering commits. + +Overview +======== + +Diffusion can close tasks and revisions and take other actions when commits +appear in a repository (either because they were pushed to Phabricator, or +because they were pushed to some remote which Phabricator is observing). + +This document explains when Diffusion acts on commits and how to configure this +behavior. + + +Publishing Commits +================== + +Diffusion distinguishes between "pushed" and "published" commits. + +Not all commits that are pushed to a repository are destined for greatness: +for example, many tools push temporary commits to secret places like +`refs/pull/123`, `refs/notes/*`, or `refs/changes/12/345678/1`. + +Sometimes, human users intentionally push changes to branches like +"tmp-hack-ignore-123". This is formally discouraged by Phabricator, but the +practice is so widespread that we've given up trying to stop anyone from doing +it. + +Phabricator will import these commits and create pages for them so you can view +them in the web UI and link to them, but does not take any other actions until +they are "published". + +A commit is "published" when it becomes reachable from a permanent ref. By +default, all branches are permanent refs, so pushing a commit to "master" will +publish it, but pushing a commit to `refs/pull/123` (either directly, or by +using a tool like GitHub) will not. + +Usually, commits are published by pushing them directly to a permanent branch +like "master", or by merging a temporary branch into a permanent branch. + +When a commit is published, Phabricator acts on it and: + + - sends email; + - delivers notifications; + - publishes a feed story; + - triggers Audits; + - runs Herald rules; + - updates mentioned objects; + - closes referenced tasks; and + - closes associated revisions. + + +Configuring Repositories +======================== + +You can control publishing behavior in two primary ways: by configuring +which refs are considered to be permanent refs, and by disabling publishing +entirely. + +By default, all branches are considered permanent refs and all other refs +(including tags and other arbitrary custom refs) are considered nonpermanent. +This means that, by default, pushing commits to a branch like +"tmp-hack-ignore-123" will publish those commits. + +If you want to be free to push commits to temporary branches like this and +only want commits on certain branches (like "master") to be published, +configure which refs are treated as permanent by editing +{nav Branches > Permanent Refs} from the "Manage" page of the repository. + +To disable publishing entirely, select {nav Basics > Disable Publishing}. + + +Next Steps +========== + +Continue by: + + - troubleshooting in greater depth with + @{article:Troubleshooting Repository Imports}.