git - remote - Elimine las ramas de seguimiento que ya no estén en el control remoto.
git push tag (25)
¿Existe una forma sencilla de eliminar todas las ramas de seguimiento cuyo equivalente remoto ya no existe?
Ejemplo:
Ramas (locales y remotas)
- dominar
- origen / maestro
- origen / bug-fix-a
- origen / bug-fix-b
- origen / bug-fix-c
A nivel local, solo tengo una rama maestra. Ahora necesito trabajar en bug-fix-a , así que lo compruebo, trabajo en él y presiono los cambios en el control remoto. A continuación hago lo mismo con bug-fix-b .
Ramas (locales y remotas)
- dominar
- corrección de errores-a
- corrección de errores-b
- origen / maestro
- origen / bug-fix-a
- origen / bug-fix-b
- origen / bug-fix-c
Ahora tengo maestro de sucursales locales, corrección de errores , corrección de errores , b . El mantenedor de la rama maestra combinará mis cambios en la maestra y eliminará todas las ramas que ya haya fusionado.
Así que el estado actual es ahora:
Ramas (locales y remotas)
- dominar
- corrección de errores-a
- corrección de errores-b
- origen / maestro
- origen / bug-fix-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 bien como git local prune origin
.
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 $_}
Explicacion
git checkout master
cambia a la rama maestra
git remote update origin --prune
las ramas remotas
git 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]}
obtiene el nombre de la rama
% {git branch -d $_}
borra la rama
Aquí hay una solución que utilizo para la cáscara de pescado. Probado en Mac OS X 10.11.5
, fish 2.3.0
y git 2.8.3
.
function git_clean_branches
set base_branch develop
# work from our base branch
git checkout $base_branch
# remove local tracking branches where the remote branch is gone
git fetch -p
# find all local branches that have been merged into the base branch
# and delete any without a corresponding remote branch
set local
for f in (git branch --merged $base_branch | grep -v "/(master/|$base_branch/|/*/)" | awk ''//s*/w*/s*/ {print $1}'')
set local $local $f
end
set remote
for f in (git branch -r | xargs basename)
set remote $remote $f
end
for f in $local
echo $remote | grep --quiet "/s$f/s"
if [ $status -gt 0 ]
git branch -d $f
end
end
end
Algunas notas:
Asegúrate de establecer la base_branch
correcta. En este caso utilizo develop
como la rama base, pero podría ser cualquier cosa.
Esta parte es muy importante: grep -v "/(master/|$base_branch/|/*/)"
. Se asegura de que no elimine maestro o su rama base.
Uso git branch -d <branch>
como precaución adicional, para no eliminar ninguna rama que no haya sido completamente fusionada con HEAD anterior o actual.
Una forma fácil de probar es reemplazar git branch -d $f
con echo "will delete $f"
.
Supongo que también debo agregar: ¡UTILICE A SU PROPIO RIESGO!
Basado en la sugerencia de Git: eliminar viejas sucursales locales , que se parece a la solución de jason.rickman, implementé un comando personalizado para este propósito llamado git ido usando Bash:
$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
-p prune remote branch
-n dry run: list the gone branches
-d delete the gone branches
-D delete the gone branches forcefully
EXAMPLES
git gone -pn prune and dry run
git gone -d delete the gone branches
git gone -pn
combina la poda y el listado de las ramas "ido":
$ git gone -pn
bport/fix-server-broadcast b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
fport/rangepos 45c857d15 [origin/fport/rangepos: gone] Bump modules
Luego puedes apretar el gatillo usando git gone -d
o git gone -D
.
Notas
- La expresión regular que utilicé es
"$BRANCH/.*: gone]"
donde$BRANCH
normalmente seríaorigin
. Esto probablemente no funcionará si su salida de Git está localizada en francés, etc. - Sebastian Wiesner también lo portó a Rust para los usuarios de Windows. Ese también se llama git ido .
Basado en la información anterior, esto funcionó para mí:
git br -d `git br -vv | grep '': gone] '' | awk ''{print $1}'' | xargs`
Elimina todas las sucursales locales con '': gone] ''
en el control remoto.
Despues del comando
git fetch -p
elimina las referencias remotas, cuando se ejecuta
git branch -vv
se mostrará ''ido'' como el estado remoto. Por ejemplo,
$ git branch -vv
master b900de9 [origin/master: behind 4] Fixed bug
release/v3.8 fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
release/v3.9 0d680d0 [origin/release/v3.9: behind 2] Updated comments
bug/1234 57379e4 [origin/bug/1234: gone] Fixed bug
Por lo tanto, puede escribir un script simple para eliminar las sucursales locales que se han ido a control remoto:
git fetch -p && for branch in `git branch -vv | grep '': gone]'' | awk ''{print $1}''`; do git branch -D $branch; done
Elimine todas las ramas que se hayan fusionado en el maestro, pero no intente eliminar el propio maestro:
git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)
o agregar 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
checkout maestro rama
git pull origin master
asegura que la sucursal local tenga todos los cambios remotos fusionados
git fetch -p
elimina las referencias a ramas remotas que han sido eliminadas
git branch -d $(git branch master --merged | grep master -v)
elimina todas las sucursales que se han fusionado en master, pero no intentes eliminar master en sí mismo
Encontré la respuesta aquí: ¿Cómo puedo eliminar todas las ramas de git que se han fusionado?
git branch --merged | grep -v "/*" | xargs -n 1 git branch -d
Asegúrate de que tenemos maestro
Puede asegurarse de que el master
, o cualquier otra rama, no se elimine agregando otro grep
después de la primera. En ese caso irías:
git branch --merged | grep -v "/*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d
Entonces, si quisiéramos master
, develop
y staging
por ejemplo, iríamos:
git branch --merged | grep -v "/*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d
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 llama gbpurge
(para git branches purge
):
alias gbpurge=''git branch --merged | grep -v "/*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d''
Luego recargue su .bashrc
o .zshrc
:
. ~/.bashrc
o
. ~/.zshrc
Esto eliminará toda la ramificación local combinada excepto la referencia maestra local y la que se está utilizando actualmente:
git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d
Y esto eliminará todas las ramas que ya han sido eliminadas del repositorio remoto referenciado por " origen ", pero aún están disponibles localmente en " remotos / origen ".
git remote prune origin
Esto eliminará todas las ramas remotas que no están presentes localmente (en ruby):
bs = `git branch`.split; bs2 = `git branch -r | grep origin`.split.reject { |b| bs.include?(b.split(''/'')[1..-1].join(''/'')) }; bs2.each { |b| puts `git push origin --delete #{b.split(''/'')[1..-1].join(''/'')}` }
Explicado:
# local branches
bs = `git branch`.split
# remote branches
bs2 = `git branch -r | grep origin`.split
# reject the branches that are present locally (removes origin/ in front)
bs2.reject! { |b| bs.include?(b.split(''/'')[1..-1].join(''/'')) }
# deletes the branches (removes origin/ in front)
bs2.each { |b| puts `git push origin --delete #{b.split(''/'')[1..-1].join(''/'')}` }
Esto funcionó para mí:
git branch -r | awk ''{print $1}'' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk ''{print $1}'' | xargs git branch -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, utiliza el indicador --format
para extraer el estado de seguimiento ascendente de cada sucursal.
Necesitaba una versión compatible con Windows, por lo que se eliminan todas las ramas que aparecen como "desaparecidas" con Powershell:
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" |
? { $_ -ne "" } |
% { git branch -D $_ }
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 emiten para las ramas que no están "desaparecidas"), luego el nombre de la rama se pasa al comando para eliminar la rama.
La mayoría de estas respuestas no responden realmente a la pregunta original. Hice un montón de excavaciones y this fue la solución más limpia que encontré. Aquí hay una versión un poco más completa de esa respuesta:
- Echa un vistazo a su rama por defecto. Generalmente
git checkout master
- Ejecutar
git fetch -p && git branch -vv | awk ''/: gone]/{print $1}'' | xargs git branch -d
git fetch -p && git branch -vv | awk ''/: gone]/{print $1}'' | xargs git branch -d
Explicación:
Trabaja podando las ramas de seguimiento y luego borrando las locales que muestran que se han "ido" en git branch -vv
.
Notas:
Si su idioma está configurado en otro idioma que no sea el inglés, deberá cambiar la palabra apropiada. Las ramas que son locales solamente no serán tocadas. Las sucursales que se eliminaron en el control remoto pero no se fusionaron mostrarán una notificación, pero no se eliminarán en local. Si desea eliminarlos también cambie -d
a -D
.
Nada de esto era realmente correcto para mí. Quería algo que eliminara todas las sucursales locales que estaban rastreando una sucursal remota, en el origin
, donde la sucursal remota se ha eliminado ( gone
). No quería eliminar las sucursales locales que nunca se configuraron para rastrear una sucursal remota (es decir, mis sucursales de desarrollo local). También quería un sencillo de una sola línea que solo use git
u otras herramientas CLI simples, en lugar de escribir scripts personalizados. Terminé usando un poco de grep
y awk
para hacer este comando simple.
Esto es en última instancia, lo que terminó en mi ~/.gitconfig
:
[alias]
prune-branches = !git remote prune origin && git branch -vv | grep '': gone]'' | awk ''{print $1}'' | xargs -r git branch -D
Aquí hay un comando git config --global ...
para agregarlo fácilmente como git prune-branches
:
git config --global alias.prune-branches ''!git remote prune origin && git branch -vv | grep ''"''"'': gone]''"''"'' | awk ''"''"''{print $1}''"''"'' | xargs -r git branch -d''
NOTA: En el comando config, uso la opción -d
para git branch
lugar de -D
, como lo hago en mi configuración real. Uso -D
porque no quiero escuchar a Git quejarse de las ramas no fusionadas. Es posible que desee esta funcionalidad también. Si es así, simplemente use -D
lugar de -d
al final de ese comando de configuración.
No creo que haya un comando incorporado para hacer esto, pero es seguro hacer lo siguiente:
git checkout master
git branch -d bug-fix-a
Cuando use -d
, git rechazará eliminar la rama a menos que esté completamente fusionada con HEAD
o su rama de seguimiento remoto ascendente. Por lo tanto, siempre se puede hacer un bucle sobre la salida de git for-each-ref
y tratar de eliminar cada rama. El problema con este enfoque es que sospecho que probablemente no desee que se elimine bug-fix-d
solo porque origin/bug-fix-d
contiene su historial. En su lugar, podría crear un script similar al siguiente:
#!/bin/sh
git checkout master &&
for r in $(git for-each-ref refs/heads --format=''%(refname:short)'')
do
if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
then
if [ "$r" != "master" ]
then
git branch -d "$r"
fi
fi
done
Advertencia: no he probado este script; utilícelo solo con cuidado ...
No estoy seguro de cuánto tiempo, pero uso git-up ahora, lo cual se encarga de eso.
Lo hago y empieza a rastrear nuevas sucursales y borra las antiguas.
Solo para dejarlo claro, no es un comando git listo para usar: https://github.com/aanand/git-up
Por cierto, también esconde un árbol sucio y hace rebases aún con solo git up
.
Espero que sea de utilidad para alguien.
Normalmente no respondería una pregunta que ya tenga 16 respuestas, pero todas las demás respuestas son incorrectas, y la respuesta correcta es muy simple. La pregunta dice: "¿Existe una forma sencilla de eliminar todas las ramas de seguimiento cuyo equivalente remoto ya no existe?"
Si "simple" significa no es frágil, no es peligroso y no se confía en 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 se basan en analizar la salida de Git (y la salida de porcelana para arrancar en la mayoría de los casos) a través de comandos de manipulación de texto o lenguajes de script, que pueden no estar presentes en todos los sistemas.
Más información: https://.com/a/20107184/587365 y https://.com/a/26152574/587365
Si desea hacer esto de manera segura, para el caso de uso en la pregunta (recolectando basura en las ramas de seguimiento que se han eliminado en el servidor pero aún existen como sucursales locales) y solo con comandos de Git de alto nivel, debe
-
git fetch --prune
(ogit fetch -p
, que es un alias, ogit prune remote origin
que hace lo mismo sin recuperar, y probablemente no sea lo que desea la mayoría del tiempo). - Tenga en cuenta las sucursales remotas que se informan como eliminado. O, para encontrarlos más adelante,
git branch -v
(cualquier rama de seguimiento huérfana se marcará "[desaparecido]"). -
git branch -d [branch_name]
en cada rama de seguimiento huérfana
Explicación de fondo
Para comprender lo que está sucediendo, debe apreciar que, en la situación de seguimiento de sucursales, no tiene una, sino tres. (Y recuerde que "rama" significa simplemente un puntero a una confirmación).
Dada una feature/X
rama de seguimiento feature/X
, el repositorio remoto (servidor) tendrá esta rama y lo llamará feature/X
Su repositorio local tiene una rama remotes/origin/feature/X
que significa que "esto es lo que me dijo el control remoto su característica / rama X, la última vez que hablamos", y finalmente, el repositorio local tiene una feature/X
rama feature/X
que apunta a su último compromiso, y está configurado para "rastrear" los remotes/origin/feature/X
, lo que significa que puede tirar y empujar para mantenerlos alineados.
En algún momento, alguien ha eliminado la feature/X
en el control remoto. A partir de ese momento, se queda con su feature/X
local (que probablemente ya no desee más, ya que el trabajo en la función X probablemente está terminado), y sus remotes/origin/feature/X
que ciertamente son inútiles porque es el único El propósito era recordar el estado de la rama del servidor.
Y Git te permitirá limpiar automáticamente los remotes/origin/feature/X
redundantes, eso es lo que git fetch --prune
hace - pero por alguna razón, no te permite eliminar automáticamente tu propia feature/X
... A pesar de que su feature/X
todavía contiene la información de seguimiento huérfana, tiene la información para identificar las ramas de seguimiento anteriores que se han fusionado por completo. (Después de todo, puede brindarle la información que le permite realizar la operación usted mismo).
Parece que la solución está aquí - https://.com/a/1072178/133986
En resumen, git remote prune
hace la magia.
Puede ser útil para algunos, una simple línea para borrar todas las sucursales locales, excepto dominar y desarrollar
git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
Se me ocurrió este guión de bash. Siempre se mantienen las ramas en develop
, qa
, master
.
git-clear() {
git pull -a > /dev/null
local branches=$(git branch --merged | grep -v ''develop'' | grep -v ''master'' | grep -v ''qa'' | sed ''s/^/s*//'')
branches=(${branches//;/ })
if [ -z $branches ]; then
echo ''No branches to delete...''
return;
fi
echo $branches
echo ''Do you want to delete these merged branches? (y/n)''
read yn
case $yn in
[^Yy]* ) return;;
esac
echo ''Deleting...''
git remote prune origin
echo $branches | xargs git branch -d
git branch -vv
}
Sin embargo, otra respuesta para la pila, se basa en https://.com/a/48411554/2858703 (lo que me gusta porque parece eliminar cualquier ambigüedad acerca de a dónde se gone]
coincidirá en la salida de la git branch
) pero añadiendo un * nix doblado:
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" /
| sed ''s,^refs/heads/,,;/^$/d'' /
| xargs git branch -D
Tengo esto envuelto en un script de git-gone
en mi camino:
#!/usr/bin/env bash
action() {
${DELETE} && xargs git branch -D || cat
}
get_gone() {
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" /
| sed ''s,^refs/heads/,,;/^$/d''
}
main() {
DELETE=false
while [ $# -gt 0 ] ; do
case "${1}" in
(-[dD] | --delete) DELETE=true ;;
esac
shift
done
get_gone | action
}
main "${@}"
Nota: la opción --format parece ser bastante nueva; Necesitaba actualizar git de 2.10.algo a 2.16.3 para obtenerlo.
Uso este método para tener más control.
git branch -D $(git branch | grep -v "master" | grep -v "develop")
Esto es quitar cualquier rama no nombrada: master
o develop
.
Utilizo un método corto para hacer el truco, te recomiendo que hagas lo mismo, ya que podría ahorrar algunas horas y darte más visibilidad.
Simplemente agregue el siguiente fragmento de código en su .bashrc (.bashprofile en macos).
git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "/bmaster|preprod|dmz/b" | xargs -n 1 git branch -d ;};
- Trae todos los controles remotos
- Obtener solo ramas fusionadas de git
- Eliminar de esta lista las ramas "protegidas / importantes"
- Eliminar el resto (por ejemplo, ramas limpias y fusionadas)
Tendrá que editar el greg regex para que se ajuste a sus necesidades (aquí, evita que se eliminen master, preprod y dmz)
git remote prune origin
ciruelas pasas de seguimiento no en el control remoto
git branch --merged
enumera las ramas que se han fusionado en la rama actual.
xargs git branch -d
elimina las ramas enumeradas en la entrada estándar.
Tenga cuidado al eliminar las ramas enumeradas por la git branch --merged
. La lista podría incluir master
u otras ramas que preferiría no eliminar.
Para darse la oportunidad de editar la lista antes de eliminar sucursales, puede hacer lo siguiente en una línea:
git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
git fetch -p
Esto eliminará todas las ramas que no se rastrean de forma remota.
grep gone <(git branch -v) | cut -d '' '' -f 3 | xargs git branch -d
El comando anterior se puede usar para buscar ramas que se combinan y eliminan en remoto y elimina la rama local que ya no está disponible en remoto