From: Phillip Wood <phillip.wood123@gmail.com>
To: domen@cachix.org, git@vger.kernel.org
Cc: gitster@pobox.com, cdwhite3@pm.me, sunshine@sunshineco.com,
ps@pks.im, avarab@gmail.com, test35965@gmail.com,
kristofferhaugsbakk@fastmail.com, maciej.ciemborowicz@gmail.com,
Claude Fable 5 <noreply@anthropic.com>
Subject: Re: [PATCH v3 1/2] worktree: add post-worktree lifecycle hook
Date: Tue, 6 Oct 2026 10:23:19 +0100 [thread overview]
Message-ID: <71131749-b624-4c81-bae2-c32a7d3f1a15@gmail.com> (raw)
In-Reply-To: <2c1c1f06-05e7-4d8c-bd29-c2a9708b443d@mtasv.net>
Hi Domen
On 05/10/2026 00:09, Domen Kožar wrote:
> Tools that manage per-worktree development environments need to observe
> worktrees created, moved, or removed by other programs. Wrapping the
> worktree command only helps when every caller uses the wrapper, and
> post-checkout does not run for add --no-checkout or --orphan.
There is quite a lot of implicit context in that sentance - it assumes
the reader has read the previous discussions about this hook. It would
be clearer if it was explicit that it was talking about (a) using a
wrapper script to perform additional operations around "git worktree"
and (b) using the post-checkout hook as a proxy for detecting when a new
worktree is added.
> There is no notification for moving or removing a worktree.
A wrapper can do that though?
> Add one post-worktree hook for these operations. Pass the event name,
> worktree identifier, old absolute path, and new absolute path as four
> arguments, using an empty string for a path that does not apply.
As I've said before, I don't think the worktree id is very useful
because git commands do not take it as an argument. Someone mentioned
wanting to use it as a key to look up other information about the
worktree, but different repositories can have worktrees with the same id
so I think we'd be better passing the worktree's absolute git-dir.
There was also a comment from someone pointing out that notifying
callers after the worktree is removed maybe too late for them to clean
up the resources associated with that worktree. If we had a
"worktree-event" hook we could run it before the worktree is removed,
but after a worktree is added or moved.
Having four arguments for add and remove seems to me to be unecessarily
complicated - why not just pass the paths that are relavent, rather than
padding the arguments with empty strings?
I see the hook is run serially, is that really necessary?
> An
> explicit event name lets one handler manage the whole lifecycle without
> using argument count to distinguish operations, as the earlier series
> with three separate hooks did.
>
> Run the hook in the invoking repository with its normal environment,
> rather than changing to the affected worktree. Passing both paths lets
> handlers target the new worktree when needed and keeps the execution
> context consistent when a worktree has been removed.
It also means that GIT_DIR and GIT_WORK_TREE are consistent with the
directory that the hook is run in. The downside for adding a worktree is
that the hook needs to clear those variables if it is going to run git
in the new worktree.
> Run the add event after post-checkout even when that hook fails, because
> the worktree remains present. A failing lifecycle hook affects the
> command's exit status without undoing the completed operation.
Ok, that matches what we do with a failing post-checkout hook
> Preserve post-checkout's failure status if both hooks fail.
Ok
> Document the interface and cover ordinary, bare, and linked callers,
> no-checkout and orphan worktrees, relative paths, paths with spaces,
> configured hooks, and hook failures.
I'm not sure why we need separate tests for paths with spaces or orphan
worktrees
I think adding a hook for worktree lifecycle events is a useful
addition. Using a wrapper script is a pain because it is easy to forget
to use it and it is hard to make it work if you have several different
entities that want to be notified about worktrees being added or removed.
Thanks
Phillip
> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
> Signed-off-by: Domen Kožar <domen@cachix.org>
> ---
> Documentation/config/hook.adoc | 1 +
> Documentation/githooks.adoc | 43 +++++++++++
> builtin/worktree.c | 56 ++++++++++----
> t/t2400-worktree-add.sh | 132 +++++++++++++++++++++++++++++++++
> t/t2403-worktree-move.sh | 113 ++++++++++++++++++++++++++++
> 5 files changed, 329 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/config/hook.adoc b/Documentation/config/hook.adoc
> index 083dc60a13..501bb006f5 100644
> --- a/Documentation/config/hook.adoc
> +++ b/Documentation/config/hook.adoc
> @@ -94,6 +94,7 @@ hook.jobs::
> Receive a commit message file and may rewrite it in place.
> `pre-commit`;;
> `post-checkout`;;
> +`post-worktree`;;
> `push-to-checkout`;;
> `post-commit`;;
> Access the working tree, index, or repository state.
> diff --git a/Documentation/githooks.adoc b/Documentation/githooks.adoc
> index 145642bf05..3e25f769c5 100644
> --- a/Documentation/githooks.adoc
> +++ b/Documentation/githooks.adoc
> @@ -215,6 +215,49 @@ This hook can be used to perform repository validity checks, auto-display
> differences from the previous HEAD if different, or set working dir metadata
> properties.
>
> +post-worktree
> +~~~~~~~~~~~~~
> +
> +This hook is invoked by linkgit:git-worktree[1] after a working tree is
> +added, moved, or removed. It takes four parameters: the event (`add`, `move`,
> +or `remove`), the worktree identifier (the name of its administrative
> +directory in `$GIT_COMMON_DIR/worktrees/`), the old absolute path, and the
> +new absolute path.
> +
> +The parameters for each event are:
> +
> + post-worktree add <id> "" <new-path>
> + post-worktree move <id> <old-path> <new-path>
> + post-worktree remove <id> <old-path> ""
> +
> +The empty strings are passed as arguments, so all events have exactly
> +four parameters.
> +
> +The hook runs in the repository where the command was invoked, following
> +the working directory and environment rules described above. It does not
> +change to the added or moved working tree. To run Git commands there,
> +clear the repository environment variables and use the new path, for
> +example:
> +
> +------------
> +(unset $(git rev-parse --local-env-vars); git -C "$4" status)
> +------------
> +
> +The `add` event runs after the new working tree has been set up, including
> +with `--no-checkout` and `--orphan`. It runs after `post-checkout`, even
> +if that hook fails. The `move` event runs after the working tree and its
> +administrative files have been moved. The `remove` event runs after the
> +working tree has been deleted or its administrative entry removed.
> +
> +The hook cannot undo the worktree operation. A non-zero exit status is
> +reflected in the command's exit status, but leaves the completed operation
> +in place. If `post-checkout` fails during `git worktree add`, its exit
> +status takes precedence over that of `post-worktree`.
> +
> +This hook can be used to set up, relocate, or tear down per-worktree
> +development environments, or to maintain registrations with external
> +tools. Hook scripts should ignore events they do not handle.
> +
> post-merge
> ~~~~~~~~~~
>
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 77ecd0f71f..0f2748080c 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -168,6 +168,15 @@ static void delete_worktrees_dir_if_empty(void)
> free(path);
> }
>
> +static int run_post_worktree_hook(const char *event, const char *id,
> + const char *old_path, const char *new_path)
> +{
> + struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;
> +
> + strvec_pushl(&hook_opt.args, event, id, old_path, new_path, NULL);
> + return run_hooks_opt(the_repository, "post-worktree", &hook_opt);
> +}
> +
> static void prune_worktree(const char *id, const char *reason)
> {
> if (show_only || verbose)
> @@ -604,21 +613,30 @@ static int add_worktree(const char *path, const char *refname,
> }
>
> /*
> - * Hook failure does not warrant worktree deletion, so run hook after
> - * is_junk is cleared, but do return appropriate code when hook fails.
> + * Hook failures do not warrant worktree deletion, so run hooks after
> + * is_junk is cleared, but do return appropriate code when a hook
> + * fails.
> */
> - if (!ret && opts->checkout && !opts->orphan) {
> - struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;
> -
> - strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
> - strvec_pushl(&opt.args,
> - oid_to_hex(null_oid(the_hash_algo)),
> - oid_to_hex(&commit->object.oid),
> - "1",
> - NULL);
> - opt.dir = path;
> -
> - ret = run_hooks_opt(the_repository, "post-checkout", &opt);
> + if (!ret) {
> + int hook_ret;
> +
> + if (opts->checkout && !opts->orphan) {
> + struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;
> +
> + strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
> + strvec_pushl(&opt.args,
> + oid_to_hex(null_oid(the_hash_algo)),
> + oid_to_hex(&commit->object.oid),
> + "1",
> + NULL);
> + opt.dir = path;
> +
> + ret = run_hooks_opt(the_repository, "post-checkout", &opt);
> + }
> +
> + hook_ret = run_post_worktree_hook("add", wt->id, "", wt->path);
> + if (!ret)
> + ret = hook_ret;
> }
>
> strvec_clear(&child_env);
> @@ -1305,7 +1323,8 @@ static int move_worktree(int ac, const char **av, const char *prefix,
> struct strbuf dst = STRBUF_INIT;
> struct strbuf errmsg = STRBUF_INIT;
> const char *reason = NULL;
> - char *path;
> + char *old_path, *path;
> + int ret;
>
> ac = parse_options(ac, av, prefix, options, git_worktree_move_usage,
> 0);
> @@ -1348,14 +1367,17 @@ static int move_worktree(int ac, const char **av, const char *prefix,
> errmsg.buf);
> strbuf_release(&errmsg);
>
> + old_path = xstrdup(wt->path);
> if (rename(wt->path, dst.buf) == -1)
> die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
>
> update_worktree_location(wt, dst.buf, use_relative_paths);
> + ret = run_post_worktree_hook("move", wt->id, old_path, wt->path);
>
> + free(old_path);
> strbuf_release(&dst);
> free_worktrees(worktrees);
> - return 0;
> + return ret;
> }
>
> /*
> @@ -1473,6 +1495,8 @@ static int remove_worktree(int ac, const char **av, const char *prefix,
> ret |= delete_git_dir(wt->id);
> delete_worktrees_dir_if_empty();
>
> + ret |= run_post_worktree_hook("remove", wt->id, wt->path, "");
> +
> free_worktrees(worktrees);
> return ret;
> }
> diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh
> index bdcca97633..65fec976b5 100755
> --- a/t/t2400-worktree-add.sh
> +++ b/t/t2400-worktree-add.sh
> @@ -1172,6 +1172,138 @@ test_expect_success '"add" in bare repo invokes post-checkout hook' '
> test_cmp hook.expect goozy/hook.actual
> '
>
> +# Install a post-worktree hook and write the output expected for adding
> +# worktree $1. Repo $2 defaults to "."; the caller worktree is $3.
> +post_worktree_add_hook () {
> + test_when_finished "rm -rf .git/hooks" &&
> + mkdir .git/hooks &&
> + test_hook -C "$2" post-worktree <<-\EOF &&
> + test "$#" = 4 &&
> + {
> + printf "%s\n" "$@" &&
> + test-tool path-utils real_path . &&
> + git rev-parse --absolute-git-dir
> + } >hook.actual
> + EOF
> + {
> + test_write_lines add "$1" "" "$(pwd)/$1" &&
> + (cd "${3:-${2:-.}}" && test-tool path-utils real_path .) &&
> + git -C "${3:-${2:-.}}" rev-parse --absolute-git-dir
> + } >hook.expect
> +}
> +
> +test_expect_success '"add" invokes post-worktree hook' '
> + post_worktree_add_hook wanda &&
> + git worktree add wanda &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success '"add" in other worktree invokes post-worktree hook there' '
> + post_worktree_add_hook wilbur "" wanda &&
> + git -C wanda worktree add ../wilbur &&
> + test_cmp hook.expect wanda/hook.actual
> +'
> +
> +test_expect_success '"add --no-checkout" still invokes post-worktree hook' '
> + post_worktree_add_hook wendy &&
> + git worktree add --no-checkout wendy &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success '"add --orphan" invokes post-worktree hook' '
> + post_worktree_add_hook winnie &&
> + git worktree add --orphan winnie &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success '"add" in bare repo invokes post-worktree hook there' '
> + rm -rf bare2 &&
> + git clone --bare . bare2 &&
> + post_worktree_add_hook willow bare2 &&
> + git -C bare2 worktree add --detach ../willow &&
> + test_cmp hook.expect bare2/hook.actual
> +'
> +
> +test_expect_success '"add" runs post-worktree after post-checkout' '
> + test_when_finished "rm -rf .git/hooks" &&
> + mkdir .git/hooks &&
> + test_hook post-checkout <<-\EOF &&
> + echo post-checkout >>"$(git rev-parse --git-common-dir)/hooks.actual"
> + EOF
> + test_hook post-worktree <<-\EOF &&
> + echo post-worktree >>"$(git rev-parse --git-common-dir)/hooks.actual"
> + EOF
> + test_write_lines post-checkout post-worktree >hooks.expect &&
> + git worktree add wobble &&
> + test_cmp hooks.expect .git/hooks.actual
> +'
> +
> +test_expect_success 'failing post-checkout hook does not suppress post-worktree hook' '
> + test_when_finished "rm -rf .git/hooks" &&
> + mkdir .git/hooks &&
> + test_hook post-checkout <<-\EOF &&
> + exit 2
> + EOF
> + test_hook post-worktree <<-\EOF &&
> + >post-worktree.ran &&
> + exit 3
> + EOF
> + test_expect_code 2 git worktree add wozzle &&
> + test_path_is_file post-worktree.ran
> +'
> +
> +test_expect_success 'failing post-worktree hook leaves worktree in place' '
> + test_when_finished "rm -rf .git/hooks" &&
> + mkdir .git/hooks &&
> + test_hook post-worktree <<-\EOF &&
> + exit 1
> + EOF
> + test_expect_code 1 git worktree add wilma &&
> + git worktree list --porcelain >out &&
> + test_grep -F "worktree $(pwd)/wilma" out
> +'
> +
> +test_expect_success 'failed "add" does not invoke post-worktree hook' '
> + test_when_finished "rm -rf .git/hooks occupied" &&
> + mkdir .git/hooks &&
> + test_hook post-worktree <<-\EOF &&
> + >hook.ran
> + EOF
> + mkdir occupied &&
> + : >occupied/blocker &&
> + test_must_fail git worktree add occupied &&
> + test_path_is_missing hook.ran
> +'
> +
> +test_expect_success 'post-worktree add gets absolute path with relative worktrees' '
> + test_when_finished "rm -rf relhook" &&
> + git init relhook &&
> + test_commit -C relhook base &&
> + test_hook -C relhook post-worktree <<-\EOF &&
> + test "$#" = 4 &&
> + printf "%s\n" "$@" >hook.actual
> + EOF
> + git -C relhook worktree add --relative-paths --detach wt &&
> + test_write_lines add wt "" "$(pwd)/relhook/wt" >hook.expect &&
> + test_cmp hook.expect relhook/hook.actual
> +'
> +
> +test_expect_success 'configured post-worktree hook preserves paths with spaces' '
> + test_when_finished "rm -rf confighook" &&
> + git init confighook &&
> + test_commit -C confighook base &&
> + write_script confighook/record-hook <<-\EOF &&
> + test "$#" = 4 &&
> + printf "%s\n" "$@" >hook.actual
> + EOF
> + git -C confighook config hook.lifecycle.command ./record-hook &&
> + git -C confighook config hook.lifecycle.event post-worktree &&
> + git -C confighook worktree add --detach "wt with spaces" &&
> + id=$(basename "$(git -C "confighook/wt with spaces" rev-parse --absolute-git-dir)") &&
> + test_write_lines add "$id" "" "$(pwd)/confighook/wt with spaces" >hook.expect &&
> + test_cmp hook.expect confighook/hook.actual
> +'
> +
> test_expect_success '"add" an existing but missing worktree' '
> git worktree add --detach pneu &&
> test_must_fail git worktree add --detach pneu &&
> diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
> index 69768c1207..11ef81dce8 100755
> --- a/t/t2403-worktree-move.sh
> +++ b/t/t2403-worktree-move.sh
> @@ -82,6 +82,59 @@ test_expect_success 'move worktree' '
> test_cmp expected2 actual2
> '
>
> +test_expect_success '"move" invokes post-worktree hook in the calling repository' '
> + test_hook post-worktree <<-\EOF &&
> + test "$#" = 4 || exit 1
> + test "$1" = move || exit 0
> + {
> + printf "%s\n" "$@" &&
> + test-tool path-utils real_path . &&
> + git rev-parse --absolute-git-dir
> + } >hook.actual
> + EOF
> + git worktree add --detach hook-source &&
> + git worktree move hook-source hook-destination &&
> + {
> + test_write_lines move hook-source "$(pwd)/hook-source" "$(pwd)/hook-destination" &&
> + test-tool path-utils real_path . &&
> + git rev-parse --absolute-git-dir
> + } >hook.expect &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success 'failing post-worktree move event leaves worktree moved' '
> + test_hook post-worktree <<-\EOF &&
> + test "$1" = move || exit 0
> + exit 1
> + EOF
> + git worktree add --detach hook-failing-source &&
> + test_must_fail git worktree move hook-failing-source hook-failing-destination &&
> + test_path_is_missing hook-failing-source &&
> + git -C hook-failing-destination status --porcelain >actual &&
> + test_must_be_empty actual
> +'
> +
> +test_expect_success 'post-worktree move keeps the ID and passes absolute paths with spaces' '
> + test_when_finished "rm -rf movehook" &&
> + git init movehook &&
> + test_commit -C movehook base &&
> + git -C movehook worktree add --relative-paths --detach "source tree" &&
> + git -C movehook worktree add --detach caller &&
> + id=$(basename "$(git -C "movehook/source tree" rev-parse --absolute-git-dir)") &&
> + test_hook -C movehook post-worktree <<-\EOF &&
> + test "$#" = 4 &&
> + {
> + printf "%s\n" "$@" &&
> + git rev-parse --show-toplevel
> + } >hook.actual
> + EOF
> + git -C movehook/caller worktree move --relative-paths "../source tree" "../destination tree" &&
> + test_write_lines move "$id" "$(pwd)/movehook/source tree" \
> + "$(pwd)/movehook/destination tree" "$(pwd)/movehook/caller" >hook.expect &&
> + test_cmp hook.expect movehook/caller/hook.actual &&
> + test_path_is_dir "movehook/destination tree"
> +'
> +
> test_expect_success 'move main worktree' '
> test_must_fail git worktree move . def
> '
> @@ -246,6 +299,66 @@ test_expect_success 'not remove a repo with initialized submodule' '
> )
> '
>
> +test_expect_success '"remove" invokes post-worktree remove event' '
> + test_hook post-worktree <<-\EOF &&
> + test "$#" = 4 || exit 1
> + test "$1" = remove || exit 0
> + printf "%s\n" "$@" >hook.actual
> + EOF
> + git worktree add --detach wt-hooked &&
> + git worktree remove wt-hooked &&
> + test_write_lines remove wt-hooked "$(pwd)/wt-hooked" "" >hook.expect &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success '"remove" of missing worktree invokes post-worktree hook' '
> + test_when_finished "rm -rf wt-moved-away" &&
> + test_hook post-worktree <<-\EOF &&
> + test "$1" = remove || exit 0
> + printf "%s\n" "$@" >hook.actual
> + EOF
> + rm -f hook.actual &&
> + git worktree add --detach wt-elsewhere &&
> + mv wt-elsewhere wt-moved-away &&
> + git worktree remove wt-elsewhere &&
> + test_write_lines remove wt-elsewhere "$(pwd)/wt-elsewhere" "" >hook.expect &&
> + test_cmp hook.expect hook.actual
> +'
> +
> +test_expect_success 'refused "remove" does not invoke post-worktree hook' '
> + git worktree add --detach wt-kept &&
> + test_when_finished "git worktree remove --force --force wt-kept || :" &&
> + test_hook post-worktree <<-\EOF &&
> + >hook.ran
> + EOF
> + git worktree lock wt-kept &&
> + test_must_fail git worktree remove wt-kept &&
> + test_path_is_missing hook.ran
> +'
> +
> +test_expect_success 'failing post-worktree remove event fails "remove", worktree is gone' '
> + test_hook post-worktree <<-\EOF &&
> + test "$1" = remove || exit 0
> + exit 1
> + EOF
> + git worktree add --detach wt-doomed &&
> + test_must_fail git worktree remove wt-doomed &&
> + test_path_is_missing wt-doomed &&
> + test_path_is_missing .git/worktrees/wt-doomed
> +'
> +
> +test_expect_success 'post-worktree remove preserves paths with spaces' '
> + git worktree add --detach "remove tree" &&
> + id=$(basename "$(git -C "remove tree" rev-parse --absolute-git-dir)") &&
> + test_hook post-worktree <<-\EOF &&
> + test "$#" = 4 &&
> + printf "%s\n" "$@" >hook.actual
> + EOF
> + git worktree remove "remove tree" &&
> + test_write_lines remove "$id" "$(pwd)/remove tree" "" >hook.expect &&
> + test_cmp hook.expect hook.actual
> +'
> +
> test_expect_success 'move worktree with absolute path to relative path' '
> test_config worktree.useRelativePaths false &&
> git worktree add ./absolute &&
next prev parent reply other threads:[~2026-10-06 9:23 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 23:36 [PATCH v1 0/3] worktree: add post-worktree-add and post-worktree-remove hooks Domen Kožar
2026-07-10 9:34 ` Phillip Wood
[not found] ` <CAMvcdZS=ZYbLmjKaGJvjQ_fWYhVbOzwMvYq+MMENWPYi_RiqvQ@mail.gmail.com>
2026-07-13 13:19 ` Phillip Wood
2026-08-04 18:14 ` [PATCH v2 0/4] worktree: add lifecycle hooks Domen Kožar
2026-08-04 19:03 ` Caleb White
2026-08-04 20:28 ` Junio C Hamano
2026-08-30 17:21 ` Domen Kožar
2026-09-07 14:30 ` Domen Kožar
2026-09-07 18:18 ` Kristoffer Haugsbakk
2026-09-07 19:34 ` Domen Kožar
2026-10-03 18:47 ` Maciej Ciemborowicz
2026-10-04 23:09 ` [PATCH v3 0/2] worktree: add post-worktree lifecycle hook Domen Kožar
2026-10-05 16:47 ` Junio C Hamano
[not found] ` <cover.1791152172.git.domen@cachix.org>
2026-10-04 23:09 ` [PATCH v3 1/2] " Domen Kožar
2026-10-06 9:23 ` Phillip Wood [this message]
2026-10-04 23:09 ` [PATCH v3 2/2] worktree: notify post-worktree hook when pruning Domen Kožar
[not found] ` <20260804181358.532970-1-domen@cachix.org>
2026-08-04 18:14 ` [PATCH v2 1/4] worktree: add post-worktree-add hook Domen Kožar
2026-08-04 20:03 ` Caleb White
2026-08-04 18:14 ` [PATCH v2 2/4] worktree: add post-worktree-remove hook Domen Kožar
2026-08-04 18:14 ` [PATCH v2 3/4] worktree: run post-worktree-remove hook when pruning Domen Kožar
2026-08-04 18:14 ` [PATCH v2 4/4] worktree: add post-worktree-move hook Domen Kožar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=71131749-b624-4c81-bae2-c32a7d3f1a15@gmail.com \
--to=phillip.wood123@gmail.com \
--cc=avarab@gmail.com \
--cc=cdwhite3@pm.me \
--cc=domen@cachix.org \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=kristofferhaugsbakk@fastmail.com \
--cc=maciej.ciemborowicz@gmail.com \
--cc=noreply@anthropic.com \
--cc=phillip.wood@dunelm.org.uk \
--cc=ps@pks.im \
--cc=sunshine@sunshineco.com \
--cc=test35965@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox