{"thread":{"id":"66457","subject":"[PATCH] completion: exclude previous file arguments in Zsh","startedAt":"2026-10-03T11:22:10Z","lastAt":"2026-10-05T01:45:00Z","messageCount":5,"participants":["Fionn via GitGitGadget","SZEDER Gábor","Fionn","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"554054","messageId":"pull.2216.git.git.1791026527023.gitgitgadget@gmail.com","threadId":"66457","inReplyTo":null,"subject":"[PATCH] completion: exclude previous file arguments in Zsh","fromName":"Fionn via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-10-03T11:22:06Z","receivedAt":"2026-10-03T11:22:10Z","isPatch":true,"body":"From: Fionn Fitzmaurice <git@fionn.email>\n\nWhen using the _git completion function bundled with Zsh\n(https://sf.net/p/zsh/code/ci/master/tree/Completion/Unix/Command/_git),\nduplicate files in an argument list will not be offered as completion\ncandidates.\n\nFor example, suppose we have untracked files aa and ab (only). Then with\nthe Zsh completion,\n\n    git add aa a<tab>\n\nwould not offer both aa and ab as completion candidates, rather it would\ncomplete ab only.\n\nThis behaviour is not present in git-completion.zsh shipped with Git,\nwhich does not deduplicate arguments.\n\nWe can get this with minor changes, however. Here we introduce an array\n__git_file_exclude which we populate with existing arguments and then\ntell compadd to exclude them, which closely matches the Zsh _git\ncompletion behaviour (as well as common programs such as rm).\n\nSigned-off-by: Fionn Fitzmaurice <git@fionn.email>\n---\n    completion: exclude previous file arguments in Zsh\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2216%2Ffionn%2Fzsh-completion-exclude-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2216/fionn/zsh-completion-exclude-v1\nPull-Request: https://github.com/git/git/pull/2216\n\n contrib/completion/git-completion.zsh | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh\nindex d5c526665b..26444923c1 100644\n--- a/contrib/completion/git-completion.zsh\n+++ b/contrib/completion/git-completion.zsh\n@@ -117,7 +117,7 @@ __gitcomp_file ()\n \temulate -L zsh\n \n \tcompset -P '*[=:]'\n-\tcompadd -f -p \"${2-}\" -- ${(f)1} && _ret=0\n+\tcompadd -f -p \"${2-}\" -F __git_file_exclude -- ${(f)1} && _ret=0\n }\n \n __gitcomp_direct_append ()\n@@ -284,6 +284,8 @@ __git_zsh_main ()\n \n \t\t(( $+opt_args[--help] )) && command='help'\n \n+\t\t__git_file_exclude=(${words[2,-1]:#${words[CURRENT]}})\n+\n \t\twords=( ${orig_words[@]} )\n \n \t\t__git_zsh_bash_func $command\n@@ -296,6 +298,7 @@ _git ()\n \tlocal _ret=1\n \tlocal cur cword prev\n \tlocal __git_repo_path\n+\tlocal -a __git_file_exclude\n \n \tcur=${words[CURRENT]}\n \tprev=${words[CURRENT-1]}\n\nbase-commit: c46c1e37724f0478939de636ab8ea5a89086d532\n-- \ngitgitgadget\n"},{"id":"554094","messageId":"asIJO3CZ/P/2L4qi@szeder.dev","threadId":"66457","inReplyTo":"pull.2216.git.git.1791026527023.gitgitgadget@gmail.com","subject":"Re: [PATCH] completion: exclude previous file arguments in Zsh","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2026-10-04T08:07:23Z","receivedAt":"2026-10-04T08:07:27Z","isPatch":true,"body":"On Sat, Oct 03, 2026 at 11:22:06AM +0000, Fionn via GitGitGadget wrote:\n> We can get this with minor changes, however. Here we introduce an array\n> __git_file_exclude which we populate with existing arguments and then\n\n\"existing arguments\" of what?\n\n> tell compadd to exclude them, which closely matches the Zsh _git\n> completion behaviour (as well as common programs such as rm).\n\n\n> @@ -284,6 +284,8 @@ __git_zsh_main ()\n>  \n>  \t\t(( $+opt_args[--help] )) && command='help'\n>  \n> +\t\t__git_file_exclude=(${words[2,-1]:#${words[CURRENT]}})\n\nI don't do Zsh, but that 2 as index looks suspicious.\n\nWhat will be excluded in the following command line:\n\n  git -C dir -C subdir -c foo.bar=baz add file1 file2 <TAB>\n\nI think we should exclude only those arguments that come after the git\ncommand, in this case after \"add\", i.e. \"file1\" and \"file2\", but I\nsuspect that everything starting with \"dir\" will get excluded.\n\n> +\n>  \t\twords=( ${orig_words[@]} )\n>  \n>  \t\t__git_zsh_bash_func $command\n"},{"id":"554117","messageId":"DLW6TDPQ9DA8.3CY39XL14GO9E@fionn.email","threadId":"66457","inReplyTo":"asIJO3CZ/P/2L4qi@szeder.dev","subject":"Re: [PATCH] completion: exclude previous file arguments in Zsh","fromName":"Fionn","fromEmail":"fionn@fionn.email","sentAt":"2026-10-04T16:17:04Z","receivedAt":"2026-10-04T16:17:07Z","isPatch":true,"body":"> \"existing arguments\" of what?\n\nOf a subcommand that takes paths.\n\n> I don't do Zsh, but that 2 as index looks suspicious.\n\nFair to be suspicious. word[1] is the subcommand (e.g. \"add\"), so we \nindex from 2 on in order to skip it. This is independent of where the \nsubcommand appears in the entire command line.\n\n> What will be excluded in the following command line:\n>\n>   git -C dir -C subdir -c foo.bar=baz add file1 file2 <TAB>\n>\n> I think we should exclude only those arguments that come after the git\n> command, in this case after \"add\", i.e. \"file1\" and \"file2\", but I\n> suspect that everything starting with \"dir\" will get excluded.\n\nIn my testing this works correctly (i.e. file1 and file2 are not offered \nas completion candidates any more, but if e.g. dir or foo exist in the \nsubdirectory, they would be offered).\n\nI've been dogfooding this for about 8 months on and off. Occasionally \ncompletion candidates I'd hope would be excluded are present, but this \nis because the fallback completion bypasses __gitcomp_file, which is a \nseparate issue. I have not yet encountered completion candidates being \nunexpectedly excluded.\n\nAn easy way to test this is to link git-completion.zsh to _git and then \nadd\n\n    fpath=(/path/to/directory/containing/_git/file $fpath[@])\n\nto ~/.zshrc, or similar.\n"},{"id":"554130","messageId":"xmqqcxtprwyd.fsf@gitster.g","threadId":"66457","inReplyTo":"asIJO3CZ/P/2L4qi@szeder.dev","subject":"Re: [PATCH] completion: exclude previous file arguments in Zsh","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-04T21:13:14Z","receivedAt":"2026-10-04T21:13:17Z","isPatch":true,"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n> What will be excluded in the following command line:\n>\n>   git -C dir -C subdir -c foo.bar=baz add file1 file2 <TAB>\n>\n> I think we should exclude only those arguments that come after the git\n> command, in this case after \"add\", i.e. \"file1\" and \"file2\", but I\n> suspect that everything starting with \"dir\" will get excluded.\n\nI was writing the same message when I saw yours.\n\nIf you had a file called 'add' in the working tree and then typed\n\"a<TAB>\" to complete, is 'add' offered together with other files\nwhose name begins with 'a'?\n\n"},{"id":"554136","messageId":"DLWIW6XTLW5S.3B270NSZYIQDE@fionn.email","threadId":"66457","inReplyTo":"xmqqcxtprwyd.fsf@gitster.g","subject":"Re: [PATCH] completion: exclude previous file arguments in Zsh","fromName":"Fionn","fromEmail":"git@fionn.email","sentAt":"2026-10-05T01:44:58Z","receivedAt":"2026-10-05T01:45:00Z","isPatch":true,"body":"> If you had a file called 'add' in the working tree and then typed\n> \"a<TAB>\" to complete, is 'add' offered together with other files\n> whose name begins with 'a'?\n\nIt is indeed.\n"}]}