Pregunta

¿Cómo puedo iterar a través de todas las ramas locales en mi repositorio usando escritura del golpe. Tengo que repetir y comprobación ¿Hay alguna diferencia entre la rama y algunas ramas remotas. Ex

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

Necesito hacer algo como dado anteriormente, pero el problema que estoy enfrentando es $ (git branch) me da las carpetas dentro de la carpeta del depósito junto con las ramas presentar en el repositorio.

Es esta la forma correcta de resolver este problema? O hay otra manera de hacerlo?

Gracias

¿Fue útil?

Solución

No use git branch guiones al escribir. Git proporciona un “fontanería” interfaz que es explícitamente diseñado para su uso en secuencias de comandos (muchas implementaciones actuales y históricos de los comandos normales Git (ADD, pago y envío, fusión, etc.) utiliza la misma interfaz).

El comando de fontanería que quiere es git para-cada-ref

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

Nota: Usted no necesita el prefijo remotes/ en la ref remoto a menos que usted tiene otras referencias que causa origin/master sustituye a varios lugares en el camino ref name búsqueda (ver en la la sección Revisions Especificación de git-rev-parse (1) ). Si usted está tratando de evitar la ambigüedad explicitamente, y luego ir con el nombre completo Ref: refs/remotes/origin/master.

Se obtendrá una salida como la siguiente:

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

Puede canalizar esta salida en sh .

Si no te gusta la idea de generar el código shell, podría renunciar a un poco de solidez * y hacer esto:

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

* nombres Ref deben estar a salvo de la división de palabras de la carcasa (ver git-cheque-ref-formato (1) ). Personalmente me gustaría seguir con la versión anterior (código shell generado); Estoy más seguro de que nada inapropiado puede suceder con él.

Desde que ha especificado fiesta y es compatible con las matrices, se podría mantener la seguridad y aún así evitar la generación de las entrañas de su bucle:

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

Se podría hacer algo similar con $@ si no está utilizando un shell que da soporte a matrices (set -- para inicializar y set -- "$@" %(refname) para añadir elementos).

Otros consejos

Esto se debe a marcas git branch la rama actual con un asterisco, por ejemplo:.

$ git branch
* master
  mybranch
$ 

so expande $(git branch) a, por ejemplo, * master mybranch, y luego se expande * a la lista de archivos en el directorio actual.

No veo una opción obvia para no imprimir el asterisco en el primer lugar; pero se podía cortarlo:

$(git branch | cut -c 3-)

La orden interna fiesta, mapfile, está construido para este

todas las ramas git: git branch --all --format='%(refname:short)'

todas las ramas git locales: git branch --format='%(refname:short)'

todas las ramas git remotas: git branch --remotes --format='%(refname:short)'

iterar a través de todas las ramas git: mapfile -t -C my_callback -c 1 < <( get_branches )

ejemplo:

my_callback () {
  INDEX=${1}
  BRANCH=${2}
  echo "${INDEX} ${BRANCH}"
}
get_branches () {
  git branch --all --format='%(refname:short)'
}
# mapfile -t -C my_callback -c 1 BRANCHES < <( get_branches ) # if you want the branches that were sent to mapfile in a new array as well
# echo "${BRANCHES[@]}"
mapfile -t -C my_callback -c 1 < <( get_branches )

En la situación específica de la OP:

#!/usr/bin/env bash


_map () {
  ARRAY=${1?}
  CALLBACK=${2?}
  mapfile -t -C "${CALLBACK}" -c 1 <<< "${ARRAY[@]}"
}


get_history_differences () {
  REF1=${1?}
  REF2=${2?}
  shift
  shift
  git log --oneline "${REF1}" ^"${REF2}" "${@}"
}


has_different_history () {
  REF1=${1?}
  REF2=${2?}
  HIST_DIFF=$( get_history_differences "${REF1}" "${REF2}" )
  return $( test -n "${HIST_DIFF}" )
}


print_different_branches () {
  read -r -a ARGS <<< "${@}"
  LOCAL=${ARGS[-1]?}
  for REMOTE in "${SOME_REMOTE_BRANCHES[@]}"; do
    if has_different_history "${LOCAL}" "${REMOTE}"; then
      # { echo; echo; get_history_differences "${LOCAL}" "${REMOTE}" --color=always; } # show differences
      echo local branch "${LOCAL}" is different than remote branch "${REMOTE}";
    fi
  done
}


