Listado de cada rama y la fecha de su última revisión en Git


138

Necesito eliminar ramas viejas y sin mantenimiento de nuestro repositorio remoto. Estoy tratando de encontrar una manera de enumerar las ramas remotas por su última fecha de modificación, y no puedo.

¿Hay una manera fácil de enumerar ramas remotas de esta manera?



3
Las respuestas a: stackoverflow.com/questions/5188320/… son todas mejores que las respuestas aquí
ingeniero de software el

Respuestas:


172

commandlinefu tiene 2 propuestas interesantes:

for k in `git branch | perl -pe s/^..//`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r

o:

for k in `git branch | sed s/^..//`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";done | sort

Eso es para sucursales locales, en una sintaxis Unix. Utilizando git branch -r, puede mostrar ramas remotas de manera similar:

for k in `git branch -r | perl -pe 's/^..(.*?)( ->.*)?$/\1/'`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r

Michael Forrest menciona en los comentarios que zsh requiere escapes para la sedexpresión:

for k in git branch | perl -pe s\/\^\.\.\/\/; do echo -e git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1\\t$k; done | sort -r 

Kontinuity agrega en los comentarios :

Si desea agregarlo a su zshrc, se necesita el siguiente escape.

alias gbage='for k in `git branch -r | perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r'

En multiples lineas:

alias gbage='for k in `git branch -r | \
  perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; \
  do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | \
     head -n 1`\\t$k; done | sort -r'

Nota: la respuesta de n8tr , basada en es más limpia. Y mas rapido . Consulte también " Opción de solo nombre para ? "git for-each-ref refs/heads
git branch --list

En términos más generales, tripleee nos recuerda en los comentarios :

  • Prefiere la $(command substitution)sintaxis moderna a la sintaxis obsoleta de retroceso.

(Ilustraba ese punto en 2014 con " ¿Cuál es la diferencia entre $(command)y `command`en la programación de shell? ")

  • No leas líneas confor .
  • Probablemente cambie a git for-each-ref refs/remotepara obtener nombres de sucursales remotas en formato legible por máquina

1
@hansen j: interesante, ¿no? Se lanzó unos meses después del lanzamiento público de Stack Overflow ( codeinthehole.com/archives/… ), y fue algo inspirado por SO. Vea también commandlinefu.com/commands/tagged/67/git para más git commandlinefu;)
VonC

Esta respuesta patea el culo de stackoverflow.com/questions/5188320/… . :)
Spundun

@SebastianG no está seguro: esa sería una buena pregunta propia.
VonC

+1 Es increíble cómo puedes agregar /jsonal final de cualquier URL de commandlinefu.com y obtendrás todos los comandos como JSON.
Noah Sussman

1
@tripleee Gracias. He editado la respuesta e incluí tus comentarios para mayor visibilidad.
VonC

121

Esto es lo que uso:

git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads

Esta es la salida:

2014-01-22 11:43:18 +0100       refs/heads/master
2014-01-22 11:43:18 +0100       refs/heads/a
2014-01-17 12:34:01 +0100       refs/heads/b
2014-01-14 15:58:33 +0100       refs/heads/maint
2013-12-11 14:20:06 +0100       refs/heads/d/e
2013-12-09 12:48:04 +0100       refs/heads/f

Para ramas remotas, solo use "refs / remotes" en lugar de "refs / heads":

git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/remotes

Sobre la base de la respuesta de n8tr , si también está interesado en el último autor en la rama y si tiene la herramienta "columna" disponible, puede usar:

git for-each-ref --sort='-committerdate:iso8601' --format='%(committerdate:relative)|%(refname:short)|%(committername)' refs/remotes/ | column -s '|' -t

Lo que te dará:

21 minutes ago  refs/remotes/a        John Doe
6 hours ago     refs/remotes/b        Jane Doe
6 days ago      refs/remotes/master   John Doe

Es posible que desee llamar a "git fetch --prune" antes para obtener la información más reciente.


55
Buen uso de for-each-ref y las opciones de formato. +1. Suena más fácil que los comandos a los que hago referencia en mi propia respuesta.
VonC

2
retocando un poco: ------- git for-each-ref --sort = '- authordate: iso8601' --format = '% (authordate: relative)% 09% (refname: short)' refs / heads ------- le da una fecha relativa y elimina las referencias / cabezas
n8tr

1
Para aquellos para quienes no es obvio de inmediato, creo que esto muestra información. estrictamente para sucursales locales.
hBrent

