¿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
* master
en mi sistema. El siguiente comando funcionó para mí:git branch -d $(git branch --merged |tail -n +2)
develop
entoncesgit branch --merged
incluyemaster
! Probablemente (¡definitivamente!) No quieras eliminar eso. También creo que debería sergit branch -d
donde minúsculas-d
significa "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-branches
Despué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 branch
para obtener el estado ascendente.Otra forma de obtener este estado es utilizar el comando "plomería"
git for-each-ref
con 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 master
git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d
Explicació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
gone
a 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-d
a-D
.fuente
git checkout master && ...
al comienzo del comando.git branch -vv
comenzará 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 -d
Normalmente 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 branch
salida en un script .git remote prune
,git prune
,git fetch --prune
Si 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 origin
que 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-ref
es 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/X
que 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/X
que 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/X
en 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/X
que 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 --prune
hace, pero por alguna razón, no le permite eliminar automáticamente el suyofeature/X
... a pesar de quefeature/X
todaví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 alias
que simplificar una serie de casos.xargs
o 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 otragrep
después de la primera. En ese caso irías:Entonces, si quisiéramos mantener
master
,develop
ystaging
por ejemplo, iríamos:Haz de esto un alias
Como es un poco largo, es posible que desee agregar un alias a su
.zshrc
o.bashrc
. El mío se llamagbpurge
(paragit branches purge
):Luego recarga tu
.bashrc
o.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 master
cambia a la rama maestragit remote update origin --prune
ciruelas pasas ramas remotasgit branch -vv
obtiene 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 -d
paragit branch -D
obtener el error, la rama no está completamente fusionada.git branch -D
es destructivo y eliminará el trabajo local que aún no ha presionado.-d
siempre 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
--format
bandera 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
--format
opció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 -D
refname: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-d
lugar 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 master
caja maestra de pagogit pull origin master
asegúrese de que la sucursal local tenga todos los cambios remotos combinadosgit fetch -p
eliminar 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 -D
comandogit branch -d
que 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)X
y una rama remotaorigin/X
; el repositorio remoto eliminaX
; ustedgit fetch-p
; en su repositorio local, no soloorigin/X
sino que tambiénX
se 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 branch
salida) pero agregando un * nix doblado.En su forma más simple:
Tengo esto envuelto en un
git-gone
script en mi camino:NB: la
--format
opció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:short
de Benjamin W.NB2: solo he probado
bash
, de ahí el hashbang, pero probablemente sea portátilsh
.fuente
sed
parte usando%(refname:short)
la primera línea?--format
. Otra forma de saltear lased
parte es usarlagit update-ref -d
. Tenga en cuenta que esto es probablemente algo inseguro, el usogit for-each-ref
es más seguro aquí (dado--shell
).--format
en 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 -d
Explicación: Prefiero reemplazar elgit branch --merged
bygit branch -vv
para mostrar el estado (desaparecido) porque el anteriorgit branch --merged
tambié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 fusionadaHEAD
o en su rama de seguimiento remoto ascendente. Por lo tanto, siempre puede recorrer la salidagit for-each-ref
e intentar eliminar cada rama. El problema con ese enfoque es que sospecho que probablemente no deseebug-fix-d
ser eliminado solo porqueorigin/bug-fix-d
contiene 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 -p
podará todas las ramas que ya no existan en el control remotogit branch -vv
imprimirá sucursales locales y la rama podada se etiquetará congone
grep ': gone]'
selecciona solo la rama que se ha idoawk '{print $1}'
filtrar la salida para mostrar solo el nombre de las ramasxargs git branch -D
recorrerá todas las líneas (ramas) y forzará a eliminar esta ramaPor qué
git branch -D
y nogit branch -d
má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
gone
lugar 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 -D
para forzar la eliminación de todogone
en 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 degrep
yawk
para 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
-d
opción engit branch
lugar de hacerlo-D
, como lo hago en mi configuración actual. Lo uso-D
porque no quiero escuchar a Git quejarse de ramas no fusionadas. Es posible que también desee esta funcionalidad. Si es así, simplemente use en-D
lugar de-d
al final de ese comando de configuración.fuente
git branch -vv
y codiciar: gone]
y no hacergit branch -v
y 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 -pn
combina la poda y enumera las ramas "desaparecidas":Luego puede apretar el gatillo con
git gone -d
ogit gone -D
.Notas
"$BRANCH/.*: gone]"
donde$BRANCH
normalmente estaríaorigin
. Esto probablemente no funcionará si su salida de Git está localizada en francés, etc.fuente
git gone
parece 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-ref
lugar debranch
(comobranch
es un comando de "porcelana" diseñado para una salida legible por humanos, no un procesamiento de máquina) y usa su--shell
argumento 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-prune
comando a tu gitgit for-each-ref
--filter
sin necesidad de dependencias externas.Explicación:
~\.gitconfig
. Después de ejecutar esto, simplemente puedes hacergit branch-prune
--prune
bandera, que "poda las ramas de seguimiento remoto que ya no están en el control remoto"git for-each-ref
y--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 --prune
Hizo 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 up
y 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.0
ygit 2.8.3
.Algunas notas
Asegúrese de configurar lo correcto
base_branch
. En este caso lo usodevelop
como 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 $f
conecho "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
zsh
Shell conOh My Zsh
instalado, 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