Git development
 help / color / mirror / Atom feed
* [PATCH] completion: zsh: support completion after "git -C <path>"
@ 2026-06-17 15:30 Lutz Lengemann via GitGitGadget
  2026-06-17 17:17 ` Ben Knoble
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Lutz Lengemann via GitGitGadget @ 2026-06-17 15:30 UTC (permalink / raw)
  To: git; +Cc: Lutz Lengemann, Lutz Lengemann

From: Lutz Lengemann <lutz@lengemann.net>

The zsh completion wrapper (__git_zsh_main) did not handle the global -C
option, so "git -C <path> <command> <TAB>" offered nothing and could not
complete a command's arguments.

Three things are needed to make it work, all scoped to -C:

  - Add -C to the _arguments specification, so completion no longer stops
    at it.

  - Advance __git_cmd_idx past any leading "-C <path>" options. The index
    is hard-coded to 1, i.e. the command is assumed to be the first
    argument; with -C present the command sits two words later for each
    -C, so the bash helpers otherwise look at the wrong word and produce
    nothing.

  - Collect the -C paths into __git_C_args, as __git_main does. The bash
    helpers run git to resolve aliases and list refs; without the -C
    paths they run in the current directory, so completion fails whenever
    the cwd is not the target repository or the command is an alias.

With these, "git -C <path> <command> <TAB>" completes the command, its
options and its arguments, including outside the repository, through
aliases, and with repeated -C options.

Signed-off-by: Lutz Lengemann <lutz@lengemann.net>
---
    completion: zsh: support completion after "git -C "
    
    This patch is intentionally scoped to -C, but the underlying problem is
    more general. The zsh wrapper hard-codes __git_cmd_idx=1, i.e. it
    assumes the command is always the first argument. That assumption breaks
    argument completion after any global option that precedes the command,
    not just -C — e.g. --git-dir, --work-tree, --namespace, -c, and
    -p/--paginate. After those, git <opt> <command> <TAB> currently
    completes the command name but not its arguments.
    
    The same approach generalizes cleanly: instead of skipping only leading
    -C options, walk all leading global options and their arguments to
    locate the command and its true index (mirroring the option scan in
    __git_main in git-completion.bash), while collecting -C into
    __git_C_args and --git-dir into __git_dir as today.
    
    I kept this revision narrow for reviewability and because git -C is the
    case where I miss the completion, but I'm happy to extend it to cover
    the other global options in a follow-up (or fold it into this patch) if
    that's preferred.

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2155%2Fmobilutz%2Fzsh-complete-global-C-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2155/mobilutz/zsh-complete-global-C-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/2155

 contrib/completion/git-completion.zsh | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
index c32186a977..323049be8b 100644
--- a/contrib/completion/git-completion.zsh
+++ b/contrib/completion/git-completion.zsh
@@ -227,6 +227,7 @@ __git_zsh_main ()
 		'(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \
 		'(-p --paginate)--no-pager[do not pipe git output into a pager]' \
 		'--git-dir=-[set the path to the repository]: :_directories' \
+		'*-C[run as if git was started in <path>]: :_directories' \
 		'--bare[treat the repository as a bare repository]' \
 		'(- :)--version[prints the git suite version]' \
 		'--exec-path=-[path to where your core git programs are installed]:: :_directories' \
@@ -252,6 +253,14 @@ __git_zsh_main ()
 		;;
 	(arg)
 		local command="${words[1]}" __git_dir __git_cmd_idx=1
+		local -a __git_C_args
+		local -i i=2
+
+		while [[ ${orig_words[i]} == -C ]]; do
+			__git_C_args+=(-C ${orig_words[i+1]})
+			(( __git_cmd_idx += 2 ))
+			(( i += 2 ))
+		done
 
 		if (( $+opt_args[--bare] )); then
 			__git_dir='.'

base-commit: 0fae78c9d55efe705877ea537fe42c59164ccd94
-- 
gitgitgadget

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] completion: zsh: support completion after "git -C <path>"
  2026-06-17 15:30 [PATCH] completion: zsh: support completion after "git -C <path>" Lutz Lengemann via GitGitGadget
@ 2026-06-17 17:17 ` Ben Knoble
  2026-06-17 17:21 ` Junio C Hamano
  2026-06-18 17:43 ` D. Ben Knoble
  2 siblings, 0 replies; 6+ messages in thread