@hBrent tienes razón, no respondió exactamente la pregunta. He editado mi respuesta en consecuencia.
ocroquette

Esto ordena y enumera las ramas por authordate(¿qué parece ser cuando se creó la rama por primera vez?). Si cambia authordatea committerdate, verá las fechas de la confirmación más reciente en cada rama. Así:git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads
Logan Besecker

23

Partiendo de Olivier Croquette , me gusta usar una fecha relativa y acortar el nombre de la rama de esta manera:

git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads

Lo que te da salida:

21 minutes ago  nathan/a_recent_branch
6 hours ago        master
27 hours ago    nathan/some_other_branch
29 hours ago    branch_c
6 days ago      branch_d

Recomiendo hacer un archivo Bash para agregar todos sus alias favoritos y luego compartir el script con su equipo. Aquí hay un ejemplo para agregar solo este:

#!/bin/sh

git config --global alias.branches "!echo ' ------------------------------------------------------------' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------'"

Luego puede hacer esto para obtener una lista de sucursales locales bien formateada y ordenada:

git branches

20

Solo para agregar al comentario de @VonC, tome su solución preferida y agréguela a su lista de alias ~ / .gitconfig para mayor comodidad:

[alias]  
    branchdate = !git for-each-ref --sort='-authordate' --format='%(refname)%09%(authordate)' refs/heads | sed -e 's-refs/heads/--'

Luego, un simple "git branchdate" imprime la lista por usted ...


3
¡+1 para mostrar cómo usarlo con .gitconfig! Además, cambié la cadena de formato a: --format='%(authordate)%09%(objectname:short)%09%(refname)'que también obtiene el hash corto de cada rama.
Noah Sussman

Agradable. Agregaría "| tac" al final para ordenarlo en orden inverso para que las ramas tocadas recientemente sean rápidamente visibles.
Ben

1
No es necesario | tac, solo en --sort='authordate'lugar de-authordate
Kristján

4

Esto es lo que se me ocurrió después de también revisar esto .

for REF in $(git for-each-ref --sort=-committerdate --format="%(objectname)" \
    refs/remotes refs/heads)
do
    if [ "$PREV_REF" != "$REF" ]; then
        PREV_REF=$REF
        git log -n1 $REF --date=short \
            --pretty=format:"%C(auto)%ad %h%d %s %C(yellow)[%an]%C(reset)"
    fi
done

La PREV_REFcomprobación consiste en eliminar duplicados si más de una rama apunta a la misma confirmación. (Como en una sucursal local que también existe en el remoto).

TENGA EN CUENTA que según la solicitud de OP, git branch --mergedy git branch --no-mergedson útiles para identificar qué ramas se pueden eliminar fácilmente.

[ https://git-scm.com/docs/git-branch]


3

Ramas remotas ordenadas y la última fecha de confirmación para cada rama.

for branch in `git branch -r | grep -v HEAD`;do echo -e `git show --format="%ci %cr" $branch | head -n 1` \\t$branch; done | sort -r

1
Gracias por responder la pregunta de OP con respecto al control remoto.
arcseldon

1

Hice dos variantes, basadas en la respuesta de VonC .

Mi primera variante

for k in `git branch -a | sed -e s/^..// -e 's/(detached from .*)/HEAD/'`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`;done | sort | column -t -s "|"

Esto maneja ramas locales y remotas ( -a), maneja el estado de la cabeza separada (el comando sed más largo, aunque la solución es un poco cruda: simplemente reemplaza la información de la rama separada con la palabra clave HEAD), agrega el asunto de confirmación (% s ) y coloca las cosas en columnas mediante caracteres de canalización literales en la cadena de formato y pasando el resultado final a column -t -s "|". (Puede usar lo que sea como separador, siempre que sea algo que no espere en el resto de la salida).

Mi segunda variante es bastante hacky, pero realmente quería algo que todavía tenga un indicador de "esta es la rama en la que estás actualmente" como lo hace el comando de rama.

CURRENT_BRANCH=0
for k in `git branch -a | sed -e 's/\*/CURRENT_BRANCH_MARKER/' -e 's/(detached from .*)/HEAD/'`
do
    if [ "$k" == 'CURRENT_BRANCH_MARKER' ]; then
        # Set flag, skip output
        CURRENT_BRANCH=1
    elif [ $CURRENT_BRANCH == 0 ]; then
        echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`
    else
        echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset* %Cgreen$k%Creset |%s" $k --`
        CURRENT_BRANCH=0
    fi
done | sort | column -t -s "|"

Esto convierte lo *que marca la rama actual en una palabra clave, y cuando el cuerpo del bucle ve la palabra clave, establece una bandera y no muestra nada. El indicador se usa para indicar que se debe usar un formato alternativo para la siguiente línea. Como dije, es totalmente hacky, ¡pero funciona! (Principalmente. Por alguna razón, mi última columna se está quedando sin sangría en la rama actual).


Desafortunadamente, la información en la respuesta de VonCs no es una gran base para los scripts. Ver aquí git-blame.blogspot.com/2013/06/…
Andrew C

Hmm Eso muestra una forma de obtener el nombre de la rama actual, si tiene un nombre. ¿Hay alguna forma [preferida] de obtener una lista de sucursales amigable para las máquinas? (Y alguna forma de distinguir la rama actual, ya sea de esa salida directamente o de alguna manera preguntando a git "¿es esta la misma referencia que HEAD?")
benkc

git for-each-refes la forma fácil de guiar para procesar ramas. Tendría que ejecutar la simbólica-ref una vez para obtener la rama actual.
Andrew C

+1 por el esfuerzo, pero esa fue una vieja respuesta mía. stackoverflow.com/a/16971547/6309 o (más completo) stackoverflow.com/a/19585361/6309 puede implicar menos 'sed'.
VonC

1

Hice un alias simple, no estoy seguro de si esto es exactamente lo que preguntó, pero es simple

Hice esto porque quería enumerar todas las ramas, no solo mis ramas locales, que los comandos anteriores solo hacen

alias git_brs="git fetch && git branch -av --format='\''%(authordate)%09%(authordate:relative)%09%(refname)'\'"

Puede canalizar arriba grep originpara obtener solo orígenes

Esto enumera todas las ramas junto con la última fecha de modificación, me ayuda a decidir cuál debo obtener para la última versión

Esto da como resultado el siguiente tipo de pantalla

Wed Feb 4 23:21:56 2019 +0230   8 days ago      refs/heads/foo
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/heads/master
Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/heads/bar
Wed Feb 11 16:34:00 2019 +0230  2 days ago      refs/heads/xyz
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/HEAD
Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/remotes/origin/foo
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/master
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/bar
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/xyz

Intenta y avísame si te ayudó, feliz


Agradable y simple Sin salsa especial.
MrMas

0

O puede usar mi script PHP, https://gist.github.com/2780984

#!/usr/bin/env php
<?php
    $local = exec("git branch | xargs $1");
    $lines = explode(" ", $local);
    $limit = strtotime("-2 week");
    $exclude = array("*", "master");
    foreach ($exclude as $i) {
        $k = array_search($i, $lines);
        unset($lines[$k]);
    }
    $k = 0;
    foreach ($lines as $line) {
        $output[$k]['name'] = $line;
        $output[$k]['time'] = exec('git log '.$line.' --pretty=format:"%at" -1');
        if ($limit>$output[$k]['time']) {
            echo "This branch should be deleted $line\n";
            exec("git branch -d $line");
        }
        $k++;
    }
?>

0

Aquí hay una función que puede agregar a su bash_profile para facilitar esto.

Uso en un repositorio Git:

  • branch imprime todas las sucursales locales
  • branch -r imprime todas las ramas remotas

Función:

branch() {
   local pattern="s/^..//"
   local arg=""
   if [[ $@ == "-r" ]]; then
      pattern="s/^..(.*?)( ->.*)?$/\1/"
      arg=" -r "
      echo '-r provided'
   fi
   for k in $(git branch $arg | perl -pe "$pattern"); do
      echo -e $(git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1)\\t$k
   done | sort -r
}

0

En PowerShell, lo siguiente muestra ramas en el control remoto que ya están fusionadas y que tienen al menos dos semanas de antigüedad (el author:relativeformato comienza a mostrar semanas en lugar de días a las dos semanas):

$safeBranchRegex = "origin/(HEAD|master|develop)$";
$remoteMergedBranches = git branch --remote --merged | %{$_.trim()};
git for-each-ref --sort='authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/remotes | ?{$_ -match "(weeks|months|years) ago" -and $_ -notmatch "origin/(HEAD|master|qa/)"} | %{$_.substring($_.indexof("origin/"))} | ?{$_ -in $remoteMergedBranches}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.