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

Eri*_*ich 4 bash scripts git 21.10

我不记得从哪里得到这段脚本,但我的.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)/'
}
Run Code Online (Sandbox Code Playgroud)

gc和分别gpgit 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)
Run Code Online (Sandbox Code Playgroud)

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


更新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).
Run Code Online (Sandbox Code Playgroud)

更新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
Run Code Online (Sandbox Code Playgroud)

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

$ 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)
Run Code Online (Sandbox Code Playgroud)

local word c="$__git_cmd_idx" show_idx看起来可能是该行的问题,因为稍后触发预期的一元运算符时的比较c看起来是空的。-lt

为什么更新后这个功能就失效了?

小智 6

这已作为bash 完成的 GitHub上的错误发布。该问题已在Git 2.33.0中得到解决。

在该修复程序渗透到 Ubuntu 存储库之前,您可以按如下方式进行解决:

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

__git_func_wrap ()
{
    local cur words cword prev
Run Code Online (Sandbox Code Playgroud)

进入

__git_func_wrap ()
{
    local cur words cword prev __git_cmd_idx=1
Run Code Online (Sandbox Code Playgroud)