¿Existe una manera simple de eliminar todas las ramas de seguimiento cuyo equivalente remoto ya no existe?
Ejemplo:
Sucursales (locales y remotas)
- Maestro
- origen / maestro
- origen / corrección de errores-a
- origen / corrección de errores-b
- origen / corrección de errores-c
A nivel local, solo tengo una rama maestra. Ahora necesito trabajar en bug-fix-a , así que lo reviso, trabajo y empujo los cambios al control remoto. Luego hago lo mismo con bug-fix-b .
Sucursales (locales y remotas)
- Maestro
- bug-fix-a
- bug-fix-b
- origen / maestro
- origen / corrección de errores-a
- origen / corrección de errores-b
- origen / corrección de errores-c
Ahora tengo las sucursales locales master , bug-fix-a , bug-fix-b . El mantenedor de la rama maestra fusionará mis cambios en maestro y eliminará todas las ramas que ya ha fusionado.
Entonces el estado actual es ahora:
Sucursales (locales y remotas)
- Maestro
- bug-fix-a
- bug-fix-b
- origen / maestro
- origen / corrección de errores-c
Ahora me gustaría llamar a algún comando para eliminar ramas (en este caso, bug-fix-a , bug-fix-b ), que ya no están representadas en el repositorio remoto.
Sería algo así como el comando existente git remote prune origin, pero más parecido git local prune origin.
fuente

