Volume XXII, number 279Tuesday, October 6, 2026Latest message 52 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

patchcompletion: hide dotfiles for selected path completion

14 messages between May 24, 2026 and Jul 23, 2026, from Zakariyah Ali via GitGitGadget, Junio C Hamano, Zakariyah Ali, D. Ben Knoble.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

Zakariyah Ali via GitGitGadgetMay 24, 2026, 02:36 UTC on lore
From: Zakariyah Ali <zakariyahali100@gmail.com>
Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
---
    completion: hide dotfiles for selected path completion
    
    The completion helper for index paths uses git ls-files rather than
    shell filename completion. As a result, leading-dot paths such as a
    tracked .gitignore were offered even when the user had not started the
    path with ..
    
    Hide leading-dot path components for git rm, git mv, and git ls-files
    when completing an empty path component. Explicit dot completion is
    still preserved, so git rm . can still complete .gitignore.
    
    This removes the existing TODO expectations in t/t9902-completion.sh and
    adds coverage for explicit dot completion.
    
    Validation:
    
     * git diff --check -- contrib/completion/git-completion.bash
       t/t9902-completion.sh
     * bash -n contrib/completion/git-completion.bash
     * ./t9902-completion.sh
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2311%2Falibaba0010%2Fcompletion-hide-dotfiles-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2311/alibaba0010/completion-hide-dotfiles-v1
Pull-Request: https://github.com/git/git/pull/2311
 contrib/completion/git-completion.bash | 36 +++++++++++++++++---------
 t/t9902-completion.sh                  | 10 ++-----
 2 files changed, 26 insertions(+), 20 deletions(-)
Show changes to 2 files +26 −20

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index a8e7c6ddbf..e8f8fab125 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -638,25 +638,33 @@ __git_ls_files_helper ()
 }
 
 
-# __git_index_files accepts 1 or 2 arguments:
+# __git_index_files accepts 1 to 4 arguments:
 # 1: Options to pass to ls-files (required).
 # 2: A directory path (optional).
 #    If provided, only files within the specified directory are listed.
 #    Sub directories are never recursed.  Path must have a trailing
 #    slash.
 # 3: List only paths matching this path component (optional).
+# 4: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the third argument is empty (optional).
 __git_index_files ()
 {
-	local root="$2" match="$3"
+	local root="$2" match="$3" hide_dotfiles="${4-}"
+	local hide_dotfiles_awk=0
+	if [ "$hide_dotfiles" = "hide-dotfiles" ] && [ -z "$match" ]; then
+		hide_dotfiles_awk=1
+	fi
 
 	__git_ls_files_helper "$root" "$1" "${match:-?}" |
-	awk -F / -v pfx="${2//\\/\\\\}" '{
+	awk -F / -v pfx="${2//\\/\\\\}" -v hide_dotfiles="$hide_dotfiles_awk" '{
 		paths[$1] = 1
 	}
 	END {
 		for (p in paths) {
 			if (substr(p, 1, 1) != "\"") {
 				# No special characters, easy!
+				if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+					continue
 				print pfx p
 				continue
 			}
@@ -675,8 +683,10 @@ __git_index_files ()
 				# We have seen the same directory unquoted,
 				# skip it.
 				continue
-			else
-				print pfx p
+
+			if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+				continue
+			print pfx p
 		}
 	}
 	function dequote(p,    bs_idx, out, esc, esc_idx, dec) {
@@ -721,13 +731,15 @@ __git_index_files ()
 	}'
 }
 
-# __git_complete_index_file requires 1 argument:
+# __git_complete_index_file accepts 1 or 2 arguments:
 # 1: the options to pass to ls-file
+# 2: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the current word is empty (optional).
 #
 # The exception is --committable, which finds the files appropriate commit.
 __git_complete_index_file ()
 {
-	local dequoted_word pfx="" cur_
+	local dequoted_word pfx="" cur_ hide_dotfiles="${2-}"
 
 	__git_dequote "$cur"
 
@@ -740,7 +752,7 @@ __git_complete_index_file ()
 		cur_="$dequoted_word"
 	esac
 
-	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_" "$hide_dotfiles")"
 }
 
 # Lists branches from the local repository.
@@ -2164,7 +2176,7 @@ _git_ls_files ()
 
 	# XXX ignore options like --modified and always suggest all cached
 	# files.
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_ls_remote ()
@@ -2397,9 +2409,9 @@ _git_mv ()
 	if [ $(__git_count_arguments "mv") -gt 0 ]; then
 		# We need to show both cached and untracked files (including
 		# empty directories) since this may not be the last argument.
-		__git_complete_index_file "--cached --others --directory"
+		__git_complete_index_file "--cached --others --directory" hide-dotfiles
 	else
-		__git_complete_index_file "--cached"
+		__git_complete_index_file "--cached" hide-dotfiles
 	fi
 }
 
@@ -3219,7 +3231,7 @@ _git_rm ()
 		;;
 	esac
 
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_shortlog ()
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 28f61f08fb..02aaf71876 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2811,17 +2811,15 @@ test_expect_success 'complete files' '
 
 	touch untracked &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git rm " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
+	test_completion "git rm ." ".gitignore" &&
+
 	test_completion "git clean " "untracked" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
@@ -2832,9 +2830,7 @@ test_expect_success 'complete files' '
 
 	mkdir untracked-dir &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv modified " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	untracked
