升级到 21.10 后,git 分支的 Bash 补全功能损坏

升级到 21.10 后,git 分支的 Bash 补全功能损坏

我不记得从哪里得到这段脚本,但我的.bashrc脚本包含以下几行:

# set up autocomplete for git aliases
if [ -f "/usr/share/bash-completion/completions/git" ]; then
  source /usr/share/bash-completion/completions/git
  __git_complete gc _git_checkout
  __git_complete gp _git_pull
else
  echo "Error loading git completions"
fi

git_branch() {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}

gc和分别gp是 和 的git checkout别名git pull

我有一个/usr/share/bash-completion-completions/git,所以当我source ~/.bashrc没有任何东西回显到命令行时。

在升级到 21.10 之前(21.04、20.04 和 18.04 运行良好),我可以gc feat<tab><tab>获取以 开头的分支列表feat,但现在在每个 之后我都会收到一个奇怪的错误<tab>

$ gc featbash: [: -lt: unary operator expected   // first tab after 'gc feat'
bash: [: : integer expression expected
bash: [: -lt: unary operator expected
bash: [: -lt: unary operator expected
ure/bash: [: -lt: unary operator expected        // second tab after 'ure/' (this was returned by the first tab)
bash: [: : integer expression expected
bash: [: -lt: unary operator expected
bash: [: -lt: unary operator expected            // third tab after this line
bash: [: -lt: unary operator expected
bash: [: : integer expression expected
bash: [: -lt: unary operator expected
bash: [: -lt: unary operator expected

Display all 136 possibilities? (y or n)

知道这是什么原因造成的吗?


更新 1:

我只在使用别名时才会收到此错误 - 使用完整命令完成git checkout feat<tab>工作正常。当我使用别名时vim ~/.bash_aliases,它提示我恢复以前的版本并删除交换文件。我这样做了,一切看起来都很好,但我仍然收到错误。


更新2:

尝试升级,然后删除/重新安装git,但bash-completion无济于事。

bash-completion is already the newest version (1:2.11-2ubuntu1).
git is already the newest version (1:2.32.0-1ubuntu1).

更新 3:

是否set -xv启用了详细/调试。以下不是完整的转储,但包括创建消息的部分:

$ gc feat+ __git_func_wrap _git_checkout
+ local cur words cword prev
+ _get_comp_words_by_ref -n =: cur words cword prev
+ local exclude flag i OPTIND=1
+ words=()
+ local cur cword words
+ upargs=()
+ upvars=()
+ local upargs upvars vcur vcword vprev vwords
+ getopts c:i:n:p:w: flag -n =: cur words cword prev
+ case $flag in
+ exclude==:
+ getopts c:i:n:p:w: flag -n =: cur words cword prev
+ [[ 6 -ge 3 ]]
+ case ${!OPTIND} in
+ vcur=cur
+ (( OPTIND += 1 ))
+ [[ 6 -ge 4 ]]
+ case ${!OPTIND} in
+ vwords=words
+ (( OPTIND += 1 ))
+ [[ 6 -ge 5 ]]
+ case ${!OPTIND} in
+ vcword=cword
+ (( OPTIND += 1 ))
+ [[ 6 -ge 6 ]]
+ case ${!OPTIND} in
+ vprev=prev
+ (( OPTIND += 1 ))
+ [[ 6 -ge 7 ]]
+ __get_cword_at_cursor_by_ref =: words cword cur
+ words=()
+ local cword words
+ __reassemble_comp_words_by_ref =: words cword
+ local exclude i j line ref
+ [[ -n =: ]]
+ exclude='[=:]'
+ printf -v cword %s 1
+ [[ -v exclude ]]
+ line='gc feat'
+ (( i = 0, j = 0 ))
+ (( i < 2 ))
+ [[ 0 -gt 0 ]]
+ ref='words[0]'
+ printf -v 'words[0]' %s gc
+ line=' feat'
+ (( i == COMP_CWORD ))
+ (( i++, j++ ))
+ (( i < 2 ))
+ [[ 1 -gt 0 ]]
+ [[ feat == +([=:]) ]]
+ ref='words[1]'
+ printf -v 'words[1]' %s feat
+ line=
+ (( i == COMP_CWORD ))
+ printf -v cword %s 1
+ (( i++, j++ ))
+ (( i < 2 ))
+ (( i == COMP_CWORD ))
+ local i cur= index=7 'lead=gc feat'
+ [[ 7 -gt 0 ]]
+ [[ -n gc feat ]]
+ [[ -n gcfeat ]]
+ cur='gc feat'
+ (( i = 0 ))
+ (( i <= cword ))
+ [[ 7 -ge 2 ]]
+ [[ gc != \g\c ]]
+ (( i < cword ))
+ local old_size=7
+ cur=' feat'
+ local new_size=5
+ (( index -= old_size - new_size ))
+ (( ++i ))
+ (( i <= cword ))
+ [[ 5 -ge 4 ]]
+ [[  fea != \f\e\a\t ]]
+ cur=feat
+ (( index > 0 ))
+ (( index-- ))
+ [[ 4 -ge 4 ]]
+ [[ feat != \f\e\a\t ]]
+ (( i < cword ))
+ (( ++i ))
+ (( i <= cword ))
+ [[ -n feat ]]
+ [[ ! -n feat ]]
+ (( index < 0 ))
+ local words cword cur
+ _upvars -a2 words gc feat -v cword 1 -v cur feat
+ (( 10 ))
+ (( 10 ))
+ case $1 in
+ [[ -n 2 ]]
+ printf %d 2
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:2}")'
words=("${@:3:2}")
++ words=("${@:3:2}")
+ shift 4
+ (( 6 ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
cword="$3"
++ cword=1
+ shift 3
+ (( 3 ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
cur="$3"
++ cur=feat
+ shift 3
+ (( 0 ))
+ [[ -v vcur ]]
+ upvars+=("$vcur")
+ upargs+=(-v $vcur "$cur")
+ [[ -v vcword ]]
+ upvars+=("$vcword")
+ upargs+=(-v $vcword "$cword")
+ [[ -v vprev ]]
+ [[ 1 -ge 1 ]]
+ upvars+=("$vprev")
+ upargs+=(-v $vprev "${words[cword - 1]}")
+ [[ -v vwords ]]
+ upvars+=("$vwords")
+ upargs+=(-a${#words[@]} $vwords ${words+"${words[@]}"})
+ (( 4 ))
+ local cur cword prev words
+ _upvars -v cur feat -v cword 1 -v prev gc -a2 words gc feat
+ (( 13 ))
+ (( 13 ))
+ case $1 in
+ [[ -n cur ]]
+ unset -v cur
+ eval 'cur="$3"'
cur="$3"
++ cur=feat
+ shift 3
+ (( 10 ))
+ case $1 in
+ [[ -n cword ]]
+ unset -v cword
+ eval 'cword="$3"'
cword="$3"
++ cword=1
+ shift 3
+ (( 7 ))
+ case $1 in
+ [[ -n prev ]]
+ unset -v prev
+ eval 'prev="$3"'
prev="$3"
++ prev=gc
+ shift 3
+ (( 4 ))
+ case $1 in
+ [[ -n 2 ]]
+ printf %d 2
+ [[ -n words ]]
+ unset -v words
+ eval 'words=("${@:3:2}")'
words=("${@:3:2}")
++ words=("${@:3:2}")
+ shift 4
+ (( 0 ))
+ _git_checkout
+ __git_has_doubledash
+ local c=1
+ '[' 1 -lt 1 ']'
+ return 1
++ __git_checkout_default_dwim_mode
++ local last_option dwim_opt=--dwim
++ '[' '' = 1 ']'
+++ __git_find_on_cmdline --no-track
+++ local word c= show_idx
+++ test 1 -gt 1
+++ local wordlist=--no-track
+++ '[' -lt 1 ']'
bash: [: -lt: unary operator expected
++ '[' -n '' ']'
+++ __git config --type=bool checkout.guess
+++ git config --type=bool checkout.guess
++ '[' '' = false ']'
+++ __git_find_last_on_cmdline '--guess --no-guess'
+++ local word c=1 show_idx
+++ test 1 -gt 1
+++ local 'wordlist=--guess --no-guess'
+++ '[' 1 -gt '' ']'
bash: [: : integer expression expected
++ last_option=
++ case "$last_option" in
++ echo --dwim
+ local dwim_opt=--dwim
+ case "$prev" in
+ case "$cur" in
++ __git_find_on_cmdline '-b -B -d --detach --orphan'
++ local word c= show_idx
++ test 1 -gt 1
++ local 'wordlist=-b -B -d --detach --orphan'
++ '[' -lt 1 ']'
bash: [: -lt: unary operator expected
+ '[' -n '' ']'
++ __git_find_on_cmdline --track
++ local word c= show_idx
++ test 1 -gt 1
++ local wordlist=--track
++ '[' -lt 1 ']'
bash: [: -lt: unary operator expected

请注意,这不是完整的转储,只是包含错误消息生成位置在内的部分内容。我尝试通过脚本追溯其中一条错误消息,并在其中找到了以下内容/usr/share/bash-completion/completions/git

# Check whether one of the given words is present on the command line,
# and print the first word found.
#
# Usage: __git_find_on_cmdline [<option>]... "<wordlist>"
# --show-idx: Optionally show the index of the found word in the $words array.
__git_find_on_cmdline ()
{
        local word c="$__git_cmd_idx" show_idx

        while test $# -gt 1; do
                case "$1" in
                --show-idx)     show_idx=y ;;
                *)              return 1 ;;
                esac
                shift
        done
        local wordlist="$1"

        while [ $c -lt $cword ]; do
                for word in $wordlist; do
                        if [ "$word" = "${words[c]}" ]; then
                                if [ -n "${show_idx-}" ]; then
                                        echo "$c $word"
                                else
                                        echo "$word"
                                fi
                                return
                        fi
                done
                ((c++))
        done
}

看起来也许这一行local word c="$__git_cmd_idx" show_idx是罪魁祸首,因为稍后的比较c看起来是空的,-lt从而触发了预期的一元运算符。

为什么更新后它不再起作用?

答案1

这被发布为一个错误bash 补全的 GitHub。该问题已解决Git 2.33.0

在该修复程序进入 Ubuntu 存储库之前,你可以采取一种解决方法如下

在文件中/usr/share/bash-completion/completions/git,更改

__git_func_wrap ()
{
    local cur words cword prev

进入

__git_func_wrap ()
{
    local cur words cword prev __git_cmd_idx=1

相关内容