如何使用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