git-arc: Try to make patching more useful

Add a raw mode, which fetches the patch file and applies it manually
rather than using arc patch.  This is handy because arc patch will
always try to fetch your remotes if it can't find the base commit in
your repo (even if you ask it not to make a commit).  This is basically
unusable in some of my workspaces where I have 20+ remotes configured,
some of which may be unreachable.

Add a stack mode, which causes git-arc to recursively apply parent
revisions, going up the patch stack.  Thus, to apply a full patch stack,
just apply the final patch with -s.

Reviewed by:	ngie
Differential Revision:	https://reviews.freebsd.org/D54403
This commit is contained in:
Mark Johnston 2026-01-05 14:17:11 +00:00
parent 4a1b69ade6
commit 684c762485

View file

@ -59,7 +59,7 @@ Usage: git arc [-vy] <command> <arguments>
Commands:
create [-l] [-r <reviewer1>[,<reviewer2>...]] [-s subscriber[,...]] [<commit>|<commit range>]
list <commit>|<commit range>
patch [-bc] <diff1> [<diff2> ...]
patch [-bcrs] <diff1> [<diff2> ...]
stage [-b branch] [<commit>|<commit range>]
update [-l] [-m message] [<commit>|<commit range>]
@ -226,6 +226,20 @@ diff2phid()
jq -r "select(.response != []) | .response.${diff}.phid"
}
phid2diff()
{
local diff phid
phid=$1
if ! expr "$phid" : 'PHID-DREV-[0-9A-Za-z]*$' >/dev/null; then
err "invalid diff PHID $phid"
fi
diff=$(echo '{"constraints": {"phids": ["'"$phid"'"]}}' |
arc_call_conduit -- differential.revision.search |
jq -r '.response.data[0].id')
echo "D${diff}"
}
diff2status()
{
local diff tmp status summary
@ -244,6 +258,19 @@ diff2status()
printf "%-14s %s\n" "${status}" "${summary}"
}
diff2parents()
{
local dep dependencies diff parents phid
diff=$1
phid=$(diff2phid "$diff")
for dep in $(echo '{"phids": ["'"$phid"'"]}' |
arc_call_conduit -- differential.query |
jq -r '.response[0].auxiliary."phabricator:depends-on"[]'); do
echo $(phid2diff $dep)
done
}
log2diff()
{
local diff
@ -651,13 +678,46 @@ patch_commit()
git commit --author "${author}" --file "$tmp"
}
apply_rev()
{
local commit parent parents raw rev stack
rev=$1
commit=$2
raw=$3
stack=$4
if $stack; then
parents=$(diff2parents "$rev")
for parent in $parents; do
echo "Applying parent ${parent}..."
if ! apply_rev $parent $commit $raw $stack; then
return 1
fi
done
fi
if $raw; then
fetch -o /dev/stdout "https://reviews.freebsd.org/${rev}.diff" | git apply --index
else
arc patch --skip-dependencies --nobranch --nocommit --force $rev
fi
if ${commit}; then
patch_commit $rev
fi
return 0
}
gitarc__patch()
{
local branch commit rev
local branch commit o raw rev stack
branch=false
commit=false
while getopts bc o; do
raw=false
stack=false
while getopts bcrs o; do
case "$o" in
b)
require_clean_work_tree "patch -b"
@ -667,6 +727,12 @@ gitarc__patch()
require_clean_work_tree "patch -c"
commit=true
;;
r)
raw=true
;;
s)
stack=true
;;
*)
err_usage
;;
@ -682,13 +748,8 @@ gitarc__patch()
patch_branch "$@"
fi
for rev in "$@"; do
if ! arc patch --skip-dependencies --nobranch --nocommit --force "$rev"; then
break
fi
echo "Applying ${rev}..."
if ${commit}; then
patch_commit $rev
fi
apply_rev $rev $commit $raw $stack
done
}