@@ -2843,9 +2839,7 @@ test_expect_success 'complete files' '
 
 	test_completion "git commit " "modified" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git ls-files " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	EOF

base-commit: 9b7fa37559a1b95ee32e32858b0d038b4cf583e5
-- 
gitgitgadget
Junio C HamanoMay 24, 2026, 12:08 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 10 quoted lines
> From: Zakariyah Ali <zakariyahali100@gmail.com>
>
> Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
> ---
>     completion: hide dotfiles for selected path completion
>     
>     The completion helper for index paths uses git ls-files rather than
>     shell filename completion. As a result, leading-dot paths such as a
>     tracked .gitignore were offered even when the user had not started the
>     path with ..
Writing 'path with ".".' would have been easieer to grok.
>     Hide leading-dot path components for git rm, git mv, and git ls-files
>     when completing an empty path component. Explicit dot completion is
>     still preserved, so git rm . can still complete .gitignore.

I am not sure why this is a good idea. If we said "git rm g<TAB> and offered ".gitignore" as a candidate, it may be annoying, but tracked (or untracked for that matter) ".gitignore" and "gitfoo" should be treated the same way by "git rm <TAB>" no?

>     This removes the existing TODO expectations in t/t9902-completion.sh and
>     adds coverage for explicit dot completion.

In any case, all of the above should be in the proposed log message, not below the three-dash line.

Zakariyah Ali via GitGitGadgetMay 26, 2026, 15:23 UTC in reply to Zakariyah Ali via GitGitGadget on lore

[PATCH v2] completion: hide dotfiles for selected path completion

From: Zakariyah Ali <zakariyahali100@gmail.com>

The completion helper for index paths uses git ls-files rather than shell filename completion. As a result, leading-dot paths such as a tracked .gitignore were offered even when the user had not started the path with ".".

Hide leading-dot path components for git rm, git mv, and git ls-files when completing an empty path component. Explicit dot completion is still preserved, so git rm . can still complete .gitignore.

This matches standard shell filename completion behavior, where dotfiles are hidden by default unless the user starts their input with a dot. This also resolves four TODO comments in t/9902-completion.sh which have been present since 2013 (commit ddf07bddef9a, "completion: add file completion tests", 2013-04-27), expecting that .gitignore would not be shown when completing on an empty path component.

Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
---
    completion: hide dotfiles for selected path completion
    
    The completion helper for index paths uses git ls-files rather than
    shell filename completion. As a result, leading-dot paths such as a
    tracked .gitignore were offered even when the user had not started the
    path with ..
    
    Hide leading-dot path components for git rm, git mv, and git ls-files
    when completing an empty path component. Explicit dot completion is
    still preserved, so git rm . can still complete .gitignore.
    
    This removes the existing TODO expectations in t/t9902-completion.sh and
    adds coverage for explicit dot completion.
    
    Validation:
    
     * git diff --check -- contrib/completion/git-completion.bash
       t/t9902-completion.sh
     * bash -n contrib/completion/git-completion.bash
     * ./t9902-completion.sh
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2311%2Falibaba0010%2Fcompletion-hide-dotfiles-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2311/alibaba0010/completion-hide-dotfiles-v2
Pull-Request: https://github.com/git/git/pull/2311
Range-diff vs v1:
 1:  5ccb408fd5 ! 1:  056e239e06 completion: hide dotfiles for selected path completion
     @@ Metadata
       ## Commit message ##
          completion: hide dotfiles for selected path completion
      
     +    The completion helper for index paths uses git ls-files rather than
     +    shell filename completion. As a result, leading-dot paths such as a
     +    tracked .gitignore were offered even when the user had not started the
     +    path with ".".
     +
     +    Hide leading-dot path components for git rm, git mv, and git ls-files
     +    when completing an empty path component. Explicit dot completion is
     +    still preserved, so git rm . can still complete .gitignore.
     +
     +    This matches standard shell filename completion behavior, where dotfiles
     +    are hidden by default unless the user starts their input with a dot.
     +    This also resolves four TODO comments in t/9902-completion.sh which
     +    have been present since 2013 (commit ddf07bddef9a, "completion: add file
     +    completion tests", 2013-04-27), expecting that .gitignore would not be
     +    shown when completing on an empty path component.
     +
          Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
      
       ## contrib/completion/git-completion.bash ##
 contrib/completion/git-completion.bash | 36 +++++++++++++++++---------
 t/t9902-completion.sh                  | 10 ++-----
 2 files changed, 26 insertions(+), 20 deletions(-)
Show changes to 2 files +26 −20

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index a8e7c6ddbf..e8f8fab125 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -638,25 +638,33 @@ __git_ls_files_helper ()
 }
 
 
-# __git_index_files accepts 1 or 2 arguments:
+# __git_index_files accepts 1 to 4 arguments:
 # 1: Options to pass to ls-files (required).
 # 2: A directory path (optional).
 #    If provided, only files within the specified directory are listed.
 #    Sub directories are never recursed.  Path must have a trailing
 #    slash.
 # 3: List only paths matching this path component (optional).
+# 4: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the third argument is empty (optional).
 __git_index_files ()
 {
-	local root="$2" match="$3"
+	local root="$2" match="$3" hide_dotfiles="${4-}"
+	local hide_dotfiles_awk=0
+	if [ "$hide_dotfiles" = "hide-dotfiles" ] && [ -z "$match" ]; then
+		hide_dotfiles_awk=1
+	fi
 
 	__git_ls_files_helper "$root" "$1" "${match:-?}" |
-	awk -F / -v pfx="${2//\\/\\\\}" '{
+	awk -F / -v pfx="${2//\\/\\\\}" -v hide_dotfiles="$hide_dotfiles_awk" '{
 		paths[$1] = 1
 	}
 	END {
 		for (p in paths) {
 			if (substr(p, 1, 1) != "\"") {
 				# No special characters, easy!
+				if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+					continue
 				print pfx p
 				continue
 			}
@@ -675,8 +683,10 @@ __git_index_files ()
 				# We have seen the same directory unquoted,
 				# skip it.
 				continue
-			else
-				print pfx p
+
+			if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+				continue
+			print pfx p
 		}
 	}
 	function dequote(p,    bs_idx, out, esc, esc_idx, dec) {
@@ -721,13 +731,15 @@ __git_index_files ()
 	}'
 }
 
-# __git_complete_index_file requires 1 argument:
+# __git_complete_index_file accepts 1 or 2 arguments:
 # 1: the options to pass to ls-file
+# 2: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the current word is empty (optional).
 #
 # The exception is --committable, which finds the files appropriate commit.
 __git_complete_index_file ()
 {
-	local dequoted_word pfx="" cur_
+	local dequoted_word pfx="" cur_ hide_dotfiles="${2-}"
 
 	__git_dequote "$cur"
 
@@ -740,7 +752,7 @@ __git_complete_index_file ()
 		cur_="$dequoted_word"
 	esac
 
-	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_" "$hide_dotfiles")"
 }
 
 # Lists branches from the local repository.
@@ -2164,7 +2176,7 @@ _git_ls_files ()
 
 	# XXX ignore options like --modified and always suggest all cached
 	# files.
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_ls_remote ()
@@ -2397,9 +2409,9 @@ _git_mv ()
 	if [ $(__git_count_arguments "mv") -gt 0 ]; then
 		# We need to show both cached and untracked files (including
 		# empty directories) since this may not be the last argument.
-		__git_complete_index_file "--cached --others --directory"
+		__git_complete_index_file "--cached --others --directory" hide-dotfiles
 	else
-		__git_complete_index_file "--cached"
+		__git_complete_index_file "--cached" hide-dotfiles
 	fi
 }
 
@@ -3219,7 +3231,7 @@ _git_rm ()
 		;;
 	esac
 
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_shortlog ()
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 28f61f08fb..02aaf71876 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2811,17 +2811,15 @@ test_expect_success 'complete files' '
 
 	touch untracked &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git rm " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
+	test_completion "git rm ." ".gitignore" &&
+
 	test_completion "git clean " "untracked" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
@@ -2832,9 +2830,7 @@ test_expect_success 'complete files' '
 
 	mkdir untracked-dir &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv modified " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	untracked
@@ -2843,9 +2839,7 @@ test_expect_success 'complete files' '
 
 	test_completion "git commit " "modified" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git ls-files " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	EOF

base-commit: 9b7fa37559a1b95ee32e32858b0d038b4cf583e5
-- 
gitgitgadget
Junio C HamanoMay 27, 2026, 03:22 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH v2] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
> This matches standard shell filename completion behavior, where dotfiles
> are hidden by default unless the user starts their input with a dot.

OK, with this rationale added, I no longer have problem with the proposed new behaviour.

As I'm not going to give a serious review on the patch body itself, I would really appreciate somebody more knowledgeable on the existing bach completion code than I am to take a look.

Thanks.
Zakariyah AliJun 3, 2026, 18:09 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Follow-up and appreciation regarding Git contributions

Dear Junio,
I hope you are doing well.
I wanted to briefly follow up on my recent patch submission (Message-ID: <pull.2311.v2.git.git.1779808987825.gitgitgadget@gmail.com>). Thank you for accepting the rationale for the new behavior! Since you mentioned it would be helpful for someone more familiar with the bash completion code to review the patch itself, I wanted to ask if there is anyone specific I should CC, or if I should simply wait for another reviewer to pick it up. I would be grateful if you would let me know if there is anything else needed from my side.
Also, thank you again for the detailed reviews and guidance on my recent Git contributions. Your feedback on patch structure, commit messaging, and contribution workflow has been extremely valuable, and I genuinely appreciate the time you invest in reviewing contributions from newer developers.
Separately, I also wanted to ask for your advice professionally. I am a software engineer with over four years of experience, currently looking for entry-level or internship opportunities where I can continue growing as a systems and open-source developer. If you happen to know of any relevant opportunities, or have suggestions on how I might better position myself through open-source work  or any other opportunities, I would sincerely appreciate any guidance.
Thank you again for your time and for maintaining such a high-quality development and review culture around Git.

Best regards, Zakariyah Ali.

Junio C HamanoJun 10, 2026, 18:56 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH v2] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 45 quoted lines
> -# __git_index_files accepts 1 or 2 arguments:
> +# __git_index_files accepts 1 to 4 arguments:
>  # 1: Options to pass to ls-files (required).
>  # 2: A directory path (optional).
>  #    If provided, only files within the specified directory are listed.
>  #    Sub directories are never recursed.  Path must have a trailing
>  #    slash.
>  # 3: List only paths matching this path component (optional).
> +# 4: Hide paths whose first component starts with a dot if this is
> +#    "hide-dotfiles" and the third argument is empty (optional).
>  __git_index_files ()
>  {
> -	local root="$2" match="$3"
> +	local root="$2" match="$3" hide_dotfiles="${4-}"
> +	local hide_dotfiles_awk=0
> +	if [ "$hide_dotfiles" = "hide-dotfiles" ] && [ -z "$match" ]; then
> +		hide_dotfiles_awk=1
> +	fi
>  
>  	__git_ls_files_helper "$root" "$1" "${match:-?}" |
> -	awk -F / -v pfx="${2//\\/\\\\}" '{
> +	awk -F / -v pfx="${2//\\/\\\\}" -v hide_dotfiles="$hide_dotfiles_awk" '{
>  		paths[$1] = 1
>  	}
>  	END {
>  		for (p in paths) {
>  			if (substr(p, 1, 1) != "\"") {
>  				# No special characters, easy!
> +				if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
> +					continue
>  				print pfx p
>  				continue
>  			}
> @@ -675,8 +683,10 @@ __git_index_files ()
>  				# We have seen the same directory unquoted,
>  				# skip it.
>  				continue
> -			else
> -				print pfx p
> +
> +			if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
> +				continue
> +			print pfx p
>  		}
>  	}

Having to repeat the same thing twice here is a bit unsatisfying, but that is not a fault of this addition. I suspect that it would have been simpler to patch if the original were first simplified into something like:

	for (p in paths) {
		if (substr(p, 1, 1) == "\"") {
			p = dequote(p);
			if ((p == "") || (p in paths))
				continue
		}
                print pfx p
	}

Then the new "ah, that thing begins with a dot" logic can be added only once and at an obvious place.

Show 7 quoted lines
> @@ -2164,7 +2176,7 @@ _git_ls_files ()
>  
>  	# XXX ignore options like --modified and always suggest all cached
>  	# files.
> -	__git_complete_index_file "--cached"
> +	__git_complete_index_file "--cached" hide-dotfiles
>  }

In this patch, it is hard to tell from the patch what _other_ calls to the __git_complete_index_file helper lack hide-dotfiles flag (i.e., they are to show everything including the path that begins with a dot). I will not try to be exhaustive, but for example _git_add does not get hide-dotfiles but it is unclear why. The same for _clean, _commit. But _mv does hide them. The choice seems arbitrary and incoherent.

A few ideas (some of them may be mutually incompatible)
 * Instead of "empty vs hide-dotfiles", perhaps make the 2nd option
   mandatory for __git_complete_index_file, e.g., "hide-" vs
   "include-" dotfiles, to make it easier to see in the patch which
   ones exclude and which ones include dotfiles.
 * Extend comments like we saw in the above hunk to say why we treat
   files that begin with dot specially.
 * Make __git_complete_index_file unconditionally hide the dotfiles
   when there is no match pattern for consistency (getting rid of
   the need to explay why).
Zakariyah Ali via GitGitGadgetJun 20, 2026, 17:55 UTC in reply to Zakariyah Ali via GitGitGadget on lore

[PATCH v3 0/2] completion: hide dotfiles for selected path completion

The completion helper for index paths uses git ls-files rather than shell filename completion. As a result, leading-dot paths such as a tracked .gitignore were offered even when the user had not started the path with ..

Hide leading-dot path components for git rm, git mv, and git ls-files when completing an empty path component. Explicit dot completion is still preserved, so git rm . can still complete .gitignore.

This removes the existing TODO expectations in t/t9902-completion.sh and adds coverage for explicit dot completion.

Validation:
 * git diff --check -- contrib/completion/git-completion.bash
   t/t9902-completion.sh
 * bash -n contrib/completion/git-completion.bash
 * ./t9902-completion.sh
Zakariyah Ali (2):
  completion: hide dotfiles for selected path completion
  completion: hide dotfiles by default for path completion
 contrib/completion/git-completion.bash | 53 +++++++++++++++-----------
 t/t9902-completion.sh                  | 19 ++++-----
 2 files changed, 40 insertions(+), 32 deletions(-)
base-commit: 9b7fa37559a1b95ee32e32858b0d038b4cf583e5
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2311%2Falibaba0010%2Fcompletion-hide-dotfiles-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2311/alibaba0010/completion-hide-dotfiles-v3
Pull-Request: https://github.com/git/git/pull/2311
Range-diff vs v2:
 1:  056e239e06 = 1:  056e239e06 completion: hide dotfiles for selected path completion
 -:  ---------- > 2:  7482ee4645 completion: hide dotfiles by default for path completion
-- 
gitgitgadget
Zakariyah Ali via GitGitGadgetJun 20, 2026, 17:55 UTC in reply to Zakariyah Ali via GitGitGadget on lore

[PATCH v3 1/2] completion: hide dotfiles for selected path completion

From: Zakariyah Ali <zakariyahali100@gmail.com>

The completion helper for index paths uses git ls-files rather than shell filename completion. As a result, leading-dot paths such as a tracked .gitignore were offered even when the user had not started the path with ".".

Hide leading-dot path components for git rm, git mv, and git ls-files when completing an empty path component. Explicit dot completion is still preserved, so git rm . can still complete .gitignore.

This matches standard shell filename completion behavior, where dotfiles are hidden by default unless the user starts their input with a dot. This also resolves four TODO comments in t/9902-completion.sh which have been present since 2013 (commit ddf07bddef9a, "completion: add file completion tests", 2013-04-27), expecting that .gitignore would not be shown when completing on an empty path component.

Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
---
 contrib/completion/git-completion.bash | 36 +++++++++++++++++---------
 t/t9902-completion.sh                  | 10 ++-----
 2 files changed, 26 insertions(+), 20 deletions(-)
Show changes to 2 files +26 −20

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index a8e7c6ddbf..e8f8fab125 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -638,25 +638,33 @@ __git_ls_files_helper ()
 }
 
 
-# __git_index_files accepts 1 or 2 arguments:
+# __git_index_files accepts 1 to 4 arguments:
 # 1: Options to pass to ls-files (required).
 # 2: A directory path (optional).
 #    If provided, only files within the specified directory are listed.
 #    Sub directories are never recursed.  Path must have a trailing
 #    slash.
 # 3: List only paths matching this path component (optional).
+# 4: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the third argument is empty (optional).
 __git_index_files ()
 {
-	local root="$2" match="$3"
+	local root="$2" match="$3" hide_dotfiles="${4-}"
+	local hide_dotfiles_awk=0
+	if [ "$hide_dotfiles" = "hide-dotfiles" ] && [ -z "$match" ]; then
+		hide_dotfiles_awk=1
+	fi
 
 	__git_ls_files_helper "$root" "$1" "${match:-?}" |
-	awk -F / -v pfx="${2//\\/\\\\}" '{
+	awk -F / -v pfx="${2//\\/\\\\}" -v hide_dotfiles="$hide_dotfiles_awk" '{
 		paths[$1] = 1
 	}
 	END {
 		for (p in paths) {
 			if (substr(p, 1, 1) != "\"") {
 				# No special characters, easy!
+				if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+					continue
 				print pfx p
 				continue
 			}
@@ -675,8 +683,10 @@ __git_index_files ()
 				# We have seen the same directory unquoted,
 				# skip it.
 				continue
-			else
-				print pfx p
+
+			if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+				continue
+			print pfx p
 		}
 	}
 	function dequote(p,    bs_idx, out, esc, esc_idx, dec) {
@@ -721,13 +731,15 @@ __git_index_files ()
 	}'
 }
 
-# __git_complete_index_file requires 1 argument:
+# __git_complete_index_file accepts 1 or 2 arguments:
 # 1: the options to pass to ls-file
+# 2: Hide paths whose first component starts with a dot if this is
+#    "hide-dotfiles" and the current word is empty (optional).
 #
 # The exception is --committable, which finds the files appropriate commit.
 __git_complete_index_file ()
 {
-	local dequoted_word pfx="" cur_
+	local dequoted_word pfx="" cur_ hide_dotfiles="${2-}"
 
 	__git_dequote "$cur"
 
@@ -740,7 +752,7 @@ __git_complete_index_file ()
 		cur_="$dequoted_word"
 	esac
 
-	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_" "$hide_dotfiles")"
 }
 
 # Lists branches from the local repository.
@@ -2164,7 +2176,7 @@ _git_ls_files ()
 
 	# XXX ignore options like --modified and always suggest all cached
 	# files.
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_ls_remote ()
@@ -2397,9 +2409,9 @@ _git_mv ()
 	if [ $(__git_count_arguments "mv") -gt 0 ]; then
 		# We need to show both cached and untracked files (including
 		# empty directories) since this may not be the last argument.
-		__git_complete_index_file "--cached --others --directory"
+		__git_complete_index_file "--cached --others --directory" hide-dotfiles
 	else
-		__git_complete_index_file "--cached"
+		__git_complete_index_file "--cached" hide-dotfiles
 	fi
 }
 
@@ -3219,7 +3231,7 @@ _git_rm ()
 		;;
 	esac
 
-	__git_complete_index_file "--cached"
+	__git_complete_index_file "--cached" hide-dotfiles
 }
 
 _git_shortlog ()
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 28f61f08fb..02aaf71876 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2811,17 +2811,15 @@ test_expect_success 'complete files' '
 
 	touch untracked &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git rm " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
+	test_completion "git rm ." ".gitignore" &&
+
 	test_completion "git clean " "untracked" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv " <<-\EOF &&
-	.gitignore
 	modified
 	EOF
 
@@ -2832,9 +2830,7 @@ test_expect_success 'complete files' '
 
 	mkdir untracked-dir &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git mv modified " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	untracked
@@ -2843,9 +2839,7 @@ test_expect_success 'complete files' '
 
 	test_completion "git commit " "modified" &&
 
-	: TODO .gitignore should not be here &&
 	test_completion "git ls-files " <<-\EOF &&
-	.gitignore
 	dir
 	modified
 	EOF
-- 
gitgitgadget
Zakariyah Ali via GitGitGadgetJun 20, 2026, 17:55 UTC in reply to Zakariyah Ali via GitGitGadget on lore

[PATCH v3 2/2] completion: hide dotfiles by default for path completion

From: Zakariyah Ali <zakariyahali100@gmail.com>

The previous implementation required callers to explicitly pass a "hide-dotfiles" flag to __git_complete_index_file to avoid cluttering completions with hidden files. This led to inconsistent behavior across commands (e.g., `git add` and `git mv` behaved differently) and forced callers to maintain repetitive logic.

As suggested by Junio C Hamano, this commit simplifies the logic:
1. __git_complete_index_file now unconditionally hides dotfiles when
   no match pattern is provided.
2. The awk loop in __git_index_files is refactored to check the dotfile
   condition in a single, obvious place after handling path dequoting,
   removing the previous duplication.
3. Callers no longer need to pass "hide-dotfiles".

This provides a cleaner API and ensures a consistent, expected behavior where dotfiles are hidden unless explicitly requested by typing a dot.

Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com>
---
 contrib/completion/git-completion.bash | 65 ++++++++++++--------------
 t/t9902-completion.sh                  |  9 +++-
 2 files changed, 38 insertions(+), 36 deletions(-)
Show changes to 2 files +38 −36

contrib/completion/git-completion.bash, t/t9902-completion.sh

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index e8f8fab125..b0b1b3c27a 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -638,20 +638,23 @@ __git_ls_files_helper ()
 }
 
 
-# __git_index_files accepts 1 to 4 arguments:
+# __git_index_files accepts 1 to 3 arguments:
 # 1: Options to pass to ls-files (required).
 # 2: A directory path (optional).
 #    If provided, only files within the specified directory are listed.
 #    Sub directories are never recursed.  Path must have a trailing
 #    slash.
 # 3: List only paths matching this path component (optional).
-# 4: Hide paths whose first component starts with a dot if this is
-#    "hide-dotfiles" and the third argument is empty (optional).
+#
+# If the third argument is empty, paths that begin with a dot (dotfiles)
+# are hidden. This matches user expectations where dotfiles are considered
+# hidden configuration files/directories and shouldn't clutter default
+# completions unless explicitly requested by typing a dot.
 __git_index_files ()
 {
-	local root="$2" match="$3" hide_dotfiles="${4-}"
+	local root="$2" match="$3"
 	local hide_dotfiles_awk=0
-	if [ "$hide_dotfiles" = "hide-dotfiles" ] && [ -z "$match" ]; then
+	if [ -z "$match" ]; then
 		hide_dotfiles_awk=1
 	fi
 
@@ -661,28 +664,22 @@ __git_index_files ()
 	}
 	END {
 		for (p in paths) {
-			if (substr(p, 1, 1) != "\"") {
-				# No special characters, easy!
-				if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
+			if (substr(p, 1, 1) == "\"") {
+				# The path is quoted.
+				p = dequote(p)
+				if (p == "")
 					continue
-				print pfx p
-				continue
-			}
-
-			# The path is quoted.
-			p = dequote(p)
-			if (p == "")
-				continue
 
-			# Even when a directory name itself does not contain
-			# any special characters, it will still be quoted if
-			# any of its (stripped) trailing path components do.
-			# Because of this we may have seen the same directory
-			# both quoted and unquoted.
-			if (p in paths)
-				# We have seen the same directory unquoted,
-				# skip it.
-				continue
+				# Even when a directory name itself does not contain
+				# any special characters, it will still be quoted if
+				# any of its (stripped) trailing path components do.
+				# Because of this we may have seen the same directory
+				# both quoted and unquoted.
+				if (p in paths)
+					# We have seen the same directory unquoted,
+					# skip it.
+					continue
+			}
 
 			if (hide_dotfiles == 1 && substr(p, 1, 1) == ".")
 				continue
@@ -731,15 +728,13 @@ __git_index_files ()
 	}'
 }
 
-# __git_complete_index_file accepts 1 or 2 arguments:
-# 1: the options to pass to ls-file
-# 2: Hide paths whose first component starts with a dot if this is
-#    "hide-dotfiles" and the current word is empty (optional).
+# __git_complete_index_file accepts 1 argument:
+# 1: the options to pass to ls-files
 #
 # The exception is --committable, which finds the files appropriate commit.
 __git_complete_index_file ()
 {
-	local dequoted_word pfx="" cur_ hide_dotfiles="${2-}"
+	local dequoted_word pfx="" cur_
 
 	__git_dequote "$cur"
 
@@ -752,7 +747,7 @@ __git_complete_index_file ()
 		cur_="$dequoted_word"
 	esac
 
-	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_" "$hide_dotfiles")"
+	__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
 }
 
 # Lists branches from the local repository.
@@ -2176,7 +2171,7 @@ _git_ls_files ()
 
 	# XXX ignore options like --modified and always suggest all cached
 	# files.
-	__git_complete_index_file "--cached" hide-dotfiles
+	__git_complete_index_file "--cached"
 }
 
 _git_ls_remote ()
@@ -2409,9 +2404,9 @@ _git_mv ()
 	if [ $(__git_count_arguments "mv") -gt 0 ]; then
 		# We need to show both cached and untracked files (including
 		# empty directories) since this may not be the last argument.
-		__git_complete_index_file "--cached --others --directory" hide-dotfiles
+		__git_complete_index_file "--cached --others --directory"
 	else
-		__git_complete_index_file "--cached" hide-dotfiles
+		__git_complete_index_file "--cached"
 	fi
 }
 
