Page MenuHomePhorge

No OneTemporary

diff --git a/src/docs/flavortext/recommendations_on_revision_control.diviner b/src/docs/flavortext/recommendations_on_revision_control.diviner
new file mode 100644
index 0000000000..40b878a808
--- /dev/null
+++ b/src/docs/flavortext/recommendations_on_revision_control.diviner
@@ -0,0 +1,82 @@
+@title Recommendations on Revision Control
+@group flavortext
+
+Project recommendations on how to organize revision control.
+
+This document is purely advisory. Phabricator works with a variety of revision
+control strategies, and diverging from the recommendations in this document
+will not impact your ability to use it for code review and management.
+
+This is my (epriestley's) personal take on the issue and not necessarily
+representative of the views of the Phabricator team as a whole.
+
+= Overview =
+
+There are a few ways to use SVN, a few ways to use Mercurial, and many many many
+ways to use Git. Particularly with Git, every project does things differently,
+and all these approaches are valid for small projects. When projects scale,
+strategies which enforce **one idea is one commit** are better.
+
+= One Idea is One Commit =
+
+Choose a strategy where **one idea is one commit** in the authoritative
+master/remote version of the repository. Specifically, this means that an entire
+conceptual changeset ("add a foo widget") is represented in the remote as
+exactly one commit (in some form), not a sequence of checkpoint commits.
+
+ - In SVN, this means don't ##commit## until after an idea has been completely
+ written. All reasonable SVN workflows naturally enforce this.
+ - In Git, this means squashing checkpoint commits as you go (with ##git commit
+ --amend##) or before pushing (with ##git rebase -i##), or having a strict
+ policy where your master/trunk contains only merge commits and each is a
+ merge between the old master and a branch which represents a single idea.
+ Although this preserves the checkpoint commits along the branches, you can
+ view master alone as a series of single-idea commits.
+ - In Mercurial, it is not generally possible to avoid having ideas spread
+ across multiple commits. Mercurial does not support liberal mutability
+ doctrines (so you can't squash commits) and does not let you build a default
+ out of only merge commits, so it is not possible to have an authoritative
+ repository where one commit represents one idea in any real sense. Thus,
+ Mercurial is not recommended for projects which may ever need to scale.
+
+= Why This Matters =
+
+A strategy where **one idea is one commit** has no real advantage over any other
+strategy until your repository hits a velocity where it becomes critical. In
+particular:
+
+ - Essentially all operations against the master/remote repository are about
+ ideas, not commits. When one idea is many commits, everything you do is more
+ complicated because you need to figure out which commits represent an idea
+ ("the foo widget is broken, what do I need to revert?") or what idea is
+ ultimately represented by a commit ("commit af3291029 makes no sense, what
+ goal is this change trying to accomplish?").
+ - Release engineering is greatly simplified. Release engineers can pick or
+ drop ideas easily when each idea corresponds to one commit. When an idea
+ is several commits, it becomes easier to accidentally pick or drop half of
+ an idea and end up in a state which is virtually guaranteed to be wrong.
+ - Automated testing is greatly simplified. If each idea is one commit, you
+ can run automated tests against every commit and test failures indicate a
+ serious problem. If each idea is many commits, most of those commits
+ represent a known broken state of the codebase (e.g., a checkpoint with a
+ syntax error which was fixed in the next checkpoint, or with a
+ half-implemented idea).
+ - Understanding changes is greatly simplified. You can bisect to a break and
+ identify the entire idea trivially, without fishing forward and backward in
+ the log to identify the extents of the idea. And you can be confident in
+ what you need to revert to remove the entire idea.
+ - There is no clear value in having checkpoint commits (some of which are
+ guaranteed to be known broken versions of the repository) persist into the
+ remote. Consider a theoretical VCS which automatically creates a checkpoint
+ commit for every keystroke. This VCS would obviously be unusable. But many
+ checkpoint commits aren't much different, and conceptually represent some
+ relatively arbitrary point in the sequence of keystrokes that went into
+ writing a larger idea. Get rid of them
+ or create an abstraction layer (merge commits) which allows you to ignore
+ them when you are trying to understand the repository in terms of ideas
+ (which is almost always).
+
+All of these become problems only at scale. Facebook pushes dozens of ideas
+every day and thousands on a weekly basis, and could not do this (at least, not
+without more people or more errors) without choosing a repository strategy where
+**one idea is one commit**.
diff --git a/src/docs/userguide/arcanist.diviner b/src/docs/userguide/arcanist.diviner
index 3ba63dcab4..bef76eb7e2 100644
--- a/src/docs/userguide/arcanist.diviner
+++ b/src/docs/userguide/arcanist.diviner
@@ -1,148 +1,232 @@
@title Arcanist User Guide
@group userguide
Guide to Arcanist, a command-line tool for code review and revision management.
Arcanists glues together several other tools, like Differential and lint. It
also serves as the CLI to Phabricator, and is used to get changesets into
Differential for review.
A detailed command reference is available by running ##arc help##. This
document provides a high level overview of common workflows.
Arcanist has technical, contributor-focused documentation here:
<http://www.phabricator.com/docs/arcanist/>
= Overview =
Arcanist is a wrapper script that sits on top of other tools (e.g.,
-Differential, linters, unit test frameworks, SVN, and git) and provides a
-simple command-line API to manage code review and some related revision control
-operations.
+Differential, linters, unit test frameworks, git, Mercurial, and SVN) and
+provides a simple command-line API to manage code review and some related
+revision control operations.
Arcanist allows you to do things like:
- get detailed help about available commands with ##arc help##
- send your code to Differential for review with ##arc diff##
- show pending revision information with ##arc list##
- find likely reviewers for a change with ##arc cover##
- apply changes in a revision to the working copy with ##arc patch##
- download a patch from Differential with ##arc export##
- update Git commit messages after review with ##arc amend##
- commit SVN changes with ##arc commit##
+ - merge Git and Mercurial changes with ##arc merge##
- view enhanced information about Git branches with ##arc branch##
Once you've configured lint and unit test integration, you can also:
- check your code for syntax and style errors with ##arc lint##
- run unit tests that cover your changes with ##arc unit##
Arcanist has some advanced features as well, you can:
- execute Conduit method calls with ##arc call-conduit##
- create or update libphutil libraries with ##arc liberate##
- activate tab completion with ##arc shell-complete##
- install arc as a pre-commit hook with ##arc svn-hook-pre-commit## or
##arc git-hook-pre-receive##
- ...or extend Arcanist and add new commands.
Except where otherwise noted, these workflows are generally agnostic to the
-underlying version control system and will work properly in git or SVN
-repositories.
+underlying version control system and will work properly in git, Mercurial, or
+SVN repositories.
= Installing Arcanist =
Arcanist is meant to be installed on your local machine or development server,
i.e. whatever machine you're editing code on. It runs on Linux and Mac OS X;
To install it, clone it and libphutil off github:
somewhere/ $ git clone git://github.com/facebook/libphutil.git
somewhere/ $ git clone git://github.com/facebook/arcanist.git
Now add ##somewhere/arcanist/bin/arc## to your path.
== Installing Tab Completion ==
If you use ##bash##, you can set up tab completion by adding something like this
to your ##.bashrc##, ##.profile## or similar:
source /path/to/arcanist/resources/shell/bash-completion
= Running Arcanist =
Arcanist is a context-sensitive command which you should run in a working copy,
-like ##svn## or ##git##. Generally speaking, ##arc## commands operate on changed
-files in the working copy in svn, and on the commit at HEAD in git.
+like ##git##, ##hg##, or ##svn##. Generally speaking, ##arc## commands operate
+on changed files in the working copy in SVN, a commit range you specify in git,
+and outgoing changes on the current branch in Mercurial.
== SVN Basics ==
To **create a revision** in SVN:
$ nano source_code.c # Make changes.
$ arc diff
This will give you a diff URI, which you can use to create a new revision via
the web UI. To later **update an existing revision**, just do the same thing:
$ nano source_code.c # Make more changes.
$ arc diff
This time, attach the diff to your existing revision. Once your revision has
been accepted, you can commit it like this:
$ arc commit
== Git Basics ==
There are a lot of ways to use git, and Arcanist is flexible enough to handle
-several of them. Use a commit template similar to this one:
+several of them. Git workflows divide into two major groups based on your
+**doctrine of history mutability**.
+
+Choose a **history mutability doctrine** by setting ##"immutable_history"## in
+your ##.arcconfig##. Valid values are ##true## to enforce a **conservative
+history mutability doctrine** or ##false## to enforce a **liberal history
+mutability doctrine**.
+
+A **liberal history mutability doctrine** means you rewrite local history. You
+develop in feature branches, but squash or amend before pushing by using ##git
+commit --amend## or ##git rebase -i##. Generally, one idea in the remote is
+represented by one commit. Arc will read revision information from commit
+messages, and you will finalize commits with ##arc amend##.
+
+A **conservative history mutability doctrine** means that you do not rewrite
+local history. This is similar to how Mercurial works. You develop in feature
+branches and push them without squashing commits. You do not use ##git commit
+--amend## or ##git rebase -i##. Generally, one idea in the remote is represented
+by many commits. You will specify revision information via web workflows, and
+finalize commits with ##arc merge##.
+
+You can also choose no doctrine, which allows you to use both ##arc amend##
+and ##arc merge##. This isn't recommended, but Phabricator explicitly tries to
+support a broad range of git workflows. For recommendations on how to use git
+and why this choice of doctrines exists, see @{article:Recommendations on
+Revision Control}. If you aren't compelled by this and want to use a mixed
+workflow, you can pick and choose parts of each workflow.
+
+Phabricator associates commits to revisions (code reviews) by using commit
+messages and commit hashes. It will be unable to detect that you have committed
+a revision if you rebase (which changes all the hashes), and don't ##arc amend##
+or ##arc merge##, and don't ##arc diff## to update Differential with the new
+local hashes. You can use ##arc mark-committed## to explicitly mark revisions
+committed.
+
+=== Git: Conservative Mutability Doctrine ===
+
+NOTE: This doctrine is new and experimental.
+
+This section assumes you are using git with a **conservative history mutability
+doctrine** and have set ##"immutable_history" : true## in your ##.arcconfig##.
+
+To **create or update a revision** in git with a conservative doctrine:
+
+ $ git checkout master
+ $ git checkout -b feature # Create a feature branch
+ $ git commit -m '...' # Make a commit
+ $ arc diff master # Send changes since master for review
+ $ git commit -m '...' # Make more changes
+ $ git commit -m '...'
+ $ arc diff master # Update the revision
+
+Once the revision has been accepted:
+
+ $ git checkout master # Checkout master
+ $ arc merge feature # Merge your feature branch with "arc merge" to
+ # generate a rich merge commit.
+
+Now you can ##git push## or similar.
+
+=== Git: Liberal Mutability Doctrine ===
+
+This section assumes you are using git with a **liberal history mutability
+doctrine** and have set ##"immutable_history" : false## in your ##.arcconfig##.
+
+Under a liberal mutability doctrine, arc will read revision information from
+your commit message. Use a commit template similar to this one:
arcanist/resources/git/commit-template.txt
The easiest way to set up the template is to check it into your repository
somewhere and then add this to your ##.git/config## file:
[commit]
template = path/to/template.txt
You can also configure it globally, consult the git documentation for details.
To **create a revision** in git:
$ nano source_code.c # Make changes.
$ git commit -a # Fill out the template.
- $ arc diff
+ $ arc diff origin/master # Send changes from the origin for review.
To **update a revision** in git by amending HEAD:
$ nano source_code.c # Make changes.
$ git commit -a --amend # Amend into HEAD.
- $ arc diff
+ $ arc diff origin/master # Send changes from the origin for review.
To **update a revision** in git by stacking local commits:
$ nano source_code.c # Make changes.
$ git commit -a -m '...' # Make another local commit.
- $ arc diff HEAD^^ # Update with the last two changes.
+ $ arc diff origin/master # Send changes from the origin for review.
To **create and update a revision** using feature branches:
$ git checkout master
$ git checkout -b feature # Create a branch.
$ nano source_code.c # Make changes.
$ git commit -a # Fill out the template.
$ arc diff master # Diff changes between here and branch 'master'
$ nano source_code.c # Make more changes.
$ git commit -a -m '...' # Or you can amend.
$ arc diff master # Updates the diff.
Once your revision has been accepted, use ##arc amend## to finalize it.
- $ arc amend # If you used an --amend workflow.
-
-If you used a multiple-commit workflow, you need to squash commits first with
-##git rebase -i## or similar, then amend the squashed commit.
+ $ git rebase -i # Squash commits if necessary.
+ $ arc amend # Update HEAD with final revision information.
After amending, you can push the commit to the remote with ##git push## or
##git svn dcommit## or via whatever other channel your project uses as
applicable.
+
+== Mercurial ==
+
+Mercurial works similarly to git's immutable history doctrine.
+
+To **create or update** a revision in Mercurial:
+
+ $ hg commit -m '...' # Create a commit
+ $ arc diff # Creates or updates a revision with outgoing changes
+ # on this branch.
+
+Once a revision has been accepted, you can finalize it with ##arc merge##:
+
+ $ arc merge # Works like "hg merge && hg commit" but gives you a
+ # rich commit message.
+
+This won't work if there are no remote changes on your branch, since the merge
+is linear. In this case, just skip this step. You can now "hg push" or similar.

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 17:12 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1126836
Default Alt Text
(15 KB)

Event Timeline