From: Ben Knoble @ 2026-06-17 17:17 UTC (permalink / raw)
  To: Lutz Lengemann via GitGitGadget; +Cc: git, Lutz Lengemann

I’d like to take a deeper look at this, but I’m not sure when I can.

> Le 17 juin 2026 à 11:37, Lutz Lengemann via GitGitGadget <gitgitgadget@gmail.com> a écrit :
> 
> From: Lutz Lengemann <lutz@lengemann.net>
> 
> The zsh completion wrapper (__git_zsh_main) did not handle the global -C
> option, so "git -C <path> <command> <TAB>" offered nothing and could not
> complete a command's arguments.

One easy note, though: our commit style prefers describing the code base before the patch in question in the present tense (« does not handle », « offers nothing »).

The below imperative mood looks appropriate to me.

> 
> Three things are needed to make it work, all scoped to -C:
> 
>  - Add -C to the _arguments specification, so completion no longer stops
>    at it.
> 
>  - Advance __git_cmd_idx past any leading "-C <path>" options. The index
>    is hard-coded to 1, i.e. the command is assumed to be the first
>    argument; with -C present the command sits two words later for each
>    -C, so the bash helpers otherwise look at the wrong word and produce
>    nothing.
> 
>  - Collect the -C paths into __git_C_args, as __git_main does. The bash
>    helpers run git to resolve aliases and list refs; without the -C
>    paths they run in the current directory, so completion fails whenever
>    the cwd is not the target repository or the command is an alias.
> 
> With these, "git -C <path> <command> <TAB>" completes the command, its
> options and its arguments, including outside the repository, through
> aliases, and with repeated -C options.
> 
> Signed-off-by: Lutz Lengemann <lutz@lengemann.net>
> ---
>    completion: zsh: support completion after "git -C "
> 
>    This patch is intentionally scoped to -C, but the underlying problem is
>    more general. The zsh wrapper hard-codes __git_cmd_idx=1, i.e. it
>    assumes the command is always the first argument. That assumption breaks
>    argument completion after any global option that precedes the command,
>    not just -C — e.g. --git-dir, --work-tree, --namespace, -c, and
>    -p/--paginate. After those, git <opt> <command> <TAB> currently
>    completes the command name but not its arguments.
> 
>    The same approach generalizes cleanly: instead of skipping only leading
>    -C options, walk all leading global options and their arguments to
>    locate the command and its true index (mirroring the option scan in
>    __git_main in git-completion.bash), while collecting -C into
>    __git_C_args and --git-dir into __git_dir as today.
> 
>    I kept this revision narrow for reviewability and because git -C is the
>    case where I miss the completion, but I'm happy to extend it to cover
>    the other global options in a follow-up (or fold it into this patch) if
>    that's preferred.
> 
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-2155%2Fmobilutz%2Fzsh-complete-global-C-v1
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2155/mobilutz/zsh-complete-global-C-v1
> Pull-Request: https://github.com/gitgitgadget/git/pull/2155
> 
> contrib/completion/git-completion.zsh | 9 +++++++++
> 1 file changed, 9 insertions(+)
> 
> diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
> index c32186a977..323049be8b 100644
> --- a/contrib/completion/git-completion.zsh
> +++ b/contrib/completion/git-completion.zsh
> @@ -227,6 +227,7 @@ __git_zsh_main ()
>        '(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \
>        '(-p --paginate)--no-pager[do not pipe git output into a pager]' \
>        '--git-dir=-[set the path to the repository]: :_directories' \
> +        '*-C[run as if git was started in <path>]: :_directories' \
>        '--bare[treat the repository as a bare repository]' \
>        '(- :)--version[prints the git suite version]' \
>        '--exec-path=-[path to where your core git programs are installed]:: :_directories' \
> @@ -252,6 +253,14 @@ __git_zsh_main ()
>        ;;
>    (arg)
>        local command="${words[1]}" __git_dir __git_cmd_idx=1
> +        local -a __git_C_args
> +        local -i i=2
> +
> +        while [[ ${orig_words[i]} == -C ]]; do
> +            __git_C_args+=(-C ${orig_words[i+1]})
> +            (( __git_cmd_idx += 2 ))
> +            (( i += 2 ))
> +        done
> 
>        if (( $+opt_args[--bare] )); then
>            __git_dir='.'
> 
> base-commit: 0fae78c9d55efe705877ea537fe42c59164ccd94
> --
> gitgitgadget
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] completion: zsh: support completion after "git -C <path>"
  2026-06-17 15:30 [PATCH] completion: zsh: support completion after "git -C <path>" Lutz Lengemann via GitGitGadget
  2026-06-17 17:17 ` Ben Knoble
@ 2026-06-17 17:21 ` Junio C Hamano
  2026-06-18 17:43 ` D. Ben Knoble
  2 siblings, 0 replies; 6+ messages in thread
From: Junio C Hamano @ 2026-06-17 17:21 UTC (permalink / raw)
  To: Lutz Lengemann via GitGitGadget; +Cc: git, Lutz Lengemann

"Lutz Lengemann via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Lutz Lengemann <lutz@lengemann.net>
>
> The zsh completion wrapper (__git_zsh_main) did not handle the global -C
> option, so "git -C <path> <command> <TAB>" offered nothing and could not
> complete a command's arguments.

I do not write, use, or customize zsh, so please take my comments
with huge grains of salt, or just ignore them completely (your
choice) ;-), but one thng I noticed was that ...

> diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh
> index c32186a977..323049be8b 100644
> --- a/contrib/completion/git-completion.zsh
> +++ b/contrib/completion/git-completion.zsh
> @@ -227,6 +227,7 @@ __git_zsh_main ()
>  		'(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \
>  		'(-p --paginate)--no-pager[do not pipe git output into a pager]' \
>  		'--git-dir=-[set the path to the repository]: :_directories' \
> +		'*-C[run as if git was started in <path>]: :_directories' \
>  		'--bare[treat the repository as a bare repository]' \
>  		'(- :)--version[prints the git suite version]' \
>  		'--exec-path=-[path to where your core git programs are installed]:: :_directories' \

... this part talks about not just "-C<dir>" but knows about
all the other options that the "git" potty itself takes, while ...

> @@ -252,6 +253,14 @@ __git_zsh_main ()
>  		;;
>  	(arg)
>  		local command="${words[1]}" __git_dir __git_cmd_idx=1
> +		local -a __git_C_args
> +		local -i i=2
> +
> +		while [[ ${orig_words[i]} == -C ]]; do
> +			__git_C_args+=(-C ${orig_words[i+1]})
> +			(( __git_cmd_idx += 2 ))
> +			(( i += 2 ))
> +		done

... this only knows about "-C<dir>" and nothing else.

Doesn't it want to do something similar to what __git_main in
git-completion.bash does at the beginning, namely, this part?

__git_main ()
{
	local i c=1 command __git_dir __git_repo_path
	local __git_C_args C_args_count=0
	local __git_cmd_idx

	while [ $c -lt $cword ]; do
		i="${words[c]}"
		case "$i" in
		--git-dir=*)
			__git_dir="${i#--git-dir=}"
			;;
		--git-dir)
			((c++))
			__git_dir="${words[c]}"
			;;
		--bare)
			__git_dir="."
			;;
		--help)
			command="help"
			break
			;;
		-c|--work-tree|--namespace)
			((c++))
			;;
		-C)
			__git_C_args[C_args_count++]=-C
			((c++))
			__git_C_args[C_args_count++]="${words[c]}"
			;;
		-*)
			;;
		*)
			command="$i"
			__git_cmd_idx="$c"
			break
			;;
		esac
		((c++))
	done

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] completion: zsh: support completion after "git -C <path>"
  2026-06-17 15:30 [PATCH] completion: zsh: support completion after "git -C <path>" Lutz Lengemann via GitGitGadget
  2026-06-17 17:17 ` Ben Knoble
  2026-06-17 17:21 ` Junio C Hamano
@ 2026-06-18 17:43 ` D. Ben Knoble
  2026-07-14 22:34   ` D. Ben Knoble
  2 siblings, 1 reply; 6+ messages in thread
From: D. Ben Knoble @ 2026-06-18 17:43 UTC (permalink / raw)
  To: Lutz Lengemann via GitGitGadget; +Cc: git, Lutz Lengemann, Junio C Hamano

[apologies in advance for the strange format below]

On Wed, Jun 17, 2026 at 11:37 AM Lutz Lengemann via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Lutz Lengemann <lutz@lengemann.net>
>
> The zsh completion wrapper (__git_zsh_main) did not handle the global -C
> option, so "git -C <path> <command> <TAB>" offered nothing and could not
> complete a command's arguments.
>
> Three things are needed to make it work, all scoped to -C:
>
>   - Add -C to the _arguments specification, so completion no longer stops
>     at it.
>
>   - Advance __git_cmd_idx past any leading "-C <path>" options. The index
>     is hard-coded to 1, i.e. the command is assumed to be the first
>     argument; with -C present the command sits two words later for each
>     -C, so the bash helpers otherwise look at the wrong word and produce
>     nothing.
>
>   - Collect the -C paths into __git_C_args, as __git_main does. The bash
>     helpers run git to resolve aliases and list refs; without the -C
>     paths they run in the current directory, so completion fails whenever
>     the cwd is not the target repository or the command is an alias.
>
> With these, "git -C <path> <command> <TAB>" completes the command, its
> options and its arguments, including outside the repository, through
> aliases, and with repeated -C options.
>
> Signed-off-by: Lutz Lengemann <lutz@lengemann.net>
> ---
>     completion: zsh: support completion after "git -C "
>
>     This patch is intentionally scoped to -C, but the underlying problem is
>     more general. The zsh wrapper hard-codes __git_cmd_idx=1, i.e. it
>     assumes the command is always the first argument. That assumption breaks
>     argument completion after any global option that precedes the command,
>     not just -C — e.g. --git-dir, --work-tree, --namespace, -c, and
>     -p/--paginate. After those, git <opt> <command> <TAB> currently
>     completes the command name but not its arguments.
>
>     The same approach generalizes cleanly: instead of skipping only leading
>     -C options, walk all leading global options and their arguments to
>     locate the command and its true index (mirroring the option scan in
>     __git_main in git-completion.bash), while collecting -C into
>     __git_C_args and --git-dir into __git_dir as today.
>
>     I kept this revision narrow for reviewability and because git -C is the
>     case where I miss the completion, but I'm happy to extend it to cover
>     the other global options in a follow-up (or fold it into this patch) if
>     that's preferred.

See Junio's review for whether we should expand in this patch or a follow-up.

In reply to Junio:

> [the new handling only knows about -C]
> Doesn't it want to do something similar to what __git_main in
> git-completion.bash does at the beginning, namely, this part?

Yeah, we probably do want to skip over -c, etc. (I see some support for
--bare and --git-dir, but not skipping over it.) Still, this patch makes
things no worse in that regard, and improves the situation for -C
AFAICT.

In reply to Lutz:

> +        local -a __git_C_args
> +        local -i i=2
> +
> +        while [[ ${orig_words[i]} == -C ]]; do
> +            __git_C_args+=(-C ${orig_words[i+1]})
> +            (( __git_cmd_idx += 2 ))
> +            (( i += 2 ))
> +        done

I don't see either of these 2 local variables used anywhere else…

…well, except the Bash completion helpers, I suppose. But we mark these
local, so how do they propagate to the other functions?

Still, I was able to try this out with the somewhat hacky

    zsh # new shell :)
    # absolute path important
    autoload -Uz $PWD/contrib/completion/git-completion.zsh
    compdef git-completion.zsh git

    git -C <tab>

and it does prioritize directories there (though I still get a listing
of files afterwards, so the screen is taken up by that gigantic listing
in git.git, for example).

By the way, I've realized that "git -<tab>" has the same problem (a
giant list of files after the other option completions), and worse has
some _funky_ output!

    git -<tab> # without patch
    (option)
    --bare
    --exec-path
    --git-dir
    --help
    --html-path
    --info-path
    --man-path
    --namespace
    --no-pager
    --no-replace-objects
    --paginate
    --version
    --work-tree

    -p

    # treat the repository as a bare repository
    # path to where your core git programs are installed
    # set the path to the repository
    # prints the synopsis and a list of the most commonly used commands
    # print the path where gits HTML documentation is installed
    # print the path where the Info files are installed
    # print the manpath (see `man(1)`) for the man pages
    # set the git namespace
    # do not pipe git output into a pager
    # do not use replacement refs to replace git objects
    # pipe all output into less
    # prints the git suite version
    # set the path to the working tree
    [ed: the above block repeats twice more before the (file) listing below]
    (file)
    […]

Here's the output of _complete_help (^Xh by default) in both situations,
in case that helps to understand either the extra files listing (1) in
the example further back or the issue with single letter options (2)
just mentioned:

1: tags in context :completion::complete:git::
    option-C-1     (_arguments __git_zsh_main _git git-completion.zsh)
    use-compctl    (_default _git git-completion.zsh)
    globbed-files  (_files _default _git git-completion.zsh)
tags in context :completion::complete:git:option-C-1:
    directories    (_directories _arguments __git_zsh_main _git
git-completion.zsh)
    globbed-files  (_files _directories _arguments __git_zsh_main _git
git-completion.zsh)
    all-files      (_files _directories _arguments __git_zsh_main _git
git-completion.zsh)

2: tags in context :completion::complete:git::
    argument-1 options  (_arguments __git_zsh_main _git)
    use-compctl         (_default _git)
    globbed-files       (_files _default _git)
tags in context :completion::complete:git:argument-1:
    common-commands alias-commands all-commands  (__git_zsh_main _git)
    common-commands                              (__git_zsh_cmd_common
__git_zsh_main _git)
    alias-commands                               (__git_zsh_cmd_alias
__git_zsh_main _git)
    all-commands                                 (__git_zsh_cmd_all
__git_zsh_main _git)
tags in context :completion::complete:git:options:
    options  (_arguments __git_zsh_main _git)

> +        '*-C[run as if git was started in <path>]: :_directories' \

We should probably note in the log message that the _directories
completion will not account for previous -C; that is, after typing

    git -C dir -C <tab>

we will complete directories in ".", not "dir". That's probably a
reasonable limitation for now, but I think we could do _slightly_ better
by using a state "->dir" or something, accumulating the current prefix,
and passing that to _directories as a prefix with -W (see _path_files in
zshcompsys, which _directories delegates to via _files, IIUC).

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] completion: zsh: support completion after "git -C <path>"
  2026-06-18 17:43 ` D. Ben Knoble