@@ -3231,7 +3226,7 @@ _git_rm ()
 		;;
 	esac
 
-	__git_complete_index_file "--cached" hide-dotfiles
+	__git_complete_index_file "--cached"
 }
 
 _git_shortlog ()
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 02aaf71876..7a7594455c 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2360,6 +2360,7 @@ test_expect_success 'setup for path completion tests' '
 	      "spaces in dir" \
 	      árvíztűrő &&
 	touch simple-dir/simple-file \
+	      simple-dir/.dotfile-in-dir \
 	      "spaces in dir/spaces in file" \
 	      "árvíztűrő/Сайн яваарай" &&
 	if test_have_prereq !MINGW &&
@@ -2380,6 +2381,11 @@ test_expect_success '__git_complete_index_file - simple' '
 	test_path_completion simple-dir/simple simple-dir/simple-file
 '
 
+test_expect_success '__git_complete_index_file - dotfiles' '
+	test_path_completion "simple-dir/" "simple-dir/simple-file" &&
+	test_path_completion "simple-dir/." "simple-dir/.dotfile-in-dir"
+'
+
 test_expect_success \
     '__git_complete_index_file - escaped characters on cmdline' '
 	test_path_completion spac "spaces in dir" &&  # Bash will turn this
@@ -2789,7 +2795,8 @@ test_expect_success 'complete files' '
 	echo "out_sorted" >> .gitignore &&
 
 	git add .gitignore &&
-	test_completion "git commit " ".gitignore" &&
+	test_completion "git commit " "" &&
+	test_completion "git commit ." ".gitignore" &&
 
 	git commit -m ignore &&
 
-- 
gitgitgadget
Junio C HamanoJun 21, 2026, 01:17 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH v3 0/2] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 10 quoted lines
> The completion helper for index paths uses git ls-files rather than shell
> filename completion. As a result, leading-dot paths such as a tracked
> .gitignore were offered even when the user had not started the path with ..
>
> Hide leading-dot path components for git rm, git mv, and git ls-files when
> completing an empty path component. Explicit dot completion is still
> preserved, so git rm . can still complete .gitignore.
>
> This removes the existing TODO expectations in t/t9902-completion.sh and
> adds coverage for explicit dot completion.
OK.
Show 6 quoted lines
> Validation:
>
>  * git diff --check -- contrib/completion/git-completion.bash
>    t/t9902-completion.sh
>  * bash -n contrib/completion/git-completion.bash
>  * ./t9902-completion.sh

I am not sure what you wanted to say with these lines. If you did the above to build confidence that your patch works, that would be great. Or are you telling readers to do these things and when they do not see any issues consider your patch perfect?

What is missing around here in this cover letter is a description of how this iteration is different from the previous one. And ...

Show 18 quoted lines
> Zakariyah Ali (2):
>   completion: hide dotfiles for selected path completion
>   completion: hide dotfiles by default for path completion
>
>  contrib/completion/git-completion.bash | 53 +++++++++++++++-----------
>  t/t9902-completion.sh                  | 19 ++++-----
>  2 files changed, 40 insertions(+), 32 deletions(-)
>
>
> base-commit: 9b7fa37559a1b95ee32e32858b0d038b4cf583e5
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2311%2Falibaba0010%2Fcompletion-hide-dotfiles-v3
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2311/alibaba0010/completion-hide-dotfiles-v3
> Pull-Request: https://github.com/git/git/pull/2311
>
> Range-diff vs v2:
>
>  1:  056e239e06 = 1:  056e239e06 completion: hide dotfiles for selected path completion
>  -:  ---------- > 2:  7482ee4645 completion: hide dotfiles by default for path completion

... I find this range diff very troubling. If we look at patch 2, it seems that it redoes some part of what is done in patch 1 saying "oops that was wrong, so let's do it better this time". Such a drunken-mans' walk that goes in one direction in an earlier step, only to be corrected to move to a different course, is now how we want a new topic to be presented.

The end result may be much easier to read, mostly thanks to updated loop in the awk script, so if we really want to pretend this as two patches for "small pieces are easier to digest" value, perhaps have [PATCH 1/2] that updates the awk script (without doing anything related to hide-dotfiles theme) to make it easier to read by not having multiple "print pfx p" in it, and then build on top of that improved base, have [PATCH 2/2] that adds the support to hide dotfiles, perhaps?

Since the initial iteration was quite a while ago, I no longer remember the details of the review I gave, but I recall having hard time telling which callers of the complete-index-file helper hide dotfiles from their output and which callers do not hide them, and how the patch decided to choose which ones should and should not hide. Has it been improved and if so how? That is something we expect the cover letter to tell, too.

Thanks.
D. Ben KnobleJun 21, 2026, 16:46 UTC in reply to Junio C Hamano on lore

Re: [PATCH v3 0/2] completion: hide dotfiles for selected path completion

