From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Cc: "Philippe Blain" <levraiphilippeblain@gmail.com>,
"Britton Leo Kerin" <britton.kerin@gmail.com>,
"Elijah Newren" <newren@gmail.com>,
"Rubén Justo" <rjusto@gmail.com>,
"Patrick Steinhardt" <ps@pks.im>
Subject: [PATCH] completion: complete tracked paths for 'git diff'
Date: Sun, 02 Aug 2026 17:58:01 -0700 [thread overview]
Message-ID: <xmqqcxw010me.fsf@gitster.g> (raw)
When completing arguments for 'git diff', _git_diff() delegates to
__git_complete_revlist_file(), which only completes revision
references. This is good [*], as mixing both revs and paths in a
single list to have the user pick is simply too confusing.
If no reference matches, or if '--' is given, however, _git_diff()
leaves COMPREPLY empty. Bash then falls back to default filename
completion in $PWD. This fails when 'git -C <path>' is used because
$PWD is not the target repository.
Update _git_diff() 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.
[Footnote]
* In https://lore.kernel.org/git/al%2Fw2qgBfhe9qMg6@szeder.dev/
SZEDER made the same argument for "git send-email 0<TAB>".
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
* This is one of my pet peeves that I have raised a few times on
the list but nobody reacted. So I did a "monkey see, monkey do"
patch without deeply understanding what is going on in the code
paths. When preparing the CC: list, I pulled a few folks, some
very recognizable, some not recognizable immediately by me, out
of "git shortlog --since=3.years" on this file. The contribution
by any of them looked more expertly done by whatever I did here.
The use case is that I have a checkout of the 'todo' branch in an
untracked subdirectory 'Meta' in my primary source tree. I would
do
$ git -C Meta status wh<TAB>
and it completes to whats-cooking.txt just fine, 'add' also adds
it, but 'diff' dies not work, not because I have refs that 'wh'
completes, but because bash completion is unaware that I want
paths completed in the other directory.
contrib/completion/git-completion.bash | 8 +++++-
t/t9902-completion.sh | 40 ++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index e875787710..8f5773292b 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1947,7 +1947,10 @@ __git_diff_difftool_options="--cached --staged
_git_diff ()
{
- __git_has_doubledash && return
+ if __git_has_doubledash; then
+ __git_complete_index_file
+ return
+ fi
case "$cur" in
--diff-algorithm=*)
@@ -1976,6 +1979,9 @@ _git_diff ()
;;
esac
__git_complete_revlist_file
+ if [ ${#COMPREPLY[@]} -eq 0 ]; then
+ __git_complete_index_file
+ fi
}
__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 55dc9eabfc..eecd53f097 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2663,6 +2663,7 @@ test_expect_success 'setup for integration tests' '
echo content >file1 &&
echo more >file2 &&
git add file1 file2 &&
+ echo untracked >file3 &&
git commit -m one &&
git branch mybranch &&
git tag mytag
@@ -2712,6 +2713,45 @@ test_expect_success 'git -C <path> checkout uses the right repo' '
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
+ file1
+ file2
+ EOF
+'
+
+test_expect_success 'git diff -- completes tracked paths' '
+ # file1 and file2 are tracked but file3 is not
+ test_completion "git diff -- f" <<-\EOF
+ file1
+ file2
+ EOF
+'
+
+test_expect_success 'git -C <path> diff completes tracked paths in specified repo' '
+ test_when_finished "rm -rf repo-for-diff" &&
+ git init repo-for-diff &&
+ echo content >repo-for-diff/otherfile &&
+ git -C repo-for-diff add otherfile &&
+ echo untracked >repo-for-diff/oops &&
+ git -C repo-for-diff commit -m otherfile &&
+ test_completion "git -C repo-for-diff diff o" <<-\EOF
+ otherfile
+ EOF
+'
+
+test_expect_success 'git -C <path> diff -- completes pathspecs in specified repo' '
+ test_when_finished "rm -rf repo-for-diff" &&
+ git init repo-for-diff &&
+ echo content >repo-for-diff/otherfile &&
+ git -C repo-for-diff add otherfile &&
+ git -C repo-for-diff commit -m otherfile &&
+ test_completion "git -C repo-for-diff diff -- o" <<-\EOF
+ otherfile
+ EOF
+'
+
test_expect_success 'show completes all refs' '
test_completion "git show m" <<-\EOF
main Z
--
2.55.0-607-g47e9082d35
next reply other threads:[~2026-08-03 0:58 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 0:58 Junio C Hamano [this message]
2026-08-03 1:07 ` [PATCH] completion: complete tracked paths for 'git diff' Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqqcxw010me.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=britton.kerin@gmail.com \
--cc=git@vger.kernel.org \
--cc=levraiphilippeblain@gmail.com \
--cc=newren@gmail.com \
--cc=ps@pks.im \
--cc=rjusto@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox