Como iterar através de todas as ramificações git usando o script bash

Como posso iterar através de todas as ramificações locais no meu repository usando o script bash. Eu preciso iterar e verificar se há alguma diferença entre o ramo e alguns ramos remotos. Ex

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

Eu preciso fazer algo como acima, mas o problema que estou enfrentando é $ (git branch) me fornece as pastas dentro da pasta do repository junto com as ramificações presentes no repository.

Essa é a maneira correta de resolver esse problema? Ou existe outra maneira de fazer isso?

Obrigado

   

    Você não deve usar o git branch ao escrever scripts. O Git fornece uma interface de “encanamento” que é explicitamente projetada para uso em scripts (muitas implementações atuais e históricas de comandos normais do Git (adicionar, fazer check-out, mesclar, etc.) usam essa mesma interface).

    O comando de encanamento que você quer é git for-each-ref :

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

    Nota: Você não precisa dos remotes/ prefixo na referência remota, a menos que tenha outras referências que façam com que origin/master correspondam a vários lugares no caminho de busca do nome de referência (consulte “Um nome de referência simbólica…” na seção Especificando revisões. git-rev-parse (1) ). Se você está tentando evitar explicitamente a ambiguidade, então vá com o nome completo da ref: refs/remotes/origin/master .

    Você receberá uma saída assim:

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

    Você pode canalizar essa saída para sh .

    Se você não gosta da idéia de gerar o código shell, você pode desistir de um pouco de robustez * e fazer isso:

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

    * Os nomes de referência devem estar protegidos da divisão de palavras do shell (consulte git-check-ref-format (1) ). Pessoalmente eu iria ficar com a versão anterior (código shell gerado); Estou mais confiante de que nada de inapropriado pode acontecer com isso.

    Desde que você especificou bash e suporta arrays, você poderia manter a segurança e ainda evitar gerar as entranhas de seu loop:

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

    Você poderia fazer algo similar com $@ se você não estiver usando um shell que suporte arrays ( set -- para inicializar e set -- "$@" %(refname) para adicionar elementos).

    Isto é porque git branch marca o ramo atual com um asterisco, por exemplo:

     $ git branch * master mybranch $ 

    então $(git branch) expande para eg * master mybranch , e então * expande para a lista de arquivos no diretório atual.

    Eu não vejo uma opção óbvia para não imprimir o asterisco em primeiro lugar; mas você pode cortar:

     $(git branch | cut -c 3-) 

    Eu sugeriria $(git branch|grep -o "[0-9A-Za-z]\+") se suas ramificações locais forem nomeadas apenas por dígitos, az e / ou letras AZ

    A resposta aceita é correta e deve ser a abordagem usada, mas resolver o problema no bash é um ótimo exercício para entender como os shells funcionam. O truque para fazer isso usando o bash sem executar manipulação de texto adicional, é garantir que a saída do branch git nunca seja expandida como parte de um comando a ser executado pelo shell. Isso evita que o asterisco seja expandido na expansão do nome do arquivo (etapa 8) da expansão do shell (consulte http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

    Use o bash enquanto construir com um comando de leitura para cortar a saída de ramificação do git em linhas. O ‘*’ será lido como um caractere literal. Use uma instrução de caso para corresponder, prestando atenção especial aos padrões correspondentes.

     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 

    Os asteriscos na construção de caso bash e na substituição de parâmetro precisam ser escapados com barras invertidas para evitar que o shell interprete-os como caracteres de correspondência de padrão. Os espaços também são escapados (para evitar a tokenização) porque você está correspondendo literalmente a ‘*’.

    I iterar como, por exemplo:

     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; 

    A opção mais fácil de lembrar na minha opinião:

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

    Saída:

     bamboo develop master 

    A opção -o do Grep (-only-matching) restringe a saída apenas às partes correspondentes da input.

    Como nem espaço nem * são válidos em nomes de ramificações do Git, isso retorna a lista de ramificações sem os caracteres extras.

    Editar: se você estiver no estado “cabeça desanexada” , precisará filtrar a input atual:

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

    O que acabei fazendo, aplicado à sua pergunta (& inspirado por ccpizza mencionando tr ):

    git branch | tr -d ' *' | while IFS='' read -r line; do git log --oneline "$line" ^remotes/origin/master; done

    (Eu uso while loops muito. Enquanto para coisas particulares você definitivamente quer usar um nome de variável apontado [“branch”, por exemplo], na maioria das vezes eu estou preocupado apenas em fazer algo com cada linha de input. ‘linha’ aqui em vez de ‘ramificação’ é um aceno para a reutilização / memory / eficiência muscular.)

    Estendendo-se a partir da resposta do @finn (obrigado!), O seguinte permitirá que você itere sobre os branches sem criar um script de shell intermediário. É suficientemente robusto, desde que não haja novas linhas no nome da agência 🙂

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

    O loop while é executado em um subshell, o que geralmente é bom, a menos que você esteja configurando variables ​​shell que deseja acessar no shell atual. Nesse caso, você usa a substituição de processo para reverter o pipe:

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