[Small typo correction that may affect how the message is read]
On Sat, Jun 20, 2026 at 9:18 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 55 quoted lines
>
> "Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
> > The completion helper for index paths uses git ls-files rather than shell
> > filename completion. As a result, leading-dot paths such as a tracked
> > .gitignore were offered even when the user had not started the path with ..
> >
> > Hide leading-dot path components for git rm, git mv, and git ls-files when
> > completing an empty path component. Explicit dot completion is still
> > preserved, so git rm . can still complete .gitignore.
> >
> > This removes the existing TODO expectations in t/t9902-completion.sh and
> > adds coverage for explicit dot completion.
>
> OK.
>
> > Validation:
> >
> >  * git diff --check -- contrib/completion/git-completion.bash
> >    t/t9902-completion.sh
> >  * bash -n contrib/completion/git-completion.bash
> >  * ./t9902-completion.sh
>
> I am not sure what you wanted to say with these lines.  If you did
> the above to build confidence that your patch works, that would be
> great.  Or are you telling readers to do these things and when they
> do not see any issues consider your patch perfect?
>
> What is missing around here in this cover letter is a description of
> how this iteration is different from the previous one.  And ...
>
> > Zakariyah Ali (2):
> >   completion: hide dotfiles for selected path completion
> >   completion: hide dotfiles by default for path completion
> >
> >  contrib/completion/git-completion.bash | 53 +++++++++++++++-----------
> >  t/t9902-completion.sh                  | 19 ++++-----
> >  2 files changed, 40 insertions(+), 32 deletions(-)
> >
> >
> > base-commit: 9b7fa37559a1b95ee32e32858b0d038b4cf583e5
> > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2311%2Falibaba0010%2Fcompletion-hide-dotfiles-v3
> > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2311/alibaba0010/completion-hide-dotfiles-v3
> > Pull-Request: https://github.com/git/git/pull/2311
> >
> > Range-diff vs v2:
> >
> >  1:  056e239e06 = 1:  056e239e06 completion: hide dotfiles for selected path completion
> >  -:  ---------- > 2:  7482ee4645 completion: hide dotfiles by default for path completion
>
> ... I find this range diff very troubling.  If we look at patch 2,
> it seems that it redoes some part of what is done in patch 1 saying
> "oops that was wrong, so let's do it better this time".  Such a
> drunken-mans' walk that goes in one direction in an earlier step,
> only to be corrected to move to a different course, is now how we
"is not" :)
Show 21 quoted lines
> want a new topic to be presented.
>
> The end result may be much easier to read, mostly thanks to updated
> loop in the awk script, so if we really want to pretend this as two
> patches for "small pieces are easier to digest" value, perhaps have
> [PATCH 1/2] that updates the awk script (without doing anything
> related to hide-dotfiles theme) to make it easier to read by not
> having multiple "print pfx p" in it, and then build on top of that
> improved base, have [PATCH 2/2] that adds the support to hide
> dotfiles, perhaps?
>
> Since the initial iteration was quite a while ago, I no longer
> remember the details of the review I gave, but I recall having hard
> time telling which callers of the complete-index-file helper hide
> dotfiles from their output and which callers do not hide them, and
> how the patch decided to choose which ones should and should not
> hide.  Has it been improved and if so how?  That is something we
> expect the cover letter to tell, too.
>
> Thanks.
>
-- 
D. Ben Knoble
Junio C HamanoJun 21, 2026, 20:28 UTC in reply to D. Ben Knoble on lore

Re: [PATCH v3 0/2] completion: hide dotfiles for selected path completion

"D. Ben Knoble" <ben.knoble@gmail.com> writes:
> [Small typo correction that may affect how the message is read]
Thanks, I spotted another one.
Show 7 quoted lines
>> ... I find this range diff very troubling.  If we look at patch 2,
>> it seems that it redoes some part of what is done in patch 1 saying
>> "oops that was wrong, so let's do it better this time".  Such a
>> drunken-mans' walk that goes in one direction in an earlier step,
>> only to be corrected to move to a different course, is now how we
>
> "is not" :)
True.
>> want a new topic to be presented.
>>
>> The end result may be much easier to read, mostly thanks to updated
>> loop in the awk script, so if we really want to pretend this as two
"pretend" -> "present". 
Show 6 quoted lines
>> patches for "small pieces are easier to digest" value, perhaps have
>> [PATCH 1/2] that updates the awk script (without doing anything
>> related to hide-dotfiles theme) to make it easier to read by not
>> having multiple "print pfx p" in it, and then build on top of that
>> improved base, have [PATCH 2/2] that adds the support to hide
>> dotfiles, perhaps?
Junio C HamanoJun 29, 2026, 21:52 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH v3 0/2] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
> The completion helper for index paths uses git ls-files rather than shell
> filename completion. As a result, leading-dot paths such as a tracked
> .gitignore were offered even when the user had not started the path with ..

Will we see a hopefully small and final update (v4) to conclude this topic anytime soom? No rush, but just wondering...

Junio C HamanoJul 23, 2026, 23:48 UTC in reply to Zakariyah Ali via GitGitGadget on lore

Re: [PATCH v3 0/2] completion: hide dotfiles for selected path completion

"Zakariyah Ali via GitGitGadget" <gitgitgadget@gmail.com> writes:
> The completion helper for index paths uses git ls-files rather than shell
> filename completion. As a result, leading-dot paths such as a tracked
> .gitignore were offered even when the user had not started the path with ..

I was reviewing the draft of the What's Cooking report and noticed that this topic is among a handful of stalled efforts going nowhere.

I think we are still waiting for a hopefully small and final update (v4) to conclude this topic for close to a month, without any news. Will we see an update anytime soon? If not, let me mark the topic to be discarded in my draft of the whats-cooking report.

Thanks.

Back to recent threads