* [PATCH 0/2] completion of 'git [-C <dir>] checkout'
@ 2026-08-11 3:19 Junio C Hamano
2026-08-11 3:21 ` [PATCH 1/2] completion: no-op refactoring of checkout completion Junio C Hamano
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-11 3:19 UTC (permalink / raw)
To: git
Cc: Philippe Blain, Britton Leo Kerin, Elijah Newren,
Rubén Justo, Patrick Steinhardt, D. Ben Knoble,
SZEDER Gábor
Continuing from the previous 'git [-C <dir>] diff' series, these two
patches correct completion for 'git checkout [-C <dir>] path<TAB>',
but without falling back to untracked paths, as "checkout paths out
of the index" is by definition about paths that appear in the index.
1/2: completion: no-op refactoring of checkout completion
2/2: completion: complete tracked paths for "git checkout"
contrib/completion/git-completion.bash | 86 ++++++++++++++------------
t/t9902-completion.sh | 27 ++++++++
2 files changed, 73 insertions(+), 40 deletions(-)
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/2] completion: no-op refactoring of checkout completion
2026-08-11 3:19 [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
@ 2026-08-11 3:21 ` Junio C Hamano
2026-08-11 3:21 ` [PATCH 2/2] completion: complete tracked paths for "git checkout" Junio C Hamano
` (2 subsequent siblings)
3 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-11 3:21 UTC (permalink / raw)
To: git
Cc: Philippe Blain, Britton Leo Kerin, Elijah Newren,
Rubén Justo, Patrick Steinhardt, D. Ben Knoble,
SZEDER Gábor
The 'git checkout' completion function punts very early when it sees
'--' on the command line, as it indicates that options or revisions
can no longer appear. By returning early, it allows the default
Bash action (which completes files in '$PWD') to kick in.
In preparation for changing what happens in the next step when
option or revision completion yields no matching candidates, or when
'--' is present, reorganize the control flow to avoid this early
return, and add explicit returns to the option completion branches.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
contrib/completion/git-completion.bash | 84 +++++++++++++-------------
1 file changed, 43 insertions(+), 41 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d35b4f3024..38dec1cabe 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1735,49 +1735,51 @@ __git_checkout_default_dwim_mode ()
_git_checkout ()
{
- __git_has_doubledash && return
-
- local dwim_opt="$(__git_checkout_default_dwim_mode)"
-
- case "$prev" in
- -b|-B|--orphan)
- # Complete local branches (and DWIM branch
- # remote branch names) for an option argument
- # specifying a new branch name. This is for
- # convenience, assuming new branches are
- # possibly based on pre-existing branch names.
- __git_complete_refs $dwim_opt --mode="heads"
- return
- ;;
- *)
- ;;
- esac
+ if ! __git_has_doubledash; then
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
- case "$cur" in
- --conflict=*)
- __gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
- ;;
- --*)
- __gitcomp_builtin checkout
- ;;
- *)
- # At this point, we've already handled special completion for
- # the arguments to -b/-B, and --orphan. There are 3 main
- # things left we can possibly complete:
- # 1) a start-point for -b/-B, -d/--detach, or --orphan
- # 2) a remote head, for --track
- # 3) an arbitrary reference, possibly including DWIM names
- #
+ case "$prev" in
+ -b|-B|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
- if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
- __git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
- __git_complete_refs --mode="remote-heads"
- else
- __git_complete_refs $dwim_opt --mode="refs"
- fi
- ;;
- esac
+ case "$cur" in
+ --conflict=*)
+ __gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
+ return
+ ;;
+ --*)
+ __gitcomp_builtin checkout
+ return
+ ;;
+ *)
+ # At this point, we've already handled special completion for
+ # the arguments to -b/-B, and --orphan. There are 3 main
+ # things left we can possibly complete:
+ # 1) a start-point for -b/-B, -d/--detach, or --orphan
+ # 2) a remote head, for --track
+ # 3) an arbitrary reference, possibly including DWIM names
+ #
+
+ if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
+ __git_complete_refs --mode="refs"
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
+ __git_complete_refs --mode="remote-heads"
+ else
+ __git_complete_refs $dwim_opt --mode="refs"
+ fi
+ ;;
+ esac
+ fi
}
__git_sequencer_inprogress_options="--continue --quit --abort --skip"
--
2.55.0-698-g3e60a4dc4e
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/2] completion: complete tracked paths for "git checkout"
2026-08-11 3:19 [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
2026-08-11 3:21 ` [PATCH 1/2] completion: no-op refactoring of checkout completion Junio C Hamano
@ 2026-08-11 3:21 ` Junio C Hamano
2026-08-11 16:32 ` Ben Knoble
2026-08-11 4:04 ` [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
3 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2026-08-11 3:21 UTC (permalink / raw)
To: git
Cc: Philippe Blain, Britton Leo Kerin, Elijah Newren,
Rubén Justo, Patrick Steinhardt, D. Ben Knoble,
SZEDER Gábor
When completing arguments for "git checkout", _git_checkout()
delegates to __git_complete_refs(), which only completes revision
references. This is good, as mixing revisions and paths in a single
list from which the user can choose is confusing. However, if no
reference matches, or if "--" is given, _git_checkout() leaves
COMPREPLY empty. Bash then falls back to the default filename
completion in $PWD.
This fails when "git -C <path>" is used, as $PWD is not the target
repository.
Update _git_checkout() to use __git_complete_index_file() when "--"
is present, or when revision reference completion yields no matching
candidates, so that tracked paths are offered as candidates.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
contrib/completion/git-completion.bash | 4 ++++
t/t9902-completion.sh | 27 ++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 38dec1cabe..bd4b6e9247 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1780,6 +1780,10 @@ _git_checkout ()
;;
esac
fi
+
+ if [ ${#COMPREPLY[@]} -eq 0 ]; then
+ __git_complete_index_file
+ fi
}
__git_sequencer_inprogress_options="--continue --quit --abort --skip"
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 53a2bfb2ac..46fe94d8d5 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2713,6 +2713,33 @@ test_expect_success 'git -C <path> checkout uses the right repo' '
EOF
'
+test_expect_success 'git checkout completes tracked paths when no refs match' '
+ # file1 and file2 are tracked but ufile is not
+ # there is no ref that begins with f
+ test_completion "git checkout f" <<-\EOF &&
+ file1
+ file2
+ EOF
+ test_completion "git checkout -- f" <<-\EOF
+ file1
+ file2
+ EOF
+'
+
+test_expect_success 'git -C <path> checkout completes tracked paths in specified repo' '
+ test_when_finished "rm -rf repo-for-checkout" &&
+ git init repo-for-checkout &&
+ echo content >repo-for-checkout/otherfile &&
+ git -C repo-for-checkout add otherfile &&
+ git -C repo-for-checkout commit -m otherfile &&
+ test_completion "git -C repo-for-checkout checkout o" <<-\EOF &&
+ otherfile
+ EOF
+ test_completion "git -C repo-for-checkout checkout -- o" <<-\EOF
+ otherfile
+ EOF
+'
+
test_expect_success 'git diff completes tracked paths when no refs match' '
# file1 and file2 are tracked but file3 is not
test_completion "git diff f" <<-\EOF
--
2.55.0-698-g3e60a4dc4e
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 0/2] completion of 'git [-C <dir>] checkout'
2026-08-11 3:19 [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
2026-08-11 3:21 ` [PATCH 1/2] completion: no-op refactoring of checkout completion Junio C Hamano
2026-08-11 3:21 ` [PATCH 2/2] completion: complete tracked paths for "git checkout" Junio C Hamano
@ 2026-08-11 4:04 ` Junio C Hamano
2026-08-11 16:33 ` Ben Knoble
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
3 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2026-08-11 4:04 UTC (permalink / raw)
To: git
Cc: Philippe Blain, Britton Leo Kerin, Elijah Newren,
Rubén Justo, Patrick Steinhardt, D. Ben Knoble,
SZEDER Gábor
Junio C Hamano <gitster@pobox.com> writes:
> Continuing from the previous 'git [-C <dir>] diff' series, these two
> patches correct completion for 'git checkout [-C <dir>] path<TAB>',
> but without falling back to untracked paths, as "checkout paths out
> of the index" is by definition about paths that appear in the index.
I suppose I will add the 'untracked, too' final fallback, just like
'diff', because 'git checkout other-branch foo<TAB>' could resurrect
a path like 'foolish' that appears on 'other-branch' but not in the
currently checked-out branch (and thus not in the index). The
'foolish' file might also appear in the working tree as an untracked
path.
This is not particularly useful, however, as it is unlikely that a
file like 'foolish' tracked on another branch would be lying
around untracked in the working tree to begin with.
I did not, however, find any readily usable machinery in the
'git-completion.bash' script that allows completing a path within an
arbitrary tree. If such machinery were available, 'git checkout
other-branch foo<TAB>' could capture the output of 'git ls-tree -r
other-branch' and offer paths that begin with the given prefix.
Regardless, implementing this is beyond my 'git-completion-fu' right
now. As I mentioned, I barely managed the 'diff' completion as a
monkey-see-monkey-do patch series, and I would welcome others
building on top of this once the dust settles.
> 1/2: completion: no-op refactoring of checkout completion
> 2/2: completion: complete tracked paths for "git checkout"
>
> contrib/completion/git-completion.bash | 86 ++++++++++++++------------
> t/t9902-completion.sh | 27 ++++++++
> 2 files changed, 73 insertions(+), 40 deletions(-)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] completion: complete tracked paths for "git checkout"
2026-08-11 3:21 ` [PATCH 2/2] completion: complete tracked paths for "git checkout" Junio C Hamano
@ 2026-08-11 16:32 ` Ben Knoble
2026-08-11 17:25 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Ben Knoble @ 2026-08-11 16:32 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Philippe Blain, Leo Kerin Britton, Elijah Newren,
Rubén Justo, Patrick Steinhardt, Gábor SZEDER
>
> Le 10 août 2026 à 23:21, Junio C Hamano <gitster@pobox.com> a écrit :
>
> When completing arguments for "git checkout", _git_checkout()
> delegates to __git_complete_refs(), which only completes revision
> references. This is good, as mixing revisions and paths in a single
> list from which the user can choose is confusing. However, if no
> reference matches, or if "--" is given, _git_checkout() leaves
> COMPREPLY empty. Bash then falls back to the default filename
> completion in $PWD.
>
> This fails when "git -C <path>" is used, as $PWD is not the target
> repository.
>
> Update _git_checkout() to use __git_complete_index_file() when "--"
> is present, or when revision reference completion yields no matching
> candidates, so that tracked paths are offered as candidates.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> contrib/completion/git-completion.bash | 4 ++++
> t/t9902-completion.sh | 27 ++++++++++++++++++++++++++
> 2 files changed, 31 insertions(+)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index 38dec1cabe..bd4b6e9247 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -1780,6 +1780,10 @@ _git_checkout ()
> ;;
> esac
> fi
> +
> + if [ ${#COMPREPLY[@]} -eq 0 ]; then
> + __git_complete_index_file
> + fi
> }
Assuming the prior step was purely mechanical, which I did not validate, this looks reasonable to me.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/2] completion of 'git [-C <dir>] checkout'
2026-08-11 4:04 ` [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
@ 2026-08-11 16:33 ` Ben Knoble
2026-08-12 1:45 ` Junio C Hamano
0 siblings, 1 reply; 12+ messages in thread
From: Ben Knoble @ 2026-08-11 16:33 UTC (permalink / raw)
To: Junio C Hamano
Cc: git, Philippe Blain, Leo Kerin Britton, Elijah Newren,
Rubén Justo, Patrick Steinhardt, Gábor SZEDER
> Le 11 août 2026 à 00:04, Junio C Hamano <gitster@pobox.com> a écrit :
>
> Junio C Hamano <gitster@pobox.com> writes:
>
>> Continuing from the previous 'git [-C <dir>] diff' series, these two
>> patches correct completion for 'git checkout [-C <dir>] path<TAB>',
>> but without falling back to untracked paths, as "checkout paths out
>> of the index" is by definition about paths that appear in the index.
>
> I suppose I will add the 'untracked, too' final fallback, just like
> 'diff', because 'git checkout other-branch foo<TAB>' could resurrect
> a path like 'foolish' that appears on 'other-branch' but not in the
> currently checked-out branch (and thus not in the index). The
> 'foolish' file might also appear in the working tree as an untracked
> path.
>
> This is not particularly useful, however, as it is unlikely that a
> file like 'foolish' tracked on another branch would be lying
> around untracked in the working tree to begin with.
>
> I did not, however, find any readily usable machinery in the
> 'git-completion.bash' script that allows completing a path within an
> arbitrary tree. If such machinery were available, 'git checkout
> other-branch foo<TAB>' could capture the output of 'git ls-tree -r
> other-branch' and offer paths that begin with the given prefix.
>
> Regardless, implementing this is beyond my 'git-completion-fu' right
> now. As I mentioned, I barely managed the 'diff' completion as a
> monkey-see-monkey-do patch series, and I would welcome others
> building on top of this once the dust settles.
I do not know where it lives (and it may be Zsh-specific) [partly because I haven’t looked while on mobile], but I think there is support for completing « path » in « git show <tree>:», so there might be something to build on there.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 2/2] completion: complete tracked paths for "git checkout"
2026-08-11 16:32 ` Ben Knoble
@ 2026-08-11 17:25 ` Junio C Hamano
0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-11 17:25 UTC (permalink / raw)
To: Ben Knoble
Cc: git, Philippe Blain, Leo Kerin Britton, Elijah Newren,
Rubén Justo, Patrick Steinhardt, Gábor SZEDER
Ben Knoble <ben.knoble@gmail.com> writes:
>>
>> Le 10 août 2026 à 23:21, Junio C Hamano <gitster@pobox.com> a écrit :
>>
>> When completing arguments for "git checkout", _git_checkout()
>> delegates to __git_complete_refs(), which only completes revision
>> references. This is good, as mixing revisions and paths in a single
>> list from which the user can choose is confusing. However, if no
>> reference matches, or if "--" is given, _git_checkout() leaves
>> COMPREPLY empty. Bash then falls back to the default filename
>> completion in $PWD.
>>
>> This fails when "git -C <path>" is used, as $PWD is not the target
>> repository.
>>
>> Update _git_checkout() to use __git_complete_index_file() when "--"
>> is present, or when revision reference completion yields no matching
>> candidates, so that tracked paths are offered as candidates.
>>
>> Signed-off-by: Junio C Hamano <gitster@pobox.com>
>> ---
>> contrib/completion/git-completion.bash | 4 ++++
>> t/t9902-completion.sh | 27 ++++++++++++++++++++++++++
>> 2 files changed, 31 insertions(+)
>>
>> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
>> index 38dec1cabe..bd4b6e9247 100644
>> --- a/contrib/completion/git-completion.bash
>> +++ b/contrib/completion/git-completion.bash
>> @@ -1780,6 +1780,10 @@ _git_checkout ()
>> ;;
>> esac
>> fi
>> +
>> + if [ ${#COMPREPLY[@]} -eq 0 ]; then
>> + __git_complete_index_file
>> + fi
>> }
>
> Assuming the prior step was purely mechanical, which I did not validate, this looks reasonable to me.
Actually the new call should use "--cached" to complete from the
paths in the index, I think.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/2] completion of 'git [-C <dir>] checkout'
2026-08-11 16:33 ` Ben Knoble
@ 2026-08-12 1:45 ` Junio C Hamano
0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-12 1:45 UTC (permalink / raw)
To: Ben Knoble
Cc: git, Philippe Blain, Leo Kerin Britton, Elijah Newren,
Rubén Justo, Patrick Steinhardt, Gábor SZEDER
Ben Knoble <ben.knoble@gmail.com> writes:
>> Le 11 août 2026 à 00:04, Junio C Hamano <gitster@pobox.com> a écrit :
>>
>> I did not, however, find any readily usable machinery in the
>> 'git-completion.bash' script that allows completing a path within an
>> arbitrary tree. If such machinery were available, 'git checkout
>> other-branch foo<TAB>' could capture the output of 'git ls-tree -r
>> other-branch' and offer paths that begin with the given prefix.
>>
>> Regardless, implementing this is beyond my 'git-completion-fu' right
>> now. As I mentioned, I barely managed the 'diff' completion as a
>> monkey-see-monkey-do patch series, and I would welcome others
>> building on top of this once the dust settles.
>
> I do not know where it lives (and it may be Zsh-specific) [partly
> because I haven’t looked while on mobile], but I think there is
> support for completing « path » in « git show <tree>:», so there
> might be something to build on there.
I know where treeish:path<TAB> support is. The thing is, it is not
a reusable machinery for "git checkout treeish path<TAB>".
Thanks.
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 0/3] completion of 'git [-C <dir>] checkout'
2026-08-11 3:19 [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
` (2 preceding siblings ...)
2026-08-11 4:04 ` [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
@ 2026-08-12 16:48 ` Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 1/3] completion: no-op refactoring of checkout completion Junio C Hamano
` (2 more replies)
3 siblings, 3 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-12 16:48 UTC (permalink / raw)
To: git
Cc: Philippe Blain, Britton Leo Kerin, Elijah Newren,
Rubén Justo, Patrick Steinhardt, D. Ben Knoble,
SZEDER Gábor
Continuing from the previous 'git [-C <dir>] diff' series, these two
patches correct completion for 'git checkout [-C <dir>] path<TAB>',
but without falling back to untracked paths, as "checkout paths out
of the index" is by definition about paths that appear in the index.
This has been rebuilt on the v6 iteration of the 'complete-diff'
topic to give the tests a more structured and logical organization.
Additionally, [PATCH 3/3] is new. It teaches the completion
machinery to complete untracked paths in the working tree, which may
be of limited use, as it is unlikely that a file tracked on another
branch (and thus capable of being restored with 'git checkout
another-branch path') would be lying around untracked in the working
tree to begin with.
1/3: completion: no-op refactoring of checkout completion
2/3: completion: complete tracked paths for "git checkout"
3/3: completion: 'git checkout' completes untracked paths as a last
resort
contrib/completion/git-completion.bash | 88 ++++++++++++++------------
t/t9902-completion.sh | 56 ++++++++++++++++
2 files changed, 105 insertions(+), 39 deletions(-)
Range-diff against v1:
1: f35017f5c9 = 1: d3b022ac73 completion: no-op refactoring of checkout completion
2: 20d57f0336 ! 2: 85019fbf97 completion: complete tracked paths for "git checkout"
@@ contrib/completion/git-completion.bash: _git_checkout ()
fi
+
+ if [ ${#COMPREPLY[@]} -eq 0 ]; then
-+ __git_complete_index_file
++ __git_complete_index_file ""
+ fi
}
@@ t/t9902-completion.sh: test_expect_success 'git -C <path> checkout uses the righ
'
+test_expect_success 'git checkout completes tracked paths when no refs match' '
-+ # file1 and file2 are tracked but ufile is not
++ # file1 and file2 are tracked but file3 is not
+ # there is no ref that begins with f
+ test_completion "git checkout f" <<-\EOF &&
+ file1
@@ t/t9902-completion.sh: test_expect_success 'git -C <path> checkout uses the righ
+ EOF
+'
+
-+test_expect_success 'git -C <path> checkout completes tracked paths in specified repo' '
++test_expect_success 'git -C <path> checkout completes paths in specified repo' '
++ # otherfile is tracked, oops is not
++ # lostfile is tracked but lost
+ test_when_finished "rm -rf repo-for-checkout" &&
+ git init repo-for-checkout &&
+ echo content >repo-for-checkout/otherfile &&
++ echo content >repo-for-checkout/lostfile &&
+ git -C repo-for-checkout add otherfile &&
++ git -C repo-for-checkout add lostfile &&
+ git -C repo-for-checkout commit -m otherfile &&
++ echo untracked >repo-for-checkout/oops &&
++ rm -f repo-for-checkout/lostfile &&
+ test_completion "git -C repo-for-checkout checkout o" <<-\EOF &&
+ otherfile
+ EOF
-+ test_completion "git -C repo-for-checkout checkout -- o" <<-\EOF
++ test_completion "git -C repo-for-checkout checkout -- o" <<-\EOF &&
+ otherfile
+ EOF
++ test_completion "git -C repo-for-checkout checkout l" <<-\EOF &&
++ lostfile
++ EOF
++ test_completion "git -C repo-for-checkout checkout -- l" <<-\EOF
++ lostfile
++ EOF
+'
+
test_expect_success 'git diff completes tracked paths when no refs match' '
-: ---------- > 3: 56aade8759 completion: 'git checkout' completes untracked paths as a last resort
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 1/3] completion: no-op refactoring of checkout completion
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
@ 2026-08-12 16:48 ` Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 2/3] completion: complete tracked paths for "git checkout" Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 3/3] completion: 'git checkout' completes untracked paths as a last resort Junio C Hamano
2 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-12 16:48 UTC (permalink / raw)
To: git
The 'git checkout' completion function punts very early when it sees
'--' on the command line, as it indicates that options or revisions
can no longer appear. By returning early, it allows the default
Bash action (which completes files in '$PWD') to kick in.
In preparation for changing what happens in the next step when
option or revision completion yields no matching candidates, or when
'--' is present, reorganize the control flow to avoid this early
return, and add explicit returns to the option completion branches.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
contrib/completion/git-completion.bash | 84 +++++++++++++-------------
1 file changed, 43 insertions(+), 41 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d35b4f3024..38dec1cabe 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1735,49 +1735,51 @@ __git_checkout_default_dwim_mode ()
_git_checkout ()
{
- __git_has_doubledash && return
-
- local dwim_opt="$(__git_checkout_default_dwim_mode)"
-
- case "$prev" in
- -b|-B|--orphan)
- # Complete local branches (and DWIM branch
- # remote branch names) for an option argument
- # specifying a new branch name. This is for
- # convenience, assuming new branches are
- # possibly based on pre-existing branch names.
- __git_complete_refs $dwim_opt --mode="heads"
- return
- ;;
- *)
- ;;
- esac
+ if ! __git_has_doubledash; then
+ local dwim_opt="$(__git_checkout_default_dwim_mode)"
- case "$cur" in
- --conflict=*)
- __gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
- ;;
- --*)
- __gitcomp_builtin checkout
- ;;
- *)
- # At this point, we've already handled special completion for
- # the arguments to -b/-B, and --orphan. There are 3 main
- # things left we can possibly complete:
- # 1) a start-point for -b/-B, -d/--detach, or --orphan
- # 2) a remote head, for --track
- # 3) an arbitrary reference, possibly including DWIM names
- #
+ case "$prev" in
+ -b|-B|--orphan)
+ # Complete local branches (and DWIM branch
+ # remote branch names) for an option argument
+ # specifying a new branch name. This is for
+ # convenience, assuming new branches are
+ # possibly based on pre-existing branch names.
+ __git_complete_refs $dwim_opt --mode="heads"
+ return
+ ;;
+ *)
+ ;;
+ esac
- if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
- __git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
- __git_complete_refs --mode="remote-heads"
- else
- __git_complete_refs $dwim_opt --mode="refs"
- fi
- ;;
- esac
+ case "$cur" in
+ --conflict=*)
+ __gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
+ return
+ ;;
+ --*)
+ __gitcomp_builtin checkout
+ return
+ ;;
+ *)
+ # At this point, we've already handled special completion for
+ # the arguments to -b/-B, and --orphan. There are 3 main
+ # things left we can possibly complete:
+ # 1) a start-point for -b/-B, -d/--detach, or --orphan
+ # 2) a remote head, for --track
+ # 3) an arbitrary reference, possibly including DWIM names
+ #
+
+ if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
+ __git_complete_refs --mode="refs"
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
+ __git_complete_refs --mode="remote-heads"
+ else
+ __git_complete_refs $dwim_opt --mode="refs"
+ fi
+ ;;
+ esac
+ fi
}
__git_sequencer_inprogress_options="--continue --quit --abort --skip"
--
2.55.0-721-g26b8014fc4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 2/3] completion: complete tracked paths for "git checkout"
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 1/3] completion: no-op refactoring of checkout completion Junio C Hamano
@ 2026-08-12 16:48 ` Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 3/3] completion: 'git checkout' completes untracked paths as a last resort Junio C Hamano
2 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-12 16:48 UTC (permalink / raw)
To: git
When completing arguments for "git checkout", _git_checkout()
delegates to __git_complete_refs(), which only completes revision
references. This is good, as mixing revisions and paths in a single
list from which the user can choose is confusing. However, if no
reference matches, or if "--" is given, _git_checkout() leaves
COMPREPLY empty. Bash then falls back to the default filename
completion in $PWD.
This fails when "git -C <path>" is used, as $PWD is not the target
repository.
Update _git_checkout() to use __git_complete_index_file() when "--"
is present, or when revision reference completion yields no matching
candidates, so that tracked paths are offered as candidates.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
contrib/completion/git-completion.bash | 4 +++
t/t9902-completion.sh | 39 ++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 38dec1cabe..0eecfcbf8b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1780,6 +1780,10 @@ _git_checkout ()
;;
esac
fi
+
+ if [ ${#COMPREPLY[@]} -eq 0 ]; then
+ __git_complete_index_file ""
+ fi
}
__git_sequencer_inprogress_options="--continue --quit --abort --skip"
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index b889ec8c77..13fa5c65c3 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2714,6 +2714,45 @@ test_expect_success 'git -C <path> checkout uses the right repo' '
EOF
'
+test_expect_success 'git checkout completes tracked paths when no refs match' '
+ # file1 and file2 are tracked but file3 is not
+ # there is no ref that begins with f
+ test_completion "git checkout f" <<-\EOF &&
+ file1
+ file2
+ EOF
+ test_completion "git checkout -- f" <<-\EOF
+ file1
+ file2
+ EOF
+'
+
+test_expect_success 'git -C <path> checkout completes paths in specified repo' '
+ # otherfile is tracked, oops is not
+ # lostfile is tracked but lost
+ test_when_finished "rm -rf repo-for-checkout" &&
+ git init repo-for-checkout &&
+ echo content >repo-for-checkout/otherfile &&
+ echo content >repo-for-checkout/lostfile &&
+ git -C repo-for-checkout add otherfile &&
+ git -C repo-for-checkout add lostfile &&
+ git -C repo-for-checkout commit -m otherfile &&
+ echo untracked >repo-for-checkout/oops &&
+ rm -f repo-for-checkout/lostfile &&
+ test_completion "git -C repo-for-checkout checkout o" <<-\EOF &&
+ otherfile
+ EOF
+ test_completion "git -C repo-for-checkout checkout -- o" <<-\EOF &&
+ otherfile
+ EOF
+ test_completion "git -C repo-for-checkout checkout l" <<-\EOF &&
+ lostfile
+ EOF
+ test_completion "git -C repo-for-checkout checkout -- l" <<-\EOF
+ lostfile
+ EOF
+'
+
test_expect_success 'git diff completes tracked paths when no refs match' '
# file1 and file2 are tracked but file3 is not
# there is no ref that begins with f
--
2.55.0-721-g26b8014fc4
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v2 3/3] completion: 'git checkout' completes untracked paths as a last resort
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 1/3] completion: no-op refactoring of checkout completion Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 2/3] completion: complete tracked paths for "git checkout" Junio C Hamano
@ 2026-08-12 16:48 ` Junio C Hamano
2 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-08-12 16:48 UTC (permalink / raw)
To: git
We taught 'git checkout' to first try to complete revisions (unless
'--' is present on the command line) and, failing that, to complete
tracked paths. If this yields nothing, it lets the Bash default,
which offers paths in $PWD, kick in.
Teach it to complete untracked paths before giving up and letting
the Bash default kick in. With this change,
$ git -C another-directory checkout un<TAB>
finds the 'untracked' file in another-directory and offers it as a
completion candidate.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
contrib/completion/git-completion.bash | 4 ++++
t/t9902-completion.sh | 21 +++++++++++++++++++--
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 0eecfcbf8b..22c53697ab 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1784,6 +1784,10 @@ _git_checkout ()
if [ ${#COMPREPLY[@]} -eq 0 ]; then
__git_complete_index_file ""
fi
+
+ if [ ${#COMPREPLY[@]} -eq 0 ]; then
+ __git_complete_index_file "--others"
+ fi
}
__git_sequencer_inprogress_options="--continue --quit --abort --skip"
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 13fa5c65c3..e8418f069b 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2727,9 +2727,19 @@ test_expect_success 'git checkout completes tracked paths when no refs match' '
EOF
'
+test_expect_success 'git checkout completes untracked paths, too' '
+ # ufile is not tracked and there is no ref that begins with u
+ test_completion "git checkout u" <<-\EOF &&
+ ufile
+ EOF
+ test_completion "git checkout -- u" <<-\EOF
+ ufile
+ EOF
+'
+
test_expect_success 'git -C <path> checkout completes paths in specified repo' '
# otherfile is tracked, oops is not
- # lostfile is tracked but lost
+ # lostfile is tracked but lost, ufile is untracked.
test_when_finished "rm -rf repo-for-checkout" &&
git init repo-for-checkout &&
echo content >repo-for-checkout/otherfile &&
@@ -2738,6 +2748,7 @@ test_expect_success 'git -C <path> checkout completes paths in specified repo' '
git -C repo-for-checkout add lostfile &&
git -C repo-for-checkout commit -m otherfile &&
echo untracked >repo-for-checkout/oops &&
+ echo untracked >repo-for-checkout/ufile &&
rm -f repo-for-checkout/lostfile &&
test_completion "git -C repo-for-checkout checkout o" <<-\EOF &&
otherfile
@@ -2748,9 +2759,15 @@ test_expect_success 'git -C <path> checkout completes paths in specified repo' '
test_completion "git -C repo-for-checkout checkout l" <<-\EOF &&
lostfile
EOF
- test_completion "git -C repo-for-checkout checkout -- l" <<-\EOF
+ test_completion "git -C repo-for-checkout checkout -- l" <<-\EOF &&
lostfile
EOF
+ test_completion "git -C repo-for-checkout checkout u" <<-\EOF &&
+ ufile
+ EOF
+ test_completion "git -C repo-for-checkout checkout -- u" <<-\EOF
+ ufile
+ EOF
'
test_expect_success 'git diff completes tracked paths when no refs match' '
--
2.55.0-721-g26b8014fc4
^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-08-12 16:48 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-11 3:19 [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
2026-08-11 3:21 ` [PATCH 1/2] completion: no-op refactoring of checkout completion Junio C Hamano
2026-08-11 3:21 ` [PATCH 2/2] completion: complete tracked paths for "git checkout" Junio C Hamano
2026-08-11 16:32 ` Ben Knoble
2026-08-11 17:25 ` Junio C Hamano
2026-08-11 4:04 ` [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
2026-08-11 16:33 ` Ben Knoble
2026-08-12 1:45 ` Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 0/3] " Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 1/3] completion: no-op refactoring of checkout completion Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 2/3] completion: complete tracked paths for "git checkout" Junio C Hamano
2026-08-12 16:48 ` [PATCH v2 3/3] completion: 'git checkout' completes untracked paths as a last resort Junio C Hamano
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox