completion: 'git checkout' completes untracked paths as a last resort

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 <gitster@pobox.com>
main
Junio C Hamano 2026-08-13 12:12:34 -07:00
parent 3fe9209986
commit 05e2ab1f31
2 changed files with 23 additions and 2 deletions

View File

@ -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"

View File

@ -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' '