* masteren mi sistema. El siguiente comando funcionó para mí:git branch -d $(git branch --merged |tail -n +2)developentoncesgit branch --mergedincluyemaster! Probablemente (¡definitivamente!) No quieras eliminar eso. También creo que debería sergit branch -ddonde minúsculas-dsignifica "eliminación segura", por ejemplo, solo eliminar si se fusionó.git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branchesDespués del comando
elimina las referencias remotas, cuando ejecuta
mostrará "ido" como el estado remoto. Por ejemplo,
Para que pueda escribir una secuencia de comandos simple para eliminar las ramas locales que se han convertido en controles remotos:
Tenga en cuenta que lo anterior utiliza el comando "porcelana"
git branchpara obtener el estado ascendente.Otra forma de obtener este estado es utilizar el comando "plomería"
git for-each-refcon la variable de interpolación%(upstream:track), que será[gone]igual que la anterior.Este enfoque es algo más seguro, porque no hay riesgo de coincidencia accidental en parte del mensaje de confirmación.
fuente
git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'awk '/: gone]/{if ($1!="*") print $1}'. Esto ahora funciona como se esperaba.test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"La mayoría de estas respuestas no responden realmente la pregunta original. Hice un montón de excavación y esta fue la solución más limpia que encontré. Aquí hay una versión un poco más completa de esa respuesta:
git checkout mastergit fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -dExplicación:
Funciona podando sus ramas de rastreo y luego eliminando las locales que muestran que se han "ido"
git branch -vv.Notas:
Si su idioma está configurado en algo diferente al inglés, deberá cambiar
gonea la palabra apropiada. Las ramas que solo son locales no se tocarán. Las ramas que se han eliminado en remoto pero que no se fusionaron mostrarán una notificación pero no se eliminarán en local. Si desea eliminarlos, también cambie-da-D.fuente
git checkout master && ...al comienzo del comando.git branch -vvcomenzará con un asterisco que finalmente se ejecutarágit branch -d *. Aquí hay una versión parcheada que ignorará las líneas con asterisco:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -dNormalmente no respondería una pregunta que ya tiene 16 respuestas, pero todas las demás respuestas son incorrectas, y la respuesta correcta es muy simple. La pregunta dice: "¿Hay una manera simple de eliminar todas las ramas de seguimiento cuyo equivalente remoto ya no existe?"
Si "simple" significa eliminarlos de una vez, no son frágiles, no son peligrosos y no dependen de herramientas que no todos los lectores tendrán, entonces la respuesta correcta es: no.
Algunas respuestas son simples, pero no hacen lo que se les pidió. Otros hacen lo que se les pidió, pero no son simples: todos confían en analizar la salida de Git a través de comandos de manipulación de texto o lenguajes de script, que pueden no estar presentes en todos los sistemas. Además de eso, la mayoría de las sugerencias usan comandos de porcelana, cuya salida no está diseñada para ser analizada por script ("porcelain" se refiere a los comandos destinados a la operación humana; los scripts deben usar los comandos de "plomería" de nivel inferior).
Otras lecturas:
git branchsalida en un script .git remote prune,git prune,git fetch --pruneSi desea hacer esto de forma segura, para el caso de uso en la pregunta (ramas de seguimiento de recolección de basura que se han eliminado en el servidor pero que todavía existen como ramas locales) y solo con comandos Git de alto nivel, debe
git fetch --prune(ogit fetch -p, que es un alias, ogit prune remote originque hace lo mismo sin buscar, y probablemente no es lo que quieres la mayor parte del tiempo).git branch -v(cualquier rama de seguimiento huérfana se marcará "[desaparecido]").git branch -d [branch_name]en cada rama de seguimiento huérfana(que es lo que proponen algunas de las otras respuestas).
Si desea escribir una solución, entonces
for-each-refes su punto de partida, como en la respuesta de Mark Longair aquí y esta respuesta a otra pregunta , pero no puedo ver una manera de explotarla sin escribir un bucle de script de shell, o usar xargs o algo .Explicación de fondo
Para comprender lo que está sucediendo, debe apreciar que, en la situación de rastrear sucursales, no tiene una, sino tres. (Y recuerde que "rama" significa simplemente un puntero a una confirmación).
Dada una rama de seguimiento
feature/X, el repositorio remoto (servidor) tendrá esta rama y la llamaráfeature/X. Su repositorio local tiene una ramaremotes/origin/feature/Xque significa: "Esto es lo que el control remoto me dijo que era su característica / rama X, la última vez que hablamos", y finalmente, el repositorio local tiene una ramafeature/Xque apunta a su último commit y está configurado para "seguimiento"remotes/origin/feature/X, lo que significa que puede tirar y empujar para mantenerlos alineados.En algún momento, alguien ha eliminado el
feature/Xen el control remoto. A partir de ese momento, te quedarás con tu localfeature/X(que probablemente ya no quieras más, ya que presumiblemente el trabajo en la función X está presumiblemente terminado), y turemotes/origin/feature/Xque sin duda es inútil porque su único propósito era recordar el estado de la rama del servidor .Y Git le permitirá limpiar automáticamente el redundante
remotes/origin/feature/X, eso es lo quegit fetch --prunehace, pero por alguna razón, no le permite eliminar automáticamente el suyofeature/X... a pesar de quefeature/Xtodavía contiene la información de seguimiento huérfana, por lo que tiene la información para identificar antiguas ramas de seguimiento que se han fusionado completamente. (Después de todo, se puede dar que la información que le permite hacer la operación por sí mismo la mano.)fuente
xargs). También haygit aliasque simplificar una serie de casos.xargso critican, y probablemente no están buscando un desafío de microcodificación, sino una respuesta rápida que pueden aplicar de manera segura sin distraerse más de su objetivo real. .Encontré la respuesta aquí: ¿Cómo puedo eliminar todas las ramas git que se han fusionado?
Asegúrate de seguir siendo maestro
Puede asegurarse de que
master, o cualquier otra rama para el caso, no se elimine agregando otragrepdespués de la primera. En ese caso irías:Entonces, si quisiéramos mantener
master,developystagingpor ejemplo, iríamos:Haz de esto un alias
Como es un poco largo, es posible que desee agregar un alias a su
.zshrco.bashrc. El mío se llamagbpurge(paragit branches purge):Luego recarga tu
.bashrco.zshrc:o
fuente
Solución de Windows
Para Microsoft Windows Powershell:
git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}Explicación
git checkout mastercambia a la rama maestragit remote update origin --pruneciruelas pasas ramas remotasgit branch -vvobtiene una salida detallada de todas las ramas ( referencia de git )Select-String -Pattern ": gone]"obtiene solo los registros donde se han eliminado del control remoto.% { $_.toString().Trim().Split(" ")[0]}obtener el nombre de la sucursal% {git branch -d $_}elimina la ramafuente
.Trim()after.toString()para eliminar dos espacios antes del nombre de la rama.git branch -dparagit branch -Dobtener el error, la rama no está completamente fusionada.git branch -Des destructivo y eliminará el trabajo local que aún no ha presionado.-dsiempre es seguro, solo ten cuidado-D.La coincidencia de patrones para "desaparecido" en la mayoría de las otras soluciones me dio un poco de miedo. Para estar más seguro, esto usa la
--formatbandera para extraer el estado de seguimiento ascendente de cada rama .Necesitaba una versión compatible con Windows, por lo que esto elimina todas las ramas que se enumeran como "desaparecidas" usando Powershell:
La primera línea enumera el nombre de las sucursales locales cuya rama ascendente está "desaparecida". La siguiente línea elimina las líneas en blanco (que se muestran para las ramas que no están "desaparecidas"), luego el nombre de la rama se pasa al comando para eliminar la rama.
fuente
--formatopción parece ser bastante nueva; Necesitaba actualizar git de 2.10.algo a 2.16.3 para obtenerlo. Esta es mi modificación para sistemas Linux-ish:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -Drefname:short. Entonces puedes borrar la línea% { $_ -replace '^refs/heads/', '' }git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }También es probablemente una buena idea usarlo en-dlugar de-D. La eliminación forzada no debería ser necesaria para las ramas que ya no están en remoto.Elimine todas las ramas que se han fusionado en master, pero no intente eliminar el master en sí:
git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)o agrega un alias:
alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"Explicación:
git checkout mastercaja maestra de pagogit pull origin masterasegúrese de que la sucursal local tenga todos los cambios remotos combinadosgit fetch -peliminar referencias a ramas remotas que se han eliminadogit branch -d $(git branch master --merged | grep master -v)elimine todas las ramas que se han fusionado en master, pero no intente eliminar el masterfuente
git branch -Dcomandogit branch -dque deberían emitir una advertencia sobre ramas no empujadas.Esto eliminará cualquier rama que ya no exista en el control remoto.
fuente
X; ustedgit checkout X; ahora su repositorio tiene una rama de seguimiento (local)Xy una rama remotaorigin/X; el repositorio remoto eliminaX; ustedgit fetch-p; en su repositorio local, no soloorigin/Xsino que tambiénXse han eliminado. ¿Eso es lo que estás diciendo?Sin embargo, otra respuesta para la pila, basada en gran medida en la respuesta de Patrick (que me gusta porque parece eliminar cualquier ambigüedad sobre dónde
gone]coincidirá en lagit branchsalida) pero agregando un * nix doblado.En su forma más simple:
Tengo esto envuelto en un
git-gonescript en mi camino:NB: la
--formatopción parece ser bastante nueva; Necesitaba actualizar git de 2.10.algo a 2.16.3 para obtenerlo.EDIT: ajustado para incluir sugerencia sobre
refname:shortde Benjamin W.NB2: solo he probado
bash, de ahí el hashbang, pero probablemente sea portátilsh.fuente
sedparte usando%(refname:short)la primera línea?--format. Otra forma de saltear lasedparte es usarlagit update-ref -d. Tenga en cuenta que esto es probablemente algo inseguro, el usogit for-each-refes más seguro aquí (dado--shell).--formaten hacerlo yo mismo. Solo una pregunta: ¿por qué#!bash? Todo aquí me parece portátilsh.Puede ser útil para algunos, una línea simple para borrar todas las sucursales locales, excepto master y desarrollo
fuente
'git branch | grep -v "master" | grep -v "develop"tipo de cosas antes de comprometerse a agregar la parte de eliminación del comando. 👏😊Esto eliminará todas las ramificaciones locales fusionadas, excepto la referencia maestra local y la que se está utilizando actualmente:
Y esto eliminará todas las ramas que ya se han eliminado del repositorio remoto al que hace referencia " origen ", pero que todavía están disponibles localmente en " control remoto / origen ".
fuente
git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -dExplicación: Prefiero reemplazar elgit branch --mergedbygit branch -vvpara mostrar el estado (desaparecido) porque el anteriorgit branch --mergedtambién puede mostrar el maestroNo creo que haya un comando incorporado para hacer esto, pero es seguro hacer lo siguiente:
Cuando lo use
-d, git se negará a eliminar la rama a menos que esté completamente fusionadaHEADo en su rama de seguimiento remoto ascendente. Por lo tanto, siempre puede recorrer la salidagit for-each-refe intentar eliminar cada rama. El problema con ese enfoque es que sospecho que probablemente no deseebug-fix-dser eliminado solo porqueorigin/bug-fix-dcontiene su historial. En su lugar, podría crear un script similar a lo siguiente:Advertencia: no he probado este script, úselo solo con cuidado ...
fuente
TL; DR:
Eliminar TODAS las sucursales locales que no están en remoto
Elimine TODAS las ramas locales que no estén en el control remoto Y que estén completamente fusionadas Y que no se usen como se dijo anteriormente en muchas respuestas.
Explicación
git fetch -ppodará todas las ramas que ya no existan en el control remotogit branch -vvimprimirá sucursales locales y la rama podada se etiquetará congonegrep ': gone]'selecciona solo la rama que se ha idoawk '{print $1}'filtrar la salida para mostrar solo el nombre de las ramasxargs git branch -Drecorrerá todas las líneas (ramas) y forzará a eliminar esta ramaPor qué
git branch -Dy nogit branch -dmás tendrá para las ramas que no están completamente fusionadas.fuente
Podrías hacer esto:
fuente
Según la información anterior, esto funcionó para mí:
Elimina todas las sucursales locales que están
': gone] 'en remoto.fuente
gonelugar en su nombre.El comando anterior se puede usar para buscar ramas que se fusionan y eliminan en remoto y elimina la rama local que ya no está disponible en remoto
fuente
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Dpara forzar la eliminación de todogoneen alguna parte de ellos (por ejemplousingonefunction).Nada de esto fue realmente bueno para mí. Quería algo que purgara todas las sucursales locales que estaban rastreando una rama remota, en
origin, donde se ha eliminado la rama remota (gone). No quería eliminar ramas locales que nunca se configuraron para rastrear una rama remota (es decir, mis ramas de desarrollo local). También quería una línea simple que solo usegit, u otras herramientas simples de CLI, en lugar de escribir scripts personalizados. Terminé usando un poco degrepyawkpara hacer este simple comando.Esto es lo que finalmente terminó en mi
~/.gitconfig:Aquí hay un
git config --global ...comando para agregar esto fácilmente comogit prune-branches:NOTA: en el comando config, utilizo la
-dopción engit branchlugar de hacerlo-D, como lo hago en mi configuración actual. Lo uso-Dporque no quiero escuchar a Git quejarse de ramas no fusionadas. Es posible que también desee esta funcionalidad. Si es así, simplemente use en-Dlugar de-dal final de ese comando de configuración.fuente
git branch -vvy codiciar: gone]y no hacergit branch -vy codiciar[gone]?v. Sigit branch -v | grep '[gone]'te funciona, hazlo. Parece un poco más limpio.Basado en el consejo de Git: Eliminando viejas sucursales locales , que se parece a la solución de jason.rickman . Implementé un comando personalizado para este propósito llamado git gone usando Bash:
git gone -pncombina la poda y enumera las ramas "desaparecidas":Luego puede apretar el gatillo con
git gone -dogit gone -D.Notas
"$BRANCH/.*: gone]"donde$BRANCHnormalmente estaríaorigin. Esto probablemente no funcionará si su salida de Git está localizada en francés, etc.fuente
git goneparece un alias paragit branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, que resuelve el problema del OP.Basándose en gran medida a partir de un número de otras respuestas aquí, he terminado con la siguiente (GIT 2.13 y superior, creo), que debe funcionar en cualquier tipo UNIX shell:
Esto usa notablemente en
for-each-reflugar debranch(comobranches un comando de "porcelana" diseñado para una salida legible por humanos, no un procesamiento de máquina) y usa su--shellargumento para obtener una salida con escape adecuado (esto nos permite no preocuparnos por ningún carácter en el nombre de referencia).fuente
[ ! -z "$ref" ]significa. Creo que un revestimiento múltiple ya habría ayudado. ¡Pero aún así, gracias por tu aporte!Otra respuesta más, porque ninguna de las soluciones satisface mis necesidades de elegancia y multiplataforma:
Comando para eliminar ramas locales que no están en remoto:
Para integrarlo con gitconfig para que pueda ejecutarse con
git branch-prune:Golpetazo
Potencia Shell
(Necesita ayuda para encontrar un comando universal para PowerShell y bash)
¿Por qué esta respuesta es la mejor?
git branch-prunecomando a tu gitgit for-each-ref--filtersin necesidad de dependencias externas.Explicación:
~\.gitconfig. Después de ejecutar esto, simplemente puedes hacergit branch-prune--prunebandera, que "poda las ramas de seguimiento remoto que ya no están en el control remoto"git for-each-refy--filter, para obtener una lista de las ramas son[gone](sin control remoto)fuente
Se me ocurrió este script bash. Siempre mantener las ramas
develop,qa,master.fuente
Utilizo un método corto para hacer el truco, te recomiendo que hagas lo mismo ya que podría ahorrarte algunas horas y darte más visibilidad
Simplemente agregue el siguiente fragmento en su .bashrc (.bashprofile en macos).
Tendrá que editar el grep regex para que se ajuste a sus necesidades (aquí, evita que se eliminen master, preprod y dmz)
fuente
git fetch --all --pruneHizo el truco. ¡Gracias!Esto funcionó para mí:
fuente
No estoy seguro de cuánto tiempo, pero uso git-up ahora, que se encarga de eso.
Lo hago
git upy comienza a rastrear nuevas ramas y elimina las viejas.Solo para que quede claro, no es un comando git listo para usar: https://github.com/aanand/git-up
Por cierto, también esconde árboles sucios y hace rebases con solo
git up.Espero que sea útil para alguien
fuente
Aquí hay una solución que uso para la concha de pescado. Probado en
Mac OS X 10.11.5,fish 2.3.0ygit 2.8.3.Algunas notas
Asegúrese de configurar lo correcto
base_branch. En este caso lo usodevelopcomo la rama base, pero podría ser cualquier cosa.Esta parte es muy importante:
grep -v "\(master\|$base_branch\|\*\)". Asegura que no elimine el maestro o su rama base.Lo uso
git branch -d <branch>como precaución adicional, para no eliminar ninguna rama que no se haya fusionado completamente con HEAD ascendente o actual.Una forma fácil de probar es reemplazar
git branch -d $fconecho "will delete $f".Supongo que también debería agregar: ¡UTILICE BAJO SU PROPIO RIESGO!
fuente
He escrito un script de Python usando GitPython para eliminar ramas locales que no existen en remoto.
Espero que alguien lo encuentre útil, agregue comentarios si me perdí algo.
fuente
Si está utilizando
zshShell conOh My Zshinstalado, la forma más fácil de hacerlo de forma segura es utilizar el autocompletado incorporado.Primero determine con qué ramas desea eliminar:
esto le mostrará una lista de ramas ya fusionadas
Después de saber algunos que desea eliminar, escriba:
Todo lo que tiene que hacer es presionar [tab] y le mostrará una lista de sucursales locales. Use tab-complete o simplemente presione [tab] nuevamente y puede recorrerlos para seleccionar una rama con [enter].
Pestaña Seleccione las ramas una y otra vez hasta que tenga una lista de ramas que desea eliminar:
Ahora solo presione enter para eliminar su colección de ramas.
Si no está usando zsh en su terminal ... Consíguelo aquí.
fuente
Me gusta usar tuberías porque hace que el comando sea más fácil de leer.
Esta es mi solución si desea eliminar todas las ramas excepto la maestra.
Para eliminar otras ramas que coincidan con sus criterios, modifique el primer y segundo bloque.
fuente
Aquí está la respuesta simple que funcionó para mí usando un cliente git:
Elimine el repositorio por completo de su máquina y luego vuelva a pagar.
No perder el tiempo con guiones arriesgados.
fuente