completions/git: only look at local branches and tags when computing 50 recent commits

Commit 836b6bea73 (git completions: Add commit hashes for `show`, 2015-12-18)
made

	git show foo<TAB>

magically expand "foo" to the commit hash of a recent commit.  I would
discourage from using raw commit IDs on the command line but I guess it's the
most convenient way sometimes. Probably this is still useful to some users even
though "git show :/foo" exists.  The set of target commits was "git log -50".

Commit 3c3bf7ffd7 (completions/git: Show recent commits *on all branches*
for rebase, 2021-03-12) and others expanded the set of target commits to "git
log -50 --all" for some commands. I think Git partially sorts the result
set before returning the top 50 entries, possibly causing a slowdown.
(A slowdown is easily reproducible with "time git log --max-count=50
>/dev/null" with and without "--all").

The "--all" flag seems excessive because
1. it looks at remote branches. There can be a lot of those, especially in
   a monorepo context or when Git is configured to fetch branches from
   multiple remotes.  See also #9248 where we explicitly decided not to sort
   remote branches.
2. it looks at refs that are neither branches nor tags.
   Some systems like Jujutsu or git-branchless use such refs to prevent their
   commits from being garbage-collected. Such refs typically have opaque
   (autogenerated) IDs and should normally not be shown in a generic Git UI.

I don't know if completion of commit IDs for these kinds of refs is worth it.
(Normally you'd run something like "git checkout remote-branch" instead.)

Exclude these two types of refs.  Do include HEAD which is not a branch or
tag.  In future we could include refs like REBASE_HEAD again; though again,
I don't know if those are needed for commit-ID completion.

Given

	$ git for-each-ref refs/tags | wc -l
	1033
	$ git for-each-ref refs/heads | wc -l   # local branches
	6
	$ git for-each-ref refs/remotes | wc -l # remote branches
	5270
	$ git for-each-ref refs/jj/keep | wc -l # Jujutsu
	8390

this results in a good speedup for completions:

	$ fish -c "time complete -C'git ' >/dev/null && time complete -C'git checkout hello' >/dev/null" &| grep .
	________________________________________________________
	Executed in   68.61 millis    fish           external
	   usr time   63.50 millis   55.17 millis    8.33 millis
	   sys time   13.41 millis   13.41 millis    0.00 millis
	________________________________________________________
	Executed in  911.49 millis    fish           external
	   usr time  359.17 millis   91.00 millis  268.18 millis
	   sys time  604.22 millis   24.70 millis  579.53 millis
	$ fish -c "time complete -C'git ' >/dev/null && time complete -C'git checkout hello' >/dev/null" &| grep .
	________________________________________________________
	Executed in   70.20 millis    fish           external
	   usr time   59.81 millis   59.81 millis    0.00 millis
	   sys time   19.39 millis   12.22 millis    7.17 millis
	________________________________________________________
	Executed in  449.83 millis    fish           external
	   usr time  240.37 millis   94.17 millis  146.21 millis
	   sys time  403.66 millis   29.66 millis  374.00 millis

Part of #11535
This commit is contained in:
Johannes Altmanninger
2025-06-01 13:59:30 +02:00
parent ad28e17b50
commit a6ee9be72a

View File

@@ -106,14 +106,22 @@ function __fish_git_remotes
__fish_git config --get-regexp 'remote\.[a-z]+\.url' | string replace -rf 'remote\.(.*)\.url (.*)' '$1\t$2'
end
set -g __fish_git_recent_commits_arg
set -g __fish_git_extra_recent_commits false
set -g __fish_git_unqualified_unique_remote_branches false
set -g __fish_git_filter_non_pushable 'string join \n'
function __fish_git_add_revision_completion
set -l c complete -f -c git $argv -n 'not contains -- -- (commandline -xpc)' -ka
# The following dynamic, order-preserved (-k) completions will be shown in reverse order (see #9221)
$c "(__fish_git_recent_commits $__fish_git_recent_commits_arg | $__fish_git_filter_non_pushable)"
$c "(__fish_git_recent_commits \$(
if $__fish_git_extra_recent_commits
begin
echo HEAD
git for-each-ref --sort=-committerdate --format='%(refname)' 2>/dev/null \
refs/tags refs/heads
end | string join ' '
end
) | $__fish_git_filter_non_pushable)"
$c "(__fish_git_tags)" -d Tag
$c "(__fish_git_heads | $__fish_git_filter_non_pushable)" -d Head
$c "(__fish_git_remotes | $__fish_git_filter_non_pushable)" -d 'Remote alias'
@@ -1204,7 +1212,7 @@ complete -c git -n '__fish_git_using_command am' -l show-current-patch -a 'diff
complete -F -c git -n '__fish_git_using_command checkout' -n 'contains -- -- (commandline -xpc)'
complete -f -c git -n __fish_git_needs_command -a checkout -d 'Checkout and switch to a branch'
begin
set -lx __fish_git_recent_commits_arg --all
set -lx __fish_git_extra_recent_commits true
set -lx __fish_git_unqualified_unique_remote_branches true
__fish_git_add_revision_completion -n '__fish_git_using_command checkout'
end
@@ -1466,7 +1474,7 @@ complete -c git -n __fish_git_needs_command -a diff -d 'Show changes between com
complete -c git -n '__fish_git_using_command diff' -n 'not contains -- -- (commandline -xpc)' -ka '(__fish_git_ranges)'
complete -c git -n '__fish_git_using_command diff' -n 'not contains -- -- (commandline -xpc)' -ka '(__fish_git_complete_stashes)'
begin
set -lx __fish_git_recent_commits_arg --all
set -lx __fish_git_extra_recent_commits true
__fish_git_add_revision_completion -n '__fish_git_using_command diff'
end
complete -c git -n '__fish_git_using_command diff' -l cached -d 'Show diff of changes in the index'
@@ -2061,7 +2069,7 @@ complete -f -c git -n '__fish_git_using_command switch' -ka '(__fish_git_branche
complete -f -c git -n '__fish_git_using_command switch' -s c -l create -d 'Create a new branch'
complete -f -c git -n '__fish_git_using_command switch' -s C -l force-create -d 'Force create a new branch'
begin
set -lx __fish_git_recent_commits_arg --all
set -lx __fish_git_extra_recent_commits true
__fish_git_add_revision_completion -n '__fish_git_using_command switch' -s d -l detach -r
end
complete -f -c git -n '__fish_git_using_command switch' -s d -l detach -d 'Switch to a commit for inspection and discardable experiment' -rka '(__fish_git_refs)'
@@ -2619,6 +2627,6 @@ for file in (path filter -xZ $PATH/git-* | path basename)
end
functions --erase __fish_git_add_revision_completion
set -eg __fish_git_recent_commits_arg
set -eg __fish_git_extra_recent_commits
set -eg __fish_git_unqualified_unique_remote_branches
set -eg __fish_git_filter_non_pushable