如何使用bash脚本遍历所有的git分支

如何使用bash脚本遍历我的资源库中的所有本地分支。 我需要迭代和检查分支和一些远程分支之间是否有任何区别。 防爆

for branch in $(git branch); do git log --oneline $branch ^remotes/origin/master; done 

我需要做上面给出的东西,但是我面临的问题是$(git分支)给我的资料库文件夹内的文件夹以及存储库中存在的分支。

这是解决这个问题的正确方法吗? 还是有另一种方法来做到这一点?

谢谢

编写脚本时不应该使用git分支 。 Git提供了一个明确devise用于脚本编写的“pipe道”接口 (许多正常的Git命令(添加,检出,合并等)的当前和历史实现使用相同的接口)。

你想要的pipe道命令是git for-each-ref

 git for-each-ref --shell \ --format='git log --oneline %(refname) ^origin/master' \ refs/heads/ 

注意:在远程文件中不需要remotes/前缀,除非有其他的引用origin/master匹配ref名称searchpath中的多个地方的引用(参见指定修订部分的 “符号引用名称…” git-rev-parse(1) )。 如果您试图明确避免含糊不清,请使用完整的ref名称: refs/remotes/origin/master

你会得到这样的输出:

 git log --oneline 'refs/heads/master' ^origin/master git log --oneline 'refs/heads/other' ^origin/master git log --oneline 'refs/heads/pu' ^origin/master 

你可以把这个输出转换成sh

如果你不喜欢生成shell代码的想法,你可以放弃一些健壮性*,并做到这一点:

 for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do git log --oneline "$branch" ^origin/master done 

Ref的名字应该是安全的,从shell的分词(参见git-check-ref-format(1) )。 我个人会坚持以前的版本(生成的shell代码); 我更有信心,没有不适当的事情可以发生。

既然你指定了bash,而且它支持数组,你可以保持安全,并且仍然避免产生你的循环的胆量:

 branches=() eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/heads/)" for branch in "${branches[@]}"; do # … done 

如果你不使用支持数组的shell( set --初始化和set -- "$@" %(refname)添加元素),你可以用$@做类似的事情。

这是因为git branch用星号标记当前分支,例如:

 $ git branch * master mybranch $ 

所以$(git branch)扩展到例如* master mybranch ,然后*展开到当前目录中的文件列表。

我没有看到一个明显的select,不是首先打印星号; 但你可以砍掉它:

 $(git branch | cut -c 3-) 

如果你的本地分支只用数字,az和/或AZ来命名,我会build议$(git branch|grep -o "[0-9A-Za-z]\+")

我重复例如:

 for BRANCH in `git branch --list|sed 's/\*//g'`; do git checkout $BRANCH git fetch git branch --set-upstream-to=origin/$BRANCH $BRANCH done git checkout master; 

被接受的答案是正确的,实际上应该是使用的方法,但在bash中解决这个问题是理解shell如何工作的一个很好的练习。 使用bash而不执行额外文本操作的技巧是确保git分支的输出不会被扩展为shell执行命令的一部分。 这可以防止星号在扩展的文件名扩展(步骤8)中被扩展(见http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html

使用bash while构造和读取命令将git分支输出切分成行。 “*”将作为文字字符读入。 使用case语句来匹配它,特别注意匹配模式。

 git branch | while read line ; do case $line in \*\ *) branch=${line#\*\ } ;; # match the current branch *) branch=$line ;; # match all the other branches esac git log --oneline $branch ^remotes/origin/master done 

bash case结构和参数replace中的星号需要用反斜线进行转义,以防止shell将它们解释为模式匹配字符。 空格也会被转义(以防止标记),因为你的字面意思是“*”。

从@ finn的答案(谢谢!)扩展,下面将允许您迭代分支而不创build干预的shell脚本。 它足够强大,只要在分支名称中没有换行符:)

 git for-each-ref --format='%(refname)' refs/heads | while read x ; do echo === $x === ; done 

while循环运行在一个子shell中,除非你在当前shell中设置你想要访问的shellvariables。 在这种情况下,您使用stream程replace来反转pipe道:

 while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads ) 

在我看来最简单的select是:

git branch | grep "[^* ]+" -Eo

输出:

 bamboo develop master 

grep的-o选项(–only-matching)将输出限制为只有input的匹配部分。

由于Git分支名称中既没有空格也没有*,因此这将返回没有额外字符的分支列表。

编辑:如果您处于“分离头”状态 ,则需要过滤掉当前条目:

git branch --list | grep -v "HEAD detached" | grep "[^* ]+" -oE