get_local_branches () {
  git branch --format='%(refname:short)'
}


get_different_branches () {
  _map "$( get_local_branches )" print_different_branches
}


# read -r -a SOME_REMOTE_BRANCHES <<< "${@}" # use this instead for command line input
declare -a SOME_REMOTE_BRANCHES
SOME_REMOTE_BRANCHES=( origin/master remotes/origin/another-branch another-remote/another-interesting-branch )
DIFFERENT_BRANCHES=$( get_different_branches )

echo "${DIFFERENT_BRANCHES}"

Fuente: Lista de todos los locales ramas Git sin asterisco

I iterate como por ejemplo:

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;

Yo sugeriría $(git branch|grep -o "[0-9A-Za-z]\+") si sus ramas locales son nombrados por dígitos, a-z, cartas y / o a-z única

La respuesta aceptada es correcta y realmente debe ser el enfoque utilizado, pero la solución del problema en bash es un gran ejercicio para comprender cómo conchas trabajo. El truco para hacer esto utilizando fiesta sin llevar a cabo la manipulación de texto adicional, es asegurar la salida de la rama git nunca se ampliado como parte de un comando a ser ejecutado por el shell. Esto evita que el asterisco de alguna vez ser la expansión en la expansión de nombre de archivo (paso 8) de expansión shell (ver http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

Usar la fiesta mientras construcción con un comando de lectura para cortar la salida de git branch en líneas. El '*' se leerá en un carácter literal. Utilice una declaración de caso para que coincida con ella, prestando especial atención a los patrones coincidentes.

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

Los asteriscos en tanto el golpe caso constructo y en la necesidad parámetro de sustitución que se escapó con barras invertidas para prevenir la cáscara interpretar como caracteres de coincidencia de patrones. Los espacios también se escaparon (para evitar tokenización), ya que son, literalmente, que contengan '*'.

opción más fácil para recordar en mi opinión:

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

Salida:

bamboo
develop
master

opción -o de Grep (--only-matching) restringe la salida a sólo las partes coincidentes de la entrada.

Dado que ni el espacio ni el * son válidos en nombres de rama Git, este devuelve la lista de ramas sin los caracteres adicionales.

Editar: Si estás en 'adosado cabeza' estado , tendrá para filtrar la entrada actual:

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

Lo que terminé haciendo, aplicado a su pregunta (y inspirado por ccpizza tr mencionar):

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

(yo uso, mientras que los bucles mucho. Mientras que para las cosas particulares que le definitivamente desea utilizar un nombre de variable en punta [ "rama", por ejemplo], la mayoría de las veces sólo estoy interesado en hacer algo con cada línea de entrada. el uso de 'línea' aquí en lugar de 'rama' es un guiño a la reutilización / memoria muscular / eficiencia.)

La extensión de la respuesta de @ de Finn (¡gracias!), A continuación se le permitirá iterar sobre las ramas sin crear un script de shell que interviene. Es lo suficientemente robusta, siempre y cuando no hay saltos de línea en el nombre de la sucursal:)

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

Las carreras bucle while en un subnivel, que es generalmente muy bien a menos que seas variables de shell de ajuste que desea acceder en el shell actual. En ese caso, se utiliza la sustitución proceso para revertir la tubería:

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

Si usted está en este estado:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

Y se ejecuta este código:

git branch -a | grep remotes/origin/*

for BRANCH in `git branch -a | grep remotes/origin/*` ;

do
    A="$(cut -d'/' -f3 <<<"$BRANCH")"
    echo $A

done        

Se conseguirá este resultado:

branch1

branch2

branch3

master

Debe ser sencillo

La forma más sencilla de conseguir nombre de la sucursal en bucle usando escritura del golpe.

#!/bin/bash

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    echo "${branch/'refs/heads/'/''}" 
done

Salida:

master
other

La respuesta de Googlian, pero sin utilizar

git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/
for branch in "$(git for-each-ref --format='%(refname:short)' refs/heads)"; do
    ...
done

Esto utiliza Git comandos de fontanería, que están diseñados para secuencias de comandos. También es simple y estándar.

Referencia: finalización de Git Bash

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top