Limpiar viejas ramas remotas de git
Trabajo desde dos computadoras diferentes (A y B) y almaceno un control remoto git común en el directorio de Dropbox.
Digamos que tengo dos ramas, master y devel. Ambos están rastreando a sus contrapartes remotas origen/maestro y origen/desarrollo.
Ahora, mientras estoy en la computadora A, elimino el desarrollo de la rama, en local y remoto.
git push origin :heads/devel
git branch -d devel
Al ejecutarlo git branch -a
en la computadora A, obtengo la siguiente lista de sucursales.
- maestro
- origen/CABEZA
- origen/maestro
Al ejecutar git fetch
en la computadora B, puedo eliminar la rama de desarrollo local con git branch -d devel
, pero no puedo eliminar la rama de desarrollo remoto.
git push origin :heads/devel
devuelve los siguientes mensajes de error.
error: no se puede enviar a un destino no calificado: heads/proxy3d
La especificación de referencia de destino no coincide con una referencia existente en el control remoto ni comienza con refs/, y no podemos adivinar un prefijo basado en la referencia de origen.
fatal: el extremo remoto se colgó inesperadamente
git branch -a
todavía enumera origen/desarrollo en las ramas remotas.
¿Cómo puedo limpiar las ramas remotas de la computadora B?
Primero, ¿cuál es el resultado de git branch -a
en la máquina B?
heads/devel
En segundo lugar, ya lo ha eliminado origin
, por eso no puede eliminarlo de la máquina B.
Intentar
git branch -r -d origin/devel
o
git remote prune origin
o
git fetch origin --prune
y siéntase libre de agregarlo --dry-run
al final de su git
declaración para ver el resultado de ejecutarlo sin ejecutarlo realmente.
Documentos para git remote prune
y git branch
.
Considere ejecutar:
git fetch --prune
De forma regular en cada repositorio para eliminar las sucursales locales que han estado rastreando una sucursal remota que se elimina (ya no existe en el repositorio GIT remoto).
Esto se puede simplificar aún más mediante
git config remote.origin.prune true
Esta es una per-repo
configuración que hará que cualquier futuro se podegit fetch or git pull
automáticamente .
Para configurar esto para su usuario, también puede editar el .gitconfig global y agregar
[fetch]
prune = true
Sin embargo, se recomienda que esto se haga usando el siguiente comando:
git config --global fetch.prune true
o aplicarlo en todo el sistema (no solo para el usuario)
git config --system fetch.prune true
Tendré que agregar una respuesta aquí, porque las otras respuestas no cubren mi caso o son innecesariamente complicadas. Utilizo github con otros desarrolladores y solo quiero que todas las sucursales locales cuyos controles remotos fueron (posiblemente fusionados y) eliminados de un PR de github se eliminen de una sola vez de mi máquina. No, cosas como git branch -r --merged
no cubren las sucursales que no se fusionaron localmente, o las que no se fusionaron en absoluto (abandonadas), etc., por lo que se necesita una solución diferente.
De todos modos, el primer paso lo obtuve de otras respuestas:
git fetch --prune
Parecía que un ensayo git remote prune origin
haría lo mismo en mi caso, así que elegí la versión más corta para mantenerlo simple.
Ahora, se git branch -v
deben marcar las ramas cuyos controles remotos se eliminan como [gone]
. Por lo tanto, todo lo que necesito hacer es:
git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}
Tan simple como eso, elimina todo lo que quiero para el escenario anterior.
La xargs
sintaxis menos común es que también funcione en Mac y BSD además de Linux. Cuidado, este comando no es un ensayo, por lo que forzará la eliminación de todas las ramas marcadas como [gone]
. Obviamente, al ser git nada desaparece para siempre, si ves ramas eliminadas que recuerdas que querías conservar, siempre puedes recuperarlas (el comando anterior habrá enumerado su hash al eliminarlas, por lo que un simple archivo git checkout -b <branch> <hash>
.
Editar: simplemente agregue este alias a su .bashrc/.bash_profile, los dos comandos se convirtieron en uno y actualicé el segundo para que funcione en todos los shells:
alias old_branch_delete='git fetch -p && git branch -vv | awk "/: gone]/{print \$1}" | xargs git branch -D'
Este comando eliminará mediante una "ejecución de prueba" todas las origin
ramas remotas ( ) fusionadas, excepto master
. Puede cambiar eso o agregar ramas adicionales después de master:grep -v for-example-your-branch-here |
git branch -r --merged |
grep origin |
grep -v '>' |
grep -v master |
xargs -L1 |
awk '{sub(/origin\//,"");print}'|
xargs git push origin --delete --dry-run
Si se ve bien, retire el --dry-run
. Además, es posible que desees probar esto primero en un tenedor.
Aquí hay un script bash que puede hacerlo por usted. Es una versión modificada del script http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Mi modificación le permite admitir diferentes ubicaciones remotas.
#!/bin/bash
current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"
git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
echo "No existing branches have been merged into $current_branch."
else
echo "This will remove the following branches:"
if [ -n "$remote_branches" ]; then
echo "$remote_branches"
fi
if [ -n "$local_branches" ]; then
echo "$local_branches"
fi
read -p "Continue? (y/n): " -n 1 choice
echo
if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
git push $remote $branches
done
# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
else
echo "No branches removed."
fi
fi