The branch main has been updated by dteske: URL: https://cgit.FreeBSD.org/src/commit/?id=f86c3e6de4795cb8b44d104635eb39e1f63209b4
commit f86c3e6de4795cb8b44d104635eb39e1f63209b4 Author: Devin Teske <[email protected]> AuthorDate: 2026-08-25 20:46:32 +0000 Commit: Devin Teske <[email protected]> CommitDate: 2026-08-25 20:46:32 +0000 git-arc: Handle -h on subcommands and align usage with the man page git-sh-setup treats -h as help against an empty USAGE, so "git arc create -h" prints "usage: git arc". Handle -h before sourcing it so every subcommand prints the real synopsis. The create, stage, and update synopses showed optional commit-refs while git-arc(1) and the code require them. Advertise -p parent on create; the option was already implemented and documented. Sort create sub-command option-arguments alphabetically in three places: (1) synopsis from tool, (2) man-page synopsis, and (3) man-page description. Check for jq(1) / arc after checking for usage so -h always works. While here, fix missing "local o" in gitarc__stage(). Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D59129 --- tools/tools/git/git-arc.1 | 27 +++--- tools/tools/git/git-arc.sh | 209 ++++++++++++++++++++++++++++++++------------- 2 files changed, 165 insertions(+), 71 deletions(-) diff --git a/tools/tools/git/git-arc.1 b/tools/tools/git/git-arc.1 index 218d852db984..d6b9ed686aaa 100644 --- a/tools/tools/git/git-arc.1 +++ b/tools/tools/git/git-arc.1 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 20, 2026 +.Dd August 23, 2026 .Dt GIT-ARC 1 .Os .Sh NAME @@ -32,28 +32,31 @@ .Nd a wrapper to improve integration between git and arcanist .Sh SYNOPSIS .Nm +.Fl h +.Nm .Cm create -.Op Fl dl +.Op Fl dhl +.Op Fl p Ar parent .Op Fl r Ar reviewer1 Ns Op Cm \&, Ns Ar reviewer2 ... .Op Fl s Ar subscriber1 Ns Op Cm \&, Ns Ar subscriber2 ... .Op Fl t Ar tag1 Ns Op Cm \&, Ns Ar tag2 ... -.Op Fl p Ar parent .Ar commit-ref Op Ar commit-ref ... .Nm -.Cm diff Ar commit-ref Op Ar commit-ref ... +.Cm diff Oo Fl h Oc Ar commit-ref Op Ar commit-ref ... .Nm -.Cm list Ar commit-ref Op Ar commit-ref ... +.Cm list Oo Fl h Oc Ar commit-ref Op Ar commit-ref ... .Nm .Cm patch -.Op Fl bcrs +.Op Fl bchrs .Ar diff1 Op Cm Ar diff2 Op Ar ... .Nm .Cm stage +.Op Fl h .Op Fl b Ar branch .Ar commit-ref Op Ar commit-ref ... .Nm .Cm update -.Op Fl l +.Op Fl hl .Op Fl m Ar message .Ar commit-ref Op Ar commit-ref ... .Sh DESCRIPTION @@ -104,9 +107,15 @@ In this mode, notifications are not sent to reviewers and subscribers until the review is published via the web UI. The draft is still visible to anyone with the URL (or able to guess it), but the review's visibility settings can be modified before publishing. +.It Fl h +Print usage statement and exit. .It Fl l Before processing commit(s) display list of commits to be processed and wait for confirmation. +.It Fl p Ar parent +Specify the parent of the first commit in the list. +This is useful when adding more commits on top of an already existing +stack in Phabricator. .It Fl r Ar reviewer Add one or more reviewers, separated by commas, to revision(s) being created. Each argument must be an existing Phabricator user or group. @@ -123,10 +132,6 @@ Unlike group reviewers, a leading is optional and is added if omitted. Spaces in tag names should be replaced with underscores .Pq e.g., Src_committers for the Do Src Committers Dc tag . -.It Fl p Ar parent -Specify the parent of the first commit in the list. -This is useful when adding more commits on top of an already existing -stack in Phabricator. .El .It Cm diff Show the differences between the specified commits and their associated diff --git a/tools/tools/git/git-arc.sh b/tools/tools/git/git-arc.sh index edaa7a62d846..07ce6539634a 100755 --- a/tools/tools/git/git-arc.sh +++ b/tools/tools/git/git-arc.sh @@ -55,15 +55,16 @@ cleanup() err_usage() { cat >&2 <<__EOF__ -Usage: git arc [-vy] <command> <arguments> +Usage: git arc [-hvy] <command> <arguments> Commands: - create [-dl] [-r <reviewer1>[,<reviewer2>...]] [-s subscriber[,...]] [<commit>|<commit range>] - diff <commit>|<commit range> - list <commit>|<commit range> - patch [-bcrs] <diff1> [<diff2> ...] - stage [-b branch] [<commit>|<commit range>] - update [-l] [-m message] [<commit>|<commit range>] + create [-dhl] [-p parent] [-r <reviewer1>[,<reviewer2>...]] \\ + [-s subscriber[,...]] [-t tag[,...]] <commit>|<commit range> + diff [-h] <commit>|<commit range> + list [-h] <commit>|<commit range> + patch [-bchrs] <diff1> [<diff2> ...] + stage [-h] [-b branch] <commit>|<commit range> + update [-hl] [-m message] <commit>|<commit range> See git-arc(1) for details. __EOF__ @@ -86,6 +87,65 @@ get_bool_config() test "$(git config --bool --get $1 2>/dev/null || echo $2)" != "false" } +# +# Per-subcommand initialization, invoked only after that sub-command's getopts +# loop and arity check have succeeded. git-sh-setup treats leading -h as help +# against empty USAGE, so must not be sourced until getopts has distinguished +# a usage request from an option argument (for example, "create -t -h"). Same +# delay skips jq(1) / arc checks when user only asked for usage. +# +# Invoke with no arguments because git-sh-setup inspects $1 (only for `-h') +# and sourcing inherits this function's args (empty $1 keeps its help check +# inert). Helpers it defines (require_clean_work_tree, git_pager) available +# only after this returns. +# +setup() +{ + [ -x "${ARC_CMD}" ] || err "arc is required, install devel/arcanist-lib" + which jq >/dev/null 2>&1 || err "jq is required, install textproc/jq" + + if [ "$VERBOSE" ]; then + exec 3>&1 + else + exec 3> /dev/null + fi + + # Pull in some git helper functions. + git_sh_setup=$(git --exec-path)/git-sh-setup + [ -f "$git_sh_setup" ] || err "cannot find git-sh-setup" + SUBDIRECTORY_OK=y + USAGE= + # shellcheck disable=SC1090 + . "$git_sh_setup" + + # git commands use GIT_EDITOR instead of EDITOR, so try to provide consistent + # behaviour. Ditto for PAGER. This makes git-arc play nicer with editor + # plugins like vim-fugitive. + if [ -n "$GIT_EDITOR" ]; then + EDITOR=$GIT_EDITOR + fi + if [ -n "$GIT_PAGER" ]; then + PAGER=$GIT_PAGER + fi + + # Bail if the working tree is unclean, except for "diff", "list" and + # "patch" operations. + case $verb in + diff|list|patch) + ;; + *) + require_clean_work_tree "$verb" + ;; + esac + + if get_bool_config arc.browse false; then + BROWSE=--browse + fi + + GITARC_TMPDIR=$(mktemp -d) || exit 1 + trap cleanup EXIT HUP INT QUIT TRAP USR1 TERM +} + # # Invoke the actual arc command. This allows us to only rely on the # devel/arcanist-lib port, which installs the actual script, rather than @@ -411,6 +471,8 @@ build_commit_list() gitarc__create() { + local OPTIND=1 OPTARG + # NB: reviewers / subscribers / tags not initialized; inheritance allowed. local commit commits doprompt draft list o prev reviewers subscribers local tags @@ -419,9 +481,8 @@ gitarc__create() if get_bool_config arc.list false; then list=1 fi - doprompt=1 draft=0 - while getopts dlp:r:s:t: o; do + while getopts dhlp:r:s:t: o; do case "$o" in d) draft=1 @@ -448,8 +509,17 @@ gitarc__create() done shift $((OPTIND-1)) + # NB: Earlier check of $# in main may have been duped by option-flags. + if [ $# -eq 0 ]; then + warn "Too few arguments" + err_usage + fi + + setup + commits=$(build_commit_list "$@") + doprompt=1 if [ "$list" ]; then for commit in ${commits}; do git --no-pager show --oneline --no-patch "$commit" @@ -479,8 +549,23 @@ gitarc__create() # gitarc__diff() { + local OPTIND=1 OPTARG o local commit commits diff rawdiff rtree + while getopts h o; do + case "$o" in + *) + err_usage + ;; + esac + done + shift $((OPTIND-1)) + + # NB: Earlier check of $# in main enough to ensure sufficient args. + # NB: If any option-flags besides -h are added, add re-check of $#. + + setup + commits=$(build_commit_list "$@") for commit in $commits; do @@ -507,8 +592,23 @@ gitarc__diff() gitarc__list() { + local OPTIND=1 OPTARG o local chash commit commits diff openrevs title + while getopts h o; do + case "$o" in + *) + err_usage + ;; + esac + done + shift $((OPTIND-1)) + + # NB: Earlier check of $# in main enough to ensure sufficient args. + # NB: If any option-flags besides -h are added, add re-check of $#. + + setup + commits=$(build_commit_list "$@") openrevs=$(arc_list --ansi) @@ -731,20 +831,19 @@ apply_rev() gitarc__patch() { + local OPTIND=1 OPTARG local branch commit o raw rev stack branch=false commit=false raw=false stack=false - while getopts bcrs o; do + while getopts bchrs o; do case "$o" in b) - require_clean_work_tree "patch -b" branch=true ;; c) - require_clean_work_tree "patch -c" commit=true ;; r) @@ -760,13 +859,22 @@ gitarc__patch() done shift $((OPTIND-1)) + # NB: Earlier check of $# in main may have been duped by option-flags. if [ $# -eq 0 ]; then + warn "Too few arguments" err_usage fi + setup + if ${branch}; then + require_clean_work_tree "patch -b" patch_branch "$@" fi + if ${commit}; then + require_clean_work_tree "patch -c" + fi + for rev in "$@"; do echo "Applying ${rev}..." apply_rev $rev $commit $raw $stack @@ -775,10 +883,11 @@ gitarc__patch() gitarc__stage() { + local OPTIND=1 OPTARG o local author branch commit commits diff reviewers title tmp branch=main - while getopts b: o; do + while getopts b:h o; do case "$o" in b) branch="$OPTARG" @@ -790,6 +899,14 @@ gitarc__stage() done shift $((OPTIND-1)) + # NB: Earlier check of $# in main may have been duped by option-flags. + if [ $# -eq 0 ]; then + warn "Too few arguments" + err_usage + fi + + setup + commits=$(build_commit_list "$@") if [ "$branch" = "main" ]; then @@ -823,14 +940,15 @@ gitarc__stage() gitarc__update() { + local OPTIND=1 OPTARG + # NB: msg / have_msg not initialized; inheritance allowed. local commit commits diff doprompt have_msg list o msg list= if get_bool_config arc.list false; then list=1 fi - doprompt=1 - while getopts lm: o; do + while getopts hlm: o; do case "$o" in l) list=1 @@ -846,8 +964,17 @@ gitarc__update() done shift $((OPTIND-1)) + # NB: Earlier check of $# in main may have been duped by option-flags. + if [ $# -eq 0 ]; then + warn "Too few arguments" + err_usage + fi + + setup + commits=$(build_commit_list "$@") + doprompt=1 if [ "$list" ]; then for commit in ${commits}; do git --no-pager show --oneline --no-patch "$commit" @@ -886,7 +1013,7 @@ if get_bool_config arc.assume-yes false; then fi VERBOSE= -while getopts vy o; do +while getopts hvy o; do case "$o" in v) VERBOSE=1 @@ -901,21 +1028,17 @@ while getopts vy o; do done shift $((OPTIND-1)) -[ $# -ge 1 ] || err_usage - -[ -x "${ARC_CMD}" ] || err "arc is required, install devel/arcanist-lib" -which jq >/dev/null 2>&1 || err "jq is required, install textproc/jq" - -if [ "$VERBOSE" ]; then - exec 3>&1 -else - exec 3> /dev/null +# NB: Only catches if neither option-flags nor sub-command. +if [ $# -eq 0 ]; then + warn "Too few arguments" + err_usage fi case "$1" in create|diff|list|patch|stage|update) ;; *) + warn "Unrecognized sub-command: $1" err_usage ;; esac @@ -924,42 +1047,8 @@ shift # All subcommands require at least one parameter. if [ $# -eq 0 ]; then + warn "Too few arguments" err_usage fi -# Pull in some git helper functions. -git_sh_setup=$(git --exec-path)/git-sh-setup -[ -f "$git_sh_setup" ] || err "cannot find git-sh-setup" -SUBDIRECTORY_OK=y -USAGE= -# shellcheck disable=SC1090 -. "$git_sh_setup" - -# git commands use GIT_EDITOR instead of EDITOR, so try to provide consistent -# behaviour. Ditto for PAGER. This makes git-arc play nicer with editor -# plugins like vim-fugitive. -if [ -n "$GIT_EDITOR" ]; then - EDITOR=$GIT_EDITOR -fi -if [ -n "$GIT_PAGER" ]; then - PAGER=$GIT_PAGER -fi - -# Bail if the working tree is unclean, except for "diff", "list" and -# "patch" operations. -case $verb in -diff|list|patch) - ;; -*) - require_clean_work_tree "$verb" - ;; -esac - -if get_bool_config arc.browse false; then - BROWSE=--browse -fi - -GITARC_TMPDIR=$(mktemp -d) || exit 1 -trap cleanup EXIT HUP INT QUIT TRAP USR1 TERM - gitarc__"${verb}" "$@"
