[PATCH v3 3/3] completion: 'git checkout' completes untracked paths as a last resort
From: Junio C Hamano <hidden>
Date: 2026-08-13 19:12:42
Subsystem:
the rest · Maintainer:
Linus Torvalds
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.
Note that this is of somewhat dubious value, as an untracked path by
definition does not exist in the index, so checking it out from the
index would not work well. Even when used to check out the path
from a different branch, it is still of dubious value because it is
unlikely that a path tracked in another branch is lying untracked in
the working tree, as switching from a branch with the path to a
branch without it will normally remove the file in the working tree.
A better behavior probably is to detect the tree-ish argument on
the command line and offer paths with the given prefix as candidates,
but there is no __git_complete_from_tree() helper readily usable,
so mark this as #leftoverbits to wait for another day.
Signed-off-by: Junio C Hamano <redacted>
---
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..e6dce62d3c 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 --directory" + 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-759-g9dcc51a0fd