Uso de expresiones regulares en Git Shell al verificar múltiples sucursales

Si tengo el siguiente command git shell:

for branch in `git branch -a | grep remotes | grep -v master | sed 's/^.*old\/\(.*\)/\1/g'`; do git branch --track $branch remotes/old/$branch; done 

Esto verifica todas las twigs remotas que existen en el control remoto anterior y las rastrea usando el mismo nombre que tienen en ese control remoto. Sin embargo, ¿qué pasaría si quisiera cambiar ligeramente el nombre que tienen las sucursales locales?

¿Qué sucede si tengo las siguientes twigs remotas?

 release/1.2.1.0 release/1.2.1.1 

Y quiero verificarlos en la misma release carpeta principal, pero solo quiero los últimos 3 dígitos en el número de versión. Entonces quiero que mis sucursales locales sean:

 release/2.1.0 release/2.1.1 

Tengo una simple expresión regular de JavaScript que coincide con los últimos 3 dígitos de la cadena de versión: (?:\d\.)(\d.*)

Esto usa un grupo que no coincide para arrojar el primer dígito seguido por el punto. La pregunta es, ¿cómo aplico esa expresión regular a la variable $branch en el script git shell bash anterior?

Primero, evita la git branch para loops como este. La herramienta correcta aquí es git for-each-ref , que está diseñada para trabajar con lenguajes de scripting ( git branch está dirigida a usuarios y el formatting de salida puede cambiar en el futuro, por ejemplo).

Para recorrer todas las twigs de seguimiento remoto, simplemente indique for-each-ref que escanee el espacio de nombre de la sucursal de seguimiento remoto. Como quiera, más específicamente, el control remoto llamado old , puede hacerlo fácilmente añadiendo /old también:

 git for-each-ref refs/remotes/old 

El resultado aquí se pnetworkingetermina a un triple de objectname objecttype refname . Solo nos importa la parte refname (y podemos usar el modificador :short para quitar refs/remotes/ también, si queremos, aunque todavía tenemos que soltar el old/ para que podamos salir sin el modificador). Por lo tanto, queremos include --format=%(refname:short) .

Pasando a bash, bash tiene soporte de expresiones regulares incorporado. Sin embargo, su syntax RE no es lo mismo, por lo que su RE existente debe cambiar. Aquí hay uno que probablemente funcione para sus necesidades:

 bash$ x=1.2.3.4 bash$ [[ $x =~ ([0-9]\.)([0-9.]+) ]] && echo ${BASH_REMATCH[2]} 2.3.4 

(Aquí hay un poco de sutileza: usar $x cambia la forma en que se aplica =~ match, que en nuestro caso probablemente sea buena. Como persona de Unix de la vieja escuela, generalmente prefiero usar expr , pero en este caso podría recurrir a haciendo esto en Python, que tiene RE de estilo Perl, y Javascript / RE de ECMAscript están modelados en Perl. Pero todo eso es más o less irrelevante. Lo más importante es que este RE es ligeramente inferior al de un apostador de número de versión. Por ejemplo, coincide con cadenas como "1.3..6". Estamos a salvo en que estos son nombres de twig no válidos, los puntos dobles están prohibidos, ya que entrarían en conflicto con la syntax de resta establecida en gitrevisions pero en general es un poco descuidado; Podríamos encontrar una expresión más estricta. Tampoco coincide con las revisiones que comienzan con dos o más dígitos, pero su ER original también lo hizo, así que lo dejé a propósito).

Leer en un bucle en shell, usar -r es generalmente sabio (ver el comentario de Etan Reisner ), aunque en este caso podríamos omitirlo de manera segura ya que git controla los nombres de las twigs. Lo usaré en el ejemplo solo por el bien de la forma.

Poniendo todo esto junto:

 warn() { echo "warning: $@" 1>&2 } # Given an input name release/\d\.(\d|\.)+, make # a local branch named release/\2 (more or less). make_local_release_branch() { local relnum newname relnum=${1#old/release/} [[ $relnum =~ ([0-9]\.)([0-9.]+) ]] || { warn "remote-tracking branch $1 does not conform to name style, ignonetworking" return } newname=release/${BASH_REMATCH[2]} git rev-parse -q --verify refs/heads/$newname >/dev/null && { warn "branch $newname already exists, remote-tracking branch $1 ignonetworking" return } git branch --track $branch $1 } git for-each-ref --format='%(refname:short)' refs/remotes/old | while read -r rmtbranch; do case $rmtbranch in old/release/[0-9]*) make_local_release_branch "$rmtbranch";; *) warn "skipping remote branch $rmtbranch -- not old/release/[digit]";; esac done 

(Todo esto no ha sido probado).