La manera de recorrer todas las ramas git utilizando escritura del golpe
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
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 ??em> 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}"
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