From nobody Tue Aug 25 20:48:48 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hV0Hh5Rqrz6q1nX for ; Tue, 25 Aug 2026 20:48:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hV0Hh4YHhz3NT1 for ; Tue, 25 Aug 2026 20:48:48 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787690928; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QFs/QX7R4juBJNBW3WLyeZNp7Rn9l0HgSxDNo6+NQ/k=; b=H6b3HtefrCX/XIHbI8igy91bVqpjoceHaDzvzXKsaTJ9rPgqGDkk89FXjsZX1GolrTiBFw wAXbhuJuS20wJ2E2B8wdegMSSJ8qjR6LuDhUvaeoN88PgDMmKx5ij4ZtSI+t7dGTe14EtT CZ2SDdnKSoGKBuuhfLmMoW6F5pu7tijBojdp7KNoK+cL2yidD8jxmqhc11p6Y6JmYxnYjV ZoU749TA02JZwKVV7SYsQL+sesxEQ6gFJ8EgeRjELt6tdkPJEonrt1pDfze3xUdwyfLuO0 v1OM9WuNVShUuKlCnFM0hurNpUxD+KqOq10vbrE/DmQ3WS8nDjc9zsS99B+BCw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1787690928; a=rsa-sha256; cv=none; b=ZGnz4BVsjscycTTqNuhDPmQF8N+dwCJ9sZ2UnkTnwT5jo26Pofxj1bOaJL7CY2TAdgq9sf yQv3rMG7NUhHQK/utBM6isG+E6wyd/7qeemgeMz+a6v1BT3x8E9DR4cObJed0FYOZffsZE fSmVU7Evr/71brAauGw8CmoTyOZJAH732opYIKuXmEIZWziUqUvADjsWrtfQ9Xm7d8Osra OQUGmBumny8+skQb+g0/Ju+ssmhgPF1+VrZecd/zwQLcTLI0AcBsh5TZzd0XLn74z0QYjq hkzcKSl25P7+tgFQ0eXzpSzyEj2pew6lvHczDH7mD5EeQa2tbvQZ6sp4s8LgoA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787690928; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QFs/QX7R4juBJNBW3WLyeZNp7Rn9l0HgSxDNo6+NQ/k=; b=PwErzw5nEF/I/zfQ4jCEIOFXV9BQjD1URCpZzJi61XJsxT/WoA1mDIOzhdcqdsdh25dPo+ 66HM2jlxb7jp7/Y33U5nymDMvBtM/OLiIebOCezehUlOjQExYGRMoOpZjXWl9owndyMF6I 9s1SPFntHwrcVaHUf5WNbKbQZwtKWJBlFbHZcwDZPvcWX1w7a2XcpdNK5opjcZCDnlrK5y VQmfveUdVD7+zY+ADVd+OP2K5BHPW8C2q13o2zQJYaCTweuhmZ9mObUSxJ2VZGjzo87gzN dPess3P50Xdt6K7qdXvJZX00+qL8TFVz6cBRKNSKg+DXFy3JqxVh1jsMBOqJoQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hV0Hh3SnWz16j9 for ; Tue, 25 Aug 2026 20:48:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1f553 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 25 Aug 2026 20:48:48 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Devin Teske Subject: git: f86c3e6de479 - main - git-arc: Handle -h on subcommands and align usage with the man page List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dteske X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: f86c3e6de4795cb8b44d104635eb39e1f63209b4 Auto-Submitted: auto-generated Date: Tue, 25 Aug 2026 20:48:48 +0000 Message-Id: <6a8dffb0.1f553.6c15e91@gitrepo.freebsd.org> The branch main has been updated by dteske: URL: https://cgit.FreeBSD.org/src/commit/?id=f86c3e6de4795cb8b44d104635eb39e1f63209b4 commit f86c3e6de4795cb8b44d104635eb39e1f63209b4 Author: Devin Teske AuthorDate: 2026-08-25 20:46:32 +0000 Commit: Devin Teske 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] +Usage: git arc [-hvy] Commands: - create [-dl] [-r [,...]] [-s subscriber[,...]] [|] - diff | - list | - patch [-bcrs] [ ...] - stage [-b branch] [|] - update [-l] [-m message] [|] + create [-dhl] [-p parent] [-r [,...]] \\ + [-s subscriber[,...]] [-t tag[,...]] | + diff [-h] | + list [-h] | + patch [-bchrs] [ ...] + stage [-h] [-b branch] | + update [-hl] [-m message] | 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}" "$@"