From a6ee9be72ae0a118afca2bcc74daee7b80d1716a Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 1 Jun 2025 13:59:30 +0200 Subject: [PATCH] completions/git: only look at local branches and tags when computing 50 recent commits Commit 836b6bea73b (git completions: Add commit hashes for `show`, 2015-12-18) made git show foo 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 3c3bf7ffd76 (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 --- share/completions/git.fish | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 7004e26e0..d66645c36 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -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