[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/docs/user/userguide/ -> arcanist_commit_ranges.diviner (source)

   1  @title Arcanist User Guide: Commit Ranges
   2  @group userguide
   3  
   4  Explains how commit ranges work in Arcanist.
   5  
   6  This is an advanced user guide which covers a complicated topic in detail. If
   7  you're just getting started, you don't need to look at this yet. Instead, start
   8  with the @{article:Arcanist User Guide}.
   9  
  10  = Overview =
  11  
  12  //In Subversion, `arc` commands always operate on the uncommitted changes in the
  13  working copy. If you use Subversion, this document is not relevant to you.//
  14  
  15  In Git and Mercurial, many `arc` commands (notably, `arc diff`) operate on a
  16  range of commits beginning with some commit you specify and ending with the
  17  working copy state.
  18  
  19  Since the end of the range is fixed (the working copy state), you only need to
  20  specify the beginning of the range. This is called the "base commit". You can do
  21  this explicitly when you run commands:
  22  
  23    $ arc diff HEAD^ # git: just the most recent commit
  24    $ arc diff .^    #  hg: just the most recent commit
  25  
  26  You can also configure `arc` so it defaults to some base commit, or figures out
  27  the base commit using a (potentially sophisticated) ruleset.
  28  
  29  NOTE: This document describes a new mechanism for determining base commits. It
  30  is subject to change. There are currently several other mechanisms available as
  31  well, mentioned in other documents. As this mechanism matures, it should replace
  32  other mechanisms and defaults.
  33  
  34  = Configuring Base Commit Rules =
  35  
  36  Base commit rule configuration may be more complicated than you expect. This is
  37  because people use many different workflows in Git and Mercurial, and have very
  38  different expectations about what base commit `arc` should pick when run. To
  39  make matters worse, some of the most common ways of thinking about which commits
  40  represent a change are incompatible when selecting defaults.
  41  
  42  Historically, we tried to use a number of heuristics and simpler approaches to
  43  determine the base commit, but there is so much diversity in how people think
  44  about version control and what they expect to happen that some users were always
  45  unhappy.
  46  
  47  Although ruleset configuration is fairly complex, it's powerful enough that you
  48  should be able to get exactly the behavior you want.
  49  
  50  To determine the base commit, `arc` processes //rules// one at a time until it
  51  gets a match (a rule which identifies a valid commit). The first match is the
  52  base commit that is used to determine the beginning of the commit range.
  53  
  54  A //rule// looks like this:
  55  
  56    arc:upstream
  57  
  58  A rule may //match//, meaning that it identifies some valid commit in the
  59  working copy, or //fail//, meaning that it does not identify a valid commit. For
  60  instance, the rule `arc:upstream` will //match// if the current Git branch
  61  tracks an upstream branch, but //fail// if the current Git branch does not track
  62  an upstream branch, or the working copy isn't a Git working copy. When a rule
  63  fails, processing continues with the next rule. Some rules can never match but
  64  produce useful side effects instead. These are described below.
  65  
  66  A //ruleset// is a comma-separated list of rules:
  67  
  68    arc:upstream, arc:prompt
  69  
  70  `arc` reads five rulesets:
  71  
  72    # `args`, specified with `--base <ruleset>` on the command line when you run
  73      a command. This ruleset is processed first.
  74    # `local`, specified with `arc set-config --local base <ruleset>`. This
  75      ruleset is local to the working copy where it is set, and is processed
  76      second.
  77    # `project`, specified by setting the "base" key in `.arcconfig`. This
  78      ruleset is bound to the project where it is configured, and is processed
  79      third.
  80    # `global`, specified with `arc set-config base <ruleset>`. This ruleset is
  81      global for the current user, and is processed fourth.
  82    # `system`, specified in a system-wide configuration file. This ruleset is
  83      global for all users on the system, and is processed last.
  84  
  85  The rules in each ruleset are processed one at a time until a valid base commit
  86  is found. Valid rules are listed below. In this list, "*" means "any string".
  87  
  88    - `git:*` Use the specified symbolic commit, if it exists.
  89    - `git:merge-base(*)` Use the merge-base of HEAD and the specified symbolic
  90      commit, if it exists.
  91    - `git:branch-unique(*)` Attempt to select changes unique to this branch (that
  92      is, changes between the branch point and HEAD). This rule is complicated and
  93      has limitations, see below for a detailed description.
  94    - `hg:*` Use the specified symbolic commit, if it exists.
  95    - `hg:gca(*)` Use the greatest common ancestor of `.` and the specified
  96       symbolic commit, if it exists.
  97    - `arc:upstream` Use the merge-base of the current branch's upstream and
  98       HEAD, if it exists. (git-only)
  99    - `arc:outgoing` Use the most recent non-outgoing ancestor of the working
 100       copy parent. (hg-only)
 101    - `arc:exec(*)` Execute the specified command. The command should determine
 102      the base revision to use and print it to stdout, then exit with return code
 103      0. If the command exits with another return code, the rule will fail. The
 104      command will be executed with the root directory of the working copy as the
 105      current working directory.
 106    - `arc:bookmark` Use the most recent non-outgoing ancestor of the working
 107       copy parent or the most recent bookmark, whichever is more recent. This
 108       rule is complicated and has limitations, see below for a detailed
 109       description.
 110    - `arc:amended` Use the current commit (`HEAD` in Git, or `.` in Mercurial) if
 111      it has been amended to include a "Differential Revision:" field. Otherwise,
 112      fail.
 113    - `arc:prompt` Prompt the user to provide a commit.
 114    - `arc:empty` Use the empty state (as though the repository were completely
 115      empty, the range will include every commit that is an ancestor of the
 116      working copy).
 117    - `arc:this` Use the current commit. This means `.` under Mercurial and HEAD
 118      under Git.
 119  
 120  Rules are also available which change the processing order of rulesets:
 121  
 122    - `arc:args`, `arc:local`, `arc:project`, `arc:global`, `arc:system` Stop
 123      processing the current ruleset and begin processing the specified ruleset.
 124      The current ruleset will resume processing after the specified ruleset is
 125      exhausted.
 126    - `arc:yield` Stop processing the current ruleset and begin processing the
 127      next ruleset. The current ruleset will resume processing after other
 128      rulesets have processed or when it next appears in the processing order,
 129      whichever comes first.
 130    - `arc:halt` Stops processing all rules. This will cause the command you ran
 131      to fail, but can be used to avoid running rules which would otherwise
 132      be processed later.
 133  
 134  Additionally, there are some rules which are probably useful mostly for testing
 135  or debugging rulesets:
 136  
 137    - `arc:verbose` Turns on verbose logging of rule processing.
 138    - `arc:skip` This rule has no effect.
 139    - `literal:*` Use the specified commit literally. Almost certainly wrong in
 140      production rules.
 141  
 142  = Examples =
 143  
 144  Diff against `origin/master` if it exists, and prompt if it doesn't:
 145  
 146    git:merge-base(origin/master), arc:prompt
 147  
 148  Diff against the upstream if it exists, or just use the last commit if it
 149  doesn't:
 150  
 151    arc:upstream, git:HEAD^
 152  
 153  As a user, ignore project rules and always use my rules:
 154  
 155    (local) arc:global, arc:halt
 156  
 157  As a project maintainer, respect user rules over project rules:
 158  
 159    (project) arc:yield, <defaults>
 160  
 161  Debug your rules:
 162  
 163    $ arc diff --base arc:verbose
 164  
 165  Understand rules processing:
 166  
 167    $ arc which
 168    $ arc which --base '<ruleset>'
 169    $ arc which --base 'arc:verbose, <ruleset>'
 170  
 171  = Detailed Rule Descriptions =
 172  
 173  Some rules have complex operation, described here in more detail. These rules
 174  are advanced features for expert users wishing to optimize their workflow and
 175  save a little typing. You do not need to understand the behavior of these rules
 176  to use `arc` (you can always specify a base commit explicitly).
 177  
 178  == git:branch-unique(*) ==
 179  
 180  This rule only works in Git.
 181  
 182  This rule tries to find commits that are unique to the current branch. It is
 183  most likely to be useful if you develop using one branch per feature, update
 184  changes by amending commits (instead of stacking commits) and merge changes by
 185  rebasing (instead of merging).
 186  
 187  The rule operates by first determining the merge-base of the specified commit
 188  and HEAD, if it exists. If no such commit exists, the rule fails. If such a
 189  commit exists, the rule counts how many branches contain HEAD, then walks from
 190  HEAD to the merge-base commit, counting how many branches contain each commit.
 191  It stops when it finds a commit which appears on more branches than HEAD,
 192  or when it reaches the merge-base commit.
 193  
 194  This rule works well for trees that look like this:
 195  
 196    |   *  Commit B1, on branch "subfeature" (HEAD)
 197    |  /
 198    | *    Commit A1, on branch "feature"
 199    |/
 200    *      Commit M1, on branch "master"
 201    |
 202  
 203  This tree represents using feature branches to develop one feature ("feature"),
 204  and then creating a sub-branch to develop a dependent feature ("subfeature").
 205  
 206  Normally, if you run `arc diff` on branch "subfeature" (with HEAD at `B1`), a
 207  rule like  `arc:merge-base(master)` will select `M1` as the base commit and thus
 208  incorrectly include `A1` in the commit range.
 209  
 210  For trees like this, `git:branch-unique(master)` will instead select `A1` as the
 211  base commit (because it is the first commit between `B1` and `M1` which appears
 212  on more branches than `B1` -- `B1` appears on only "subfeature" while `A1`
 213  appears on "subfeature" and "feature") and include only `B1` in the commit
 214  range.
 215  
 216  The rule will also do the right thing when run from "feature" in this case.
 217  
 218  However, this rule will select the wrong commit range in some cases. For
 219  instance, it will do the wrong thing in this tree:
 220  
 221    |
 222    | *    Commit A2, on branch "feature" (HEAD)
 223    | |
 224    | | *  Commit B1, on branch "subfeature"
 225    | |/
 226    | *    Commit A1, on branch "feature"
 227    |/
 228    *      Commit M1, on branch "master"
 229    |
 230  
 231  This tree represents making another commit (`A2`) on "feature", on top of `A1`.
 232  
 233  Here, when `arc diff` is run from branch "feature" (with HEAD at `A2`), this
 234  rule will incorrectly select only `A2` because `A2` (which is HEAD) appears on
 235  one branch ("feature") while `A1` appears on two branches ("feature",
 236  "subfeature").
 237  
 238  You can avoid this problem by amending changes into `A1` instead of adding new
 239  commits, or by rebasing "subfeature" before running `arc diff`.
 240  
 241  This rule will also select the wrong commit range in a tree like this:
 242  
 243    |
 244    | *    Commit A1', on branch "feature", created by amending A1
 245    | |
 246    | | *  Commit B1, on branch "subfeature" (HEAD)
 247    | |/
 248    | o    Commit A1, no longer on "feature" but still on "subfeature"
 249    |/
 250    *      Commit M1, on branch "master"
 251    |
 252  
 253  This tree represents amending `A1` without rebasing "subfeature", so that `A1`
 254  is no longer on "feature" (replaced with `A1'`) but still on "subfeature". In
 255  this case, running `arc diff` from "subfeature" will incorrectly select both
 256  `B1` and `A1`, because they now are contained by the same number of branches.
 257  
 258  You can avoid this problem by rebasing sub-branches before running `arc diff`,
 259  or by using a rule like `arc:amended` before `git:branch-unique(*)`.
 260  
 261  == arc:bookmark ==
 262  
 263  This rule only works in Mercurial.
 264  
 265  This rule finds outgoing changes, but stops when it encounters a bookmark. It is
 266  most likely to be useful if you use one bookmark per feature.
 267  
 268  This rule operates like `arc:outgoing`, but then walks the commits between
 269  `.` and the selected base commit. It stops when it encounters a bookmark. For
 270  example, if you have a tree like this:
 271  
 272    |
 273    | *  C4 (outgoing, bookmark: stripes)
 274    | |
 275    | *  C3 (outgoing, bookmark: zebra)
 276    | |
 277    | *  C2 (outgoing, no bookmark)
 278    |/
 279    *    C1 (pushed, no bookmark)
 280    |
 281  
 282  When run from `C4`, this rule will select just `C4`, stopping on `C3` because
 283  it has a different bookmark. When run from `C3`, it will select `C2` and `C3`.
 284  
 285  However, this rule will select the wrong commit range in some cases (for
 286  example, if the "zebra" bookmark has moved on, the rule will no longer stop on
 287  `C3` and will select `C2`, `C3` and `C4` when run from `C4`).
 288  
 289  == arc:exec(*) ==
 290  
 291  This rule runs some external script or shell command. It is intended for
 292  advanced users who want specialized behavior that can't be expressed with other
 293  rules.
 294  
 295  To use this rule, provide some script or shell command. For example:
 296  
 297    arc:exec(git merge-base origin/master HEAD)
 298    arc:exec(/path/to/some/script.sh)
 299  
 300  The command will be executed with the working copy as its working directory,
 301  and passed no arguments. To //match//, it should print the name of a base commit
 302  on stdout and then exit with return code 0. To //fail//, it should exit with
 303  any other return code.
 304  
 305  = Next Steps =
 306  
 307  Continue by:
 308  
 309    - learning about `arc diff` in more detail with
 310      @{article:Arcanist User Guide: arc diff}; or
 311    - returning to @{article:Arcanist User Guide}.


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1