签出多个分支时在git shell中使用正则表达式

时间:2016-04-07 16:34:25

标签: regex git bash shell

如果我有以下git shell命令:

for branch in `git branch -a | grep remotes | grep -v master | sed 's/^.*old\/\(.*\)/\1/g'`; do git branch --track $branch remotes/old/$branch; done

这会检出old遥控器上存在的每个远程分支,并使用与该遥控器上相同的名称跟踪它们。但是,如果我想稍微更改本地分支的名称,该怎么办?

如果我有以下远程分支怎么办:

release/1.2.1.0
release/1.2.1.1

我想在相同的父文件夹release下查看它们,但我只想要版本号中的最后3位数字。所以我希望我的本地分支是:

release/2.1.0
release/2.1.1

我有一个简单的javascript正则表达式,匹配版本字符串的最后3位数字:(?:\d\.)(\d.*)

这使用不匹配的组来丢弃第一个数字,然后是句点。问题是,如何将该正则表达式应用于上面的git shell bash脚本中的$branch变量?

1 个答案:

答案 0 :(得分:2)

首先,避免git branch这样的循环。这里的正确工具是git for-each-ref,它旨在使用脚本语言(git branch针对用户,输出格式将来可能会发生变化,例如)。

要遍历所有远程跟踪分支,只需告诉for-each-ref扫描远程跟踪分支命名空间。由于您需要(更具体地说)名为old的远程,您可以通过添加/old来轻松完成此操作:

git for-each-ref refs/remotes/old

此处的输出默认为objectname objecttype refname的三倍。我们只关心 refname 部分(如果我们愿意的话,我们也可以使用:short修饰符删除refs/remotes/,尽管我们仍然需要删除old/我也可以在没有修饰符的情况下逃脱。因此,我们希望包含--format=%(refname:short)

继续bash,bash具有内置的正则表达式支持。但它的RE语法并不完全相同,所以你现有的RE必须改变。这是一个可能适合您的需求:

bash$ x=1.2.3.4
bash$ [[ $x =~ ([0-9]\.)([0-9.]+) ]] && echo ${BASH_REMATCH[2]}
2.3.4

(这里有一点微妙之处:使用$x改变=~匹配的方式,在我们的例子中可能是好的。作为一个老派的Unix人我通常更喜欢使用{{ 1}}我自己,但在这种情况下,我可能会在Python中执行此操作,它具有Perl样式的RE,并且Javascript / ECMAscript RE在Perl上建模。但所有这些或多或少都无关紧要。最重要的是这个RE与版本号匹配器稍微相当。例如,它匹配“1.3..6”之类的字符串。我们很安全,因为它们是无效的分支名称 - 双点是禁止的,因为它们会与set减法冲突gitrevisions中的语法 - 但它通常有点草率;通过一些工作,我们可以提出更严格的表达。它也失败以匹配从两个或更多数字开始的修订,但是你的原始RE也是如此,所以我故意将其留下。)

在shell中循环读取,使用expr通常是明智的(参见Etan Reisner's comment),尽管在这种情况下我们可以安全地省略它,因为git控制分支名称。我将在示例中使用它只是为了表单。

将这些全部放在一起:

-r

(这整件事完全没有经过考验)。