问题
arc help --full | less
reveals this for graft
:
graft revision
Grafts revision and its dependencies (if any) onto your working tree.
--force
Do not run any sanity checks.
--skip-landed
Do not try to patch landed/closed diffs.
and this for patch
:
patch D12345
patch --revision revision_id
patch --diff diff_id
patch --patch file
patch --arcbundle bundlefile
Supports: git, svn, hg
Apply the changes in a Differential revision, patchfile, or arc
bundle to the working copy.
--arcbundle bundlefile
Apply changes from an arc bundle generated with 'arc export'.
which is vague to me. Using the word "graft" to describe what "graft" means doesn't help me much.
For those who don't know, arc
(Arcanist) is a command-line tool inside of "Phabricator" which acts like a high-level wrapper around Git (or even Mercurial and Subversion) to aid in the development process for large software projects. Here's a few links:
https://phacility.com/phabricator/
Phabricator was originally developed as an internal tool at Facebook.[7][8][9] Phabricator's principal developer is Evan Priestley.[1] Priestley left Facebook to continue Phabricator's development in a new company called Phacility.[2] https://en.wikipedia.org/wiki/Phabricator
回答1:
Update 19 Mar. 2020:
Note that arc flow
and arc cascade
are apparently not part of the mainstream version of Phacility's arcanist. Rather, they are only part of the Uber fork of arcanist. Some of the arc flow
source code is found here, for instance. Additionally, arc cascade
is also only an Uber fork arcanist feature, and some of its arc cascade
source code is found here.
To learn how to install Uber's fork of arcanist in order to begin using these features in your regular git
workflow (you don't need to use any other features of arcanist if not needed), jump to the bottom of this answer.
ORIGINAL ANSWER Jan. 2019:
So, after some experimenting and trial and error, I think I figured it out:
Both arc graft
and arc patch
use git cherry-pick
under the hood, and accomplish similar things. However, they have some subtle differences, and sometimes arc patch
fails and you must use arc graft
with the --skip-landed
flag instead (update: or perhaps arc patch
with the --skip-dependencies
flag will work too?).
Examples:
# cherry-pick their "D999" "diff" (branch) onto your current branch, while creating
# a new single branch for you named "arcpatch-D999", skipping dependencies in case
# they've already landed on the branch (ex: master) you currently have checked out.
arc patch --skip-dependencies D999
OR
# cherry-pick their "D999" "diff" (branch), *as well as all parent branch(es) it
# depends on*, onto your current branch, while creating the entire dependency tree
# of branches for you, exactly as the submitter originally had on their local
# machine, skipping any commits that have already landed on your local branch
# (ex: master) you currently have checked out
arc graft --skip-landed D999
Imagine your arc flow
dependency tree only contains the "master" branch:
master
A coworker, however, has the following arc flow
dependency tree:
master
└──new_feature_1
└──new_feature_2
Short aside: what's an arc flow
dependency tree? Ans: it is a tree structure, shown via the arc flow
command, which shows which branches depend on what. It is a somewhat arbitrary thing that you as a human are tracking manually, since you know that one feature depends on another. To establish a "dependency", you have two options:
- Call
arc flow new_branch_name
to create a new child branch while you have currently checked-out the branch you want to be the parent, OR: Use git to create a new branch, then set its upstream to what you want to be the parent. Ex:
git branch new_branch_name git checkout new_branch_name # Or use `git checkout -b new_branch_name` to do both at once git branch --set-upstream-to=upstream_branch_name # or `git branch -u upstream_branch_name` for short
Now, arc flow
will show your dependency tree. This allows you to to things like arc cascade
from a parent down to its children, which is just doing automated recursive git rebases from parents down to children (ie: rebasing children onto parents).
End of aside.
Anyway, with the dependency tree shown above, your coworker has "new_feature_2" checked out, and they arc diff
it for you to review. You go to the web-based "Differential" tool and start reviewing the change. However, you want to test it. This means you need to pull their diff to your local machine. You have two options: 1. arc patch
their diff (dependency-tree-aware branch) onto your local master, or 2. arc graft
their diff onto your local master.
Assuming their diff is "D999", and you currently have your "master" branch checked-out, your commands and resulting dependency trees would look as follows:
arc patch D999
. You now have this tree, where your newly-created "arcpatch-D999" is their "new_feature_2" branch:master └──arcpatch-D999
arc graft D999
. You now have this tree, just like they have:master └──new_feature_1 └──new_feature_2
However, (I think, based on my problems) that sometimes when they have a multi-generation dependency tree like this, arc patch
will fail (giving an error that says "Cherry Pick Failed!"), and in such a case you must use arc graft
instead! HOWEVER, if their master is NOT the exact same as your master (which is almost certainly will NOT be, since they probably pulled their master a while back and you should have just pulled yours to ensure you have the latest), then your attempts to graft or patch will fail. It is likely the failures will be related to the fact that some of the commits in their branch history contain changes which are already landed and present in your master. The solution is to use arc graft D999 --skip-landed
, which will allow you to grab their diff and pull it down, mirroring their arc flow
dependency tree. In such a case, arc patch D999
will likely continue to fail until they pull the latest master and arc cascade
(or git rebase twice), then re-arc diff
to push their changes to the server, at which point you can then arc patch D999
onto your master successfully. Since you can't always get them to rebase/arc cascade
immediately, however, just do the arc graft D999 --skip-landed
now and be done! Let them rebase and re-arc diff
when they get to it.
One minor problem, however, is that if you are arc graft
ing much, it can get confusing who made which branches (you, or someone else?), so I recommend you get into the habit of grafting onto a new branch you name yourself, as follows, just for organization:
git checkout master # same as `arc flow master`
git pull origin master # pull latest master
arc flow graft-D999 # create and checkout a new child branch you are calling "graft-D999" (name it appropriately)
arc graft D999 --skip-landed # graft their entire dependency tree onto your branch "graft-D999"
Your dependency tree will now be as follows:
master
└──graft-D999
└──new_feature_1
└──new_feature_2
Excellent! Nice and organized. Now you can check out "new_feature_2" and compile and test it. Note, however, that "master" and "graft-D999" will be exactly identical branches, but that's ok.
How to install Uber's fork of arcanist
(in case you'd like to start using arc flow
and arc cascade
in your own git work-flows):
Note: Arcanist runs on Windows (inside the git for Windows git bash terminal), Mac, and Linux. I'll just present the Linux installation instructions. To get help on installing in other systems start by seeing the References below.
Linux Ubuntu installation:
cd
to where you'd like the installation files to live, then do the following:
# 1. Obtain the Uber fork of the arcanist program by cloning it into an "uber" directory.
mkdir uber
git clone https://github.com/uber/arcanist.git uber
# 2. Symbolically link the `arc` program to your ~/bin directory so you can call `arc` from anywhere.
# - this assumes that ~/bin is in your PATH.
# Ensure the ~/bin dir exists; if just creating this dir for the first time you may need to log out of Ubuntu
# and log back in AFTER running the `mkdir` command below, in order to force your ~/.profile script to
# automatically add ~/bin to your PATH (assuming your ~/.profile script does this, as default Ubuntu scripts do).
mkdir -p ~/bin
ln -s $PWD/uber/arcanist/bin/arc ~/bin
Now try to run arc
. It should fail with the following message:
$ arc
ERROR: Unable to load libphutil. Put libphutil/ next to arcanist/, or update your PHP 'include_path' to include the parent directory of libphutil/, or symlink libphutil/ into arcanist/externals/includes/.
So, do the following:
# 3. Obtain the libphutil program.
# - Note that git cloning it like this `git clone https://github.com/phacility/libphutil.git` will NOT work anymore
# for Uber's fork of arcanist because the libphutil project is now empty. So, do this instead:
sudo apt install libphutil
# 4. symbolically link the libphutil program into arcanist.
# First, we need to know where it is installed.
dpkg -L libphutil
# Now look at the output from the above command. Mine shows libphutil is installed in "/usr/share/libphutil/",
# so do the following:
ln -s /usr/share/libphutil uber/arcanist/externals/includes
Now test the arc
command and you should see the following:
$ arc
Usage Exception: No command provided. Try `arc help`.
Run arc help
to see the help menu, or arc help --full
for the full help menu.
Let's grep for flow
and cascade
to prove they are in the help menu for the Uber fork only (but not for the main arcanist):
Grepping for flow
in the full help menu:
$ arc help --full | grep flow
This workflow is primarily useful for writing scripts which integrate
soft version of '' used by other workflows.
flow [options]
flow name [options]
flow name upstream [options]
step in the standard Differential pre-publish code review workflow.
The workflow selects a target branch to land onto and a remote where
Consulting mystical sources of power, the workflow makes a guess
step in the standard Differential pre-publish code review workflow.
The workflow selects a target branch to land onto and a remote where
Consulting mystical sources of power, the workflow makes a guess
code review workflow.
The workflow selects a target branch to land onto and a remote where
And cascade
in the full help menu:
$ arc help --full | grep -A 4 cascade
cascade [--halt-on-conflict] [rootbranch]
Automates the process of rebasing and patching local working branches
and their associated differential diffs. Cascades from current branch
if branch is not specified.
--
Rather than aborting any rebase attempts, cascade will drop the
user
into the conflicted branch in a rebase state.
References:
- Phacility's Arcanist (lacks
arc flow
andarc cascade
features): https://github.com/phacility/arcanist - Uber's fork of Arcanist (has
arc flow
andarc cascade
features added): https://github.com/uber/arcanist - Arcanist User Guide: https://secure.phabricator.com/book/phabricator/article/arcanist/ --> See "Installing Arcanist" section for their instructions on how to install it in Windows, Mac, Linux, or FreeBSD.
- ERROR: Unable to load libphutil
Related:
- Output of git branch in tree like fashion
回答2:
This might be related to git grafts, where you take a commit/revision, and change its parent commit, thus changing the history of a repo.
(although, since Git 2.18, Q2 2018, graft has been superseded by git ref/replace/)
As opposed to patches, which simply create a new commit/revision from an existing diff, adding to the history of a repo.
来源:https://stackoverflow.com/questions/54227968/whats-the-difference-between-arc-graft-and-arc-patch