在创建安装脚本时,我在本地克隆了几个git repo。这是通过一个临时可用的代理完成的,该代理稍后可能可用,也可能不可用,所以我需要从远程repo创建所有远程分支作为可以切换到的本地分支。我有一种方法来提取我想要的远程repo的名称,当存储为时
[user]$ nvVar=$(git branch -r | grep -v '->' | grep -Ev 'master|spdk-1.6' | cut -d'/' -f2)
这给了我一个可以迭代的变量列表,其中包含我需要删除的分支。
[user]$ echo "$nvVar"
lightnvm
nvme-cuse
spdk
如果我手动完成所有这些操作,我会使用以下命令:
[user]$ git branch --track lightnvm origin/lightnvm
Branch lightnvm set up to track remote branch lightnvm from origin.
这很好。。。但是,当我尝试使用shell展开循环遍历变量时,我失败了。(仅供参考,如果我在$nvVar周围加引号,它不会迭代,只是尝试运行整个字符串,但失败了。我也尝试过用数组来做这件事,但也不起作用,还使用了while循环,使用git branch-r的过滤输出)
[user]$ for i in $nvVar; do git branch --track "${i}" "origin/${i}"; done
它应该产生以下git命令:
git branch --track lightnvm origin/lightnvm
git branch --track nvme-cuse origin/nvme-cuse
git branch --track spdk origin/spdk
这似乎与手动键入的相同命令相同。。但相反,我得到了这些错误:
fatal: 'lightnvm' is not a valid branch name.
fatal: 'nvme-cuse' is not a valid branch name.
fatal: 'spdk' is not a valid branch name.
这毫无意义。。。
OS:RHEL 7.6
Git版本:1.8.3.1
Bash版本:GNU Bash,版本4.2.46(2)-发布(x86_64-redhat-linux-GNU)
(编辑)显然,我捕捉到了一些特殊的角色,这些角色扰乱了命令。
有一个"^[[m〃被附加到捕获的变量…真的不知道如何在不硬编码命令的情况下消除它,我曾希望避免
找到了一个解决方案:
echo '#!/bin/bash' > gitShell
git branch -r | grep -v '->' | grep -Ev 'master|spdk-1.6' | cut -d'/' -f2 | while read remote; do
echo "git branch --track ${remote} origin/${remote}" >> gitShell
done
cat -v gitShell | sed 's/^[[m//g' > gitShell1
if /bin/bash -ex gitShell1; then
echo 'Git repos branched'
rm gitShell
rm gitShell1
fi
我只需将输出推送到一个文件中,然后使用cat-v强制隐藏的字符显示为正常字符,然后用sed过滤掉它们,然后运行新脚本。
它很笨重,但很管用。显然git返回"专用unicode字符";以响应远程查询。
感谢@Cyrus告诉我,我在原始变量中隐藏了字符。
git branch
命令不是用来编写脚本的。出现此问题的原因是在分支名称中嵌入了更改颜色的文本字符串。例如,ESC[31mbranch
ESCm前分支使用绿色,这不是这里感兴趣的分支,但仍然为非当前分支发出各种转义序列分支案例。)
您应该使用git for-each-ref
而不是git branch
。这就是Git所称的管道命令:一个用于编写脚本的命令。它的输出可以很容易地进行机器解析,并且不包含任何像变色转义序列这样的陷阱。它还消除了对一些后续技巧的需要,因为它有%(...)
指令,可以用来从项目中去除所需数量的前缀。
(或者,可以使用git branch
,但禁用颜色输出,例如git -c color.branch=never branch
。但git branch
不承诺而在未来对其输出进行任意更改,而git for-each-ref
会这样做。)
你也可以考虑用不同的方式来解决最初的问题:;镜像克隆";,但是一旦克隆完成,就重写fetch
refspec并删除镜像配置。简言之,常规克隆和镜像克隆之间的区别在于,常规克隆复制所有1提交,而没有2分支,但镜像克隆复制所有提交以及所有分支和所有其他引用,3并将remote.remote.mirror
设置为true
。
1嗯,大多数提交,这取决于从哪些引用可以访问哪些提交。如果某些对象是隐藏的,或者只能通过reflog找到,那么你通常不会得到这些对象——但你通常也不在乎,事实上,这通常是可取的,例如,在删除意外提交的10 GB数据库之后。
2复制提交后,常规提取将分支名称转换为远程跟踪名称(例如origin/master
)。最后一个git checkout
步骤创建一个新的分支名称,或者如果-n
有一个标记名称,则不创建。
3As与";所有提交";,这是一种礼貌的虚构:发送者可能隐藏某些引用,在这种情况下,你不会得到这些引用,而且可能也不会得到这些提交和其他对象。另一方面,为避免重新打包而进行的优化可能会意外发送不需要的对象:即使不想要,10GB的数据库也可能通过。幸运的是,reflog不是refs,所以通常不会发生这种情况。