@ 2026-07-14 22:34   ` D. Ben Knoble
  2026-08-17 19:29     ` Lutz Lengemann
  0 siblings, 1 reply; 6+ messages in thread
From: D. Ben Knoble @ 2026-07-14 22:34 UTC (permalink / raw)
  To: Lutz Lengemann via GitGitGadget; +Cc: git, Lutz Lengemann, Junio C Hamano

Hi Lutz,

On Thu, Jun 18, 2026 at 1:43 PM D. Ben Knoble <ben.knoble@gmail.com> wrote:
>
> [apologies in advance for the strange format below]
>
> On Wed, Jun 17, 2026 at 11:37 AM Lutz Lengemann via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
> >
> > From: Lutz Lengemann <lutz@lengemann.net>
> >
> > The zsh completion wrapper (__git_zsh_main) did not handle the global -C
> > option, so "git -C <path> <command> <TAB>" offered nothing and could not
> > complete a command's arguments.
> >
> > Three things are needed to make it work, all scoped to -C:
> >
> >   - Add -C to the _arguments specification, so completion no longer stops
> >     at it.
> >
> >   - Advance __git_cmd_idx past any leading "-C <path>" options. The index
> >     is hard-coded to 1, i.e. the command is assumed to be the first
> >     argument; with -C present the command sits two words later for each
> >     -C, so the bash helpers otherwise look at the wrong word and produce
> >     nothing.
> >
> >   - Collect the -C paths into __git_C_args, as __git_main does. The bash
> >     helpers run git to resolve aliases and list refs; without the -C
> >     paths they run in the current directory, so completion fails whenever
> >     the cwd is not the target repository or the command is an alias.
> >
> > With these, "git -C <path> <command> <TAB>" completes the command, its
> > options and its arguments, including outside the repository, through
> > aliases, and with repeated -C options.
> >
> > Signed-off-by: Lutz Lengemann <lutz@lengemann.net>
> > ---
> >     completion: zsh: support completion after "git -C "
> >
> >     This patch is intentionally scoped to -C, but the underlying problem is
> >     more general. The zsh wrapper hard-codes __git_cmd_idx=1, i.e. it
> >     assumes the command is always the first argument. That assumption breaks
> >     argument completion after any global option that precedes the command,
> >     not just -C — e.g. --git-dir, --work-tree, --namespace, -c, and
> >     -p/--paginate. After those, git <opt> <command> <TAB> currently
> >     completes the command name but not its arguments.
> >
> >     The same approach generalizes cleanly: instead of skipping only leading
> >     -C options, walk all leading global options and their arguments to
> >     locate the command and its true index (mirroring the option scan in
> >     __git_main in git-completion.bash), while collecting -C into
> >     __git_C_args and --git-dir into __git_dir as today.
> >
> >     I kept this revision narrow for reviewability and because git -C is the
> >     case where I miss the completion, but I'm happy to extend it to cover
> >     the other global options in a follow-up (or fold it into this patch) if
> >     that's preferred.
>
> See Junio's review for whether we should expand in this patch or a follow-up.
>
> In reply to Junio:
>
> > [the new handling only knows about -C]
> > Doesn't it want to do something similar to what __git_main in
> > git-completion.bash does at the beginning, namely, this part?
>
> Yeah, we probably do want to skip over -c, etc. (I see some support for
> --bare and --git-dir, but not skipping over it.) Still, this patch makes
> things no worse in that regard, and improves the situation for -C
> AFAICT.
>
> In reply to Lutz:
>
> > +        local -a __git_C_args
> > +        local -i i=2
> > +
> > +        while [[ ${orig_words[i]} == -C ]]; do
> > +            __git_C_args+=(-C ${orig_words[i+1]})
> > +            (( __git_cmd_idx += 2 ))
> > +            (( i += 2 ))
> > +        done
>
> I don't see either of these 2 local variables used anywhere else…
>
> …well, except the Bash completion helpers, I suppose. But we mark these
> local, so how do they propagate to the other functions?
>
> Still, I was able to try this out with the somewhat hacky
>
>     zsh # new shell :)
>     # absolute path important
>     autoload -Uz $PWD/contrib/completion/git-completion.zsh
>     compdef git-completion.zsh git
>
>     git -C <tab>
>
> and it does prioritize directories there (though I still get a listing
> of files afterwards, so the screen is taken up by that gigantic listing
> in git.git, for example).
>
> By the way, I've realized that "git -<tab>" has the same problem (a
> giant list of files after the other option completions), and worse has
> some _funky_ output!
>
>     git -<tab> # without patch
>     (option)
>     --bare
>     --exec-path
>     --git-dir
>     --help
>     --html-path
>     --info-path
>     --man-path
>     --namespace
>     --no-pager
>     --no-replace-objects
>     --paginate
>     --version
>     --work-tree
>
>     -p
>
>     # treat the repository as a bare repository
>     # path to where your core git programs are installed
>     # set the path to the repository
>     # prints the synopsis and a list of the most commonly used commands
>     # print the path where gits HTML documentation is installed
>     # print the path where the Info files are installed
>     # print the manpath (see `man(1)`) for the man pages
>     # set the git namespace
>     # do not pipe git output into a pager
>     # do not use replacement refs to replace git objects
>     # pipe all output into less
>     # prints the git suite version
>     # set the path to the working tree
>     [ed: the above block repeats twice more before the (file) listing below]
>     (file)
>     […]
>
> Here's the output of _complete_help (^Xh by default) in both situations,
> in case that helps to understand either the extra files listing (1) in
> the example further back or the issue with single letter options (2)
> just mentioned:
>
> 1: tags in context :completion::complete:git::
>     option-C-1     (_arguments __git_zsh_main _git git-completion.zsh)
>     use-compctl    (_default _git git-completion.zsh)
>     globbed-files  (_files _default _git git-completion.zsh)
> tags in context :completion::complete:git:option-C-1:
>     directories    (_directories _arguments __git_zsh_main _git
> git-completion.zsh)
>     globbed-files  (_files _directories _arguments __git_zsh_main _git
> git-completion.zsh)
>     all-files      (_files _directories _arguments __git_zsh_main _git
> git-completion.zsh)
>
> 2: tags in context :completion::complete:git::
>     argument-1 options  (_arguments __git_zsh_main _git)
>     use-compctl         (_default _git)
>     globbed-files       (_files _default _git)
> tags in context :completion::complete:git:argument-1:
>     common-commands alias-commands all-commands  (__git_zsh_main _git)
>     common-commands                              (__git_zsh_cmd_common
> __git_zsh_main _git)
>     alias-commands                               (__git_zsh_cmd_alias
> __git_zsh_main _git)
>     all-commands                                 (__git_zsh_cmd_all
> __git_zsh_main _git)
> tags in context :completion::complete:git:options:
>     options  (_arguments __git_zsh_main _git)
>
> > +        '*-C[run as if git was started in <path>]: :_directories' \
>
> We should probably note in the log message that the _directories
> completion will not account for previous -C; that is, after typing
>
>     git -C dir -C <tab>
>
> we will complete directories in ".", not "dir". That's probably a
> reasonable limitation for now, but I think we could do _slightly_ better
> by using a state "->dir" or something, accumulating the current prefix,
> and passing that to _directories as a prefix with -W (see _path_files in
> zshcompsys, which _directories delegates to via _files, IIUC).
>
> --
> D. Ben Knoble

