Git development
 help / color / mirror / Atom feed
* [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
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ 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] 7+ 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
  2026-08-11  4:04 ` [PATCH 0/2] completion of 'git [-C <dir>] checkout' Junio C Hamano
  2 siblings, 0 replies; 7+ 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] 7+ 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
  2 siblings, 1 reply; 7+ 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] 7+ 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
  2 siblings, 1 reply; 7+ 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] 7+ 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; 7+ 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] 7+ 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
  0 siblings, 0 replies; 7+ 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] 7+ 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; 7+ 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] 7+ messages in thread

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

Thread overview: 7+ 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

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