Any progress here? I just found my local copy of this patch and was
briefly surprised to see it hadn't graduated anywhere (until I
realized conversation had stalled at this point).

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] completion: zsh: support completion after "git -C <path>"
  2026-07-14 22:34   ` D. Ben Knoble
@ 2026-08-17 19:29     ` Lutz Lengemann
  0 siblings, 0 replies; 6+ messages in thread
From: Lutz Lengemann @ 2026-08-17 19:29 UTC (permalink / raw)
  To: D. Ben Knoble, Lutz Lengemann; +Cc: git, Junio C Hamano

Hi Ben

(Resending, my earlier reply was rejected by the list for being HTML.)

On Wed, Jul 15, 2026, at 00:34, D. Ben Knoble wrote:
> Any progress here? I just found my local copy of this patch and was
> briefly surprised to see it hadn't graduated anywhere (until I
> realized conversation had stalled at this point).

Sorry for the very late reply, I was on holiday and then other life
things got in the way of answering :(  I do have a v2 ready, which I
have just pushed to my fork, and which follows this message.

Junio C Hamano <gitster@pobox.com> writes:

> Doesn't it want to do something similar to what __git_main in
> git-completion.bash does at the beginning, namely, this part?

It does, thanks.  v2 no longer skips only leading -C options, but walks
the words in front of the command and skips over the global options and,
where they take one, their arguments, like __git_main does.

That also makes "git -p checkout <TAB>" and "git --git-dir=<path>
checkout <TAB>" complete the arguments of the command, which they did
not before.

Two related gaps are left alone, as they are bugs in the _arguments
specification rather than in the command lookup: -c is not listed there
at all, and --git-dir and friends are spelled "--git-dir=-", which
accepts only "--git-dir=<path>", not the "--git-dir <path>" form.  I can
send patches for those separately.

"D. Ben Knoble" <ben.knoble@gmail.com> writes:

> But we mark these local, so how do they propagate to the other
> functions?

zsh scoping is dynamic, not lexical, so a variable declared "local" in
__git_zsh_main is visible in the functions that are called from it, the
bash helpers included.  That is how __git_dir and __git_cmd_idx are
handed down already, and __git_C_args works the same way.

> We should probably note in the log message that the _directories
> completion will not account for previous -C

I added a note about this in the log message.

> I think we could do _slightly_ better by using a state "->dir" or
> something, accumulating the current prefix, and passing that to
> _directories as a prefix with -W

I tried that and it works, but it changes what -C offers, which is more
than fixing the completion after -C, so I left it out; happy to send it
on top.  Two things to watch out for there: the accumulated path has to
be made absolute, as -W with ".." gave me the directories of "/", and
the accumulation has to stop before the word that is being completed.

> By the way, I've realized that "git -<tab>" has the same problem (a
> giant list of files after the other option completions)

That one is older than this patch: the file listing comes from the
fallback at the end of _git,

	let _ret && _default && _ret=0

which is where the "use-compctl" and "globbed-files" tags in your
_complete_help dump come from.  I could not reproduce the repeated
description block with "zsh -f" and only the _complete completer, so
something in my setup or yours may differ there.  Either way it wants
its own topic.

I hope that the change now looks good, and if there is anything I should
still look at just tell me.

Thank you very much
Lutz

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-08-17 19:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 15:30 [PATCH] completion: zsh: support completion after "git -C <path>" Lutz Lengemann via GitGitGadget
2026-06-17 17:17 ` Ben Knoble
2026-06-17 17:21 ` Junio C Hamano
2026-06-18 17:43 ` D. Ben Knoble
2026-07-14 22:34   ` D. Ben Knoble
2026-08-17 19:29     ` Lutz Lengemann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox