Eliminar todas las ramas locales de git

323

Sigo un proceso de desarrollo en el que creo una nueva sucursal local para cada nueva característica o tarjeta de historia. Cuando termino fusiono la rama en maestra y luego empujo.

Lo que tiende a suceder con el tiempo debido a una combinación de pereza u olvido es que termino con una gran lista de sucursales locales, algunas de las cuales (como picos) pueden no haberse fusionado.

Sé cómo enumerar todas mis ramas locales y sé cómo eliminar una sola rama, pero me preguntaba si había un comando git que me permitiera eliminar todas mis ramas locales.

A continuación se muestra la salida del git branch --mergedcomando.

user@machine:~/projects/application[master]$ git branch --merged
  STORY-123-Short-Description
  STORY-456-Another-Description
  STORY-789-Blah-Blah
* master

Todos los intentos de eliminar ramas enumeradas con grep -v \*(según las respuestas a continuación) resultan en errores:

error: branch 'STORY-123-Short-Description' not found.
error: branch 'STORY-456-Another-Description' not found.
error: branch 'STORY-789-Blah-Blah' not found.

Estoy usando:
git 1.7.4.1
ubuntu 10.04
GNU bash, versión 4.1.5 (1) -release
GNU grep 2.5.4

Boca
fuente
77
¡Te ruego que aceptes la respuesta de @Andrew!
Robert Siemer
@GiulioCaccin La pregunta también se refiere a ramas que pueden no haberse fusionado y he actualizado la pregunta para reflejar explícitamente esto.
Louth el
Vea este git-delete-all-local-branch-except-some
ilusionista el

Respuestas:

384

El subcomando 'git branch -d' puede eliminar más de una rama. Entonces, simplificando la respuesta de @ sblom pero agregando un xargs crítico:

git branch -D `git branch --merged | grep -v \* | xargs`

o, simplificado aún más a:

git branch --merged | grep -v \* | xargs git branch -D 

Es importante destacar que, como señaló @AndrewC, git branchse desaconseja el uso de secuencias de comandos. Para evitarlo usa algo como:

git for-each-ref --format '%(refname:short)' refs/heads | grep -v master | xargs git branch -D

¡Precaución garantizada en eliminaciones!

$ mkdir br
$ cd br; git init
Initialized empty Git repository in /Users/ebg/test/br/.git/
$ touch README; git add README; git commit -m 'First commit'
[master (root-commit) 1d738b5] First commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git branch Story-123-a
$ git branch Story-123-b
$ git branch Story-123-c
$ git branch --merged
  Story-123-a
  Story-123-b
  Story-123-c
* master
$ git branch --merged | grep -v \* | xargs
Story-123-a Story-123-b Story-123-c
$ git branch --merged | grep -v \* | xargs git branch -D
Deleted branch Story-123-a (was 1d738b5).
Deleted branch Story-123-b (was 1d738b5).
Deleted branch Story-123-c (was 1d738b5).
GoZoner
fuente
Este comando aún informa los mismos errores que se mencionan en los comentarios para la respuesta a continuación. error:branch 'STORY-123-Short-Description' not found.para cada una de las ramas enumeradas.
Louth
1
Funciona para mi; ver arriba con detalles agregados.
GoZoner
1
Entonces, ¿el uso de git 1.7.10 resolvió su problema o prefiere trabajar directamente en el repositorio .git?
GoZoner
1
Si obtiene un error:branch 'STORY-123-Short-Description' not found.error, esto probablemente se deba a la configuración de color de git. Esto funcionó para mí (tenga en cuenta la --no-coloropción):git branch --no-color --merged | grep -v \* | xargs git branch -D
marcok
3
La única respuesta en SO que he encontrado funciona. ¡Gracias!
Kevin Suttle
140

Encontré una mejor manera en un comentario sobre este problema en github :

git branch --merged master --no-color | grep -v master | grep -v stable | xargs git branch -d

editar: se agregó la opción sin color y se excluyó la rama estable (agregue otras ramas según sea necesario en su caso)

mBardos
fuente
2
Finalmente, la solución que he estado necesitando
Code Whisperer el
1
He intentado esto, pero sigo obteniendo error: branch 'my-branch-name' not found.para cada rama. Usando git versión 1.8.3.4 (Apple Git-47). ¿Alguna idea de por qué?
wheresrhys
pruebe 'git branch - maestro fusionado | grep -v master | xargs echo 'para depurar qué es exactamente lo que está tratando de eliminar? no tengo mejores ideas ...
mBardos
2
Entonces. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Павел Тявин
1
Aprendí el uso de xargs junto con esto. Gracias
Volem
105

git branchNo se recomienda analizar la salida de , y no es una buena respuesta para futuros lectores en Stack Overflow.

  1. git branches lo que se conoce como un comando de porcelana. Los comandos de porcelana no están diseñados para analizarse a máquina y la salida puede cambiar entre diferentes versiones de Git.
  2. Hay opciones de configuración del usuario que cambian la salida de git branchuna manera que dificulta el análisis (por ejemplo, la coloración). Si un usuario lo ha configurado color.branch, obtendrá códigos de control en la salida, esto lo conducirá error: branch 'foo' not found.si intenta canalizarlo a otro comando. Puede omitir esto con el --no-colorindicador git branch, pero quién sabe qué otras configuraciones de usuario pueden romper las cosas.
  3. git branch puede hacer otras cosas que son molestas de analizar, como poner un asterisco al lado de la rama actualmente desprotegida

El mantenedor de git tiene esto que decir sobre las secuencias de comandos alrededor de la git branchsalida

Para saber cuál es la rama actual, los usuarios casuales / descuidados pueden haber escrito alrededor de git branch, lo cual está mal. Desalentamos activamente el uso de cualquier comando de Porcelain, incluida git branch, en los scripts, porque el resultado del comando está sujeto a cambios para ayudar al uso humano.

Las respuestas que sugieren editar archivos manualmente en el .gitdirectorio (como .git / refs / heads) son igualmente problemáticas (las referencias pueden estar en .git / package-refs en su lugar, o Git puede cambiar su diseño interno en el futuro).

Git proporciona el for-each-refcomando para recuperar una lista de ramas.

Git 2.7.X presentará la --mergedopción para que pueda hacer algo como lo siguiente para encontrar y eliminar todas las ramas fusionadas enHEAD

for mergedBranch in $(git for-each-ref --format '%(refname:short)' --merged HEAD refs/heads/)
do
    git branch -d ${mergedBranch}
done

Git 2.6.X y anteriores, deberá enumerar todas las sucursales locales y luego probarlas individualmente para ver si se han fusionado (lo que será significativamente más lento y un poco más complicado).

for branch in $(git for-each-ref --format '%(refname:short)' refs/heads/)
do
    git merge-base --is-ancestor ${branch} HEAD && git branch -d ${branch}
done
Andrew C
fuente
git branch --no-color 2>/dev/null?
nobar
55
Es una mejora segura. Siempre tendrá el problema de necesitar filtrar el *, y hace cosas divertidas si alguien lo ejecuta desde la cabeza separada. Sin embargo, el principal problema git branches un comando de porcelana, y no hay garantía de que el resultado no cambie en alguna versión futura de git.
Andrew C
Gracias @AndrewC: ¡esta es la respuesta a la pregunta sobre los misteriosos errores de "rama no encontrada" y proporciona una solución de trabajo con un comando más apropiado! 👍
Jason
2
¿Cómo se identifican los comandos GIT 'Porcelain' y 'non-Porcelain'?
GoZoner
1
¿Probablemente sería una mejora útil para excluir 'dev' y 'master' por defecto?
PandaWood
66

La forma más sencilla de eliminar todas las ramas pero manteniendo otras como "desarrollar" y "maestro" es la siguiente:

git branch | grep -v "develop" | grep -v "master" | xargs git branch -D

muy útil !

geoom
fuente
8
Ha resucitado un hilo antiguo y ha publicado una respuesta prácticamente idéntica a una existente, que tiene errores y le faltan los cambios de seguridad que tenía. Esta no es una buena respuesta.
Andrew C
66
Esta respuesta es clara en la salida de tubería desde git branch, modificándola y pasando a git branch -D. No hay necesidad de ser malo.
Pam
Esta solución funcionó para mí. Se eliminaron todas las sucursales locales.
Prad
1
Esto no eliminará ninguna rama que contenga desarrollo de palabras o master como 'desarrollo_feature' o 'master_feature'.
django
ESTA ES LA RESPUESTA QUE BUSCA 👆🏻
Konrad G
62

Para eliminar todas las ramas, excepto la que actualmente ha extraído:

for b in `git branch --merged | grep -v \*`; do git branch -D $b; done

Recomendaría cambiar git branch -D $ba una echo $blas primeras veces para asegurarse de que elimine las ramas que desea.

sblom
fuente
1
con este comando que obtengo error:branch 'a_branch_name' not found.puedo ver lo que estás tratando de hacer y he estado jugando con el comando, pero por alguna razón a git no parece gustarle los nombres de las ramas suministrados ...
Louth
hmmm Para ayudar a solucionar, sería útil para ver algunos ejemplo de salidagit branch --merged
sblom
mis nombres de sucursal son del formatoSTORY-123-Short-Description
Louth
y cuando corres git branch --merged, obtienes una lista con uno de esos en cada línea?
sblom
1
¿dice literalmente error:branch 'a_branch_name' not found.? ¿O se queja de uno de los nombres de rama de su git branchsalida anterior?
sblom
52

El siguiente comando eliminará todas las ramas locales excepto la rama maestra.

git branch | grep -v "master" | xargs git branch -D

El comando anterior

  1. enumera todas las ramas
  2. De la lista, ignore la rama maestra y tome el resto de las ramas
  3. eliminar la rama
Cazador
fuente
44
Lo usaría git branch | grep -v "master" | xargs git branch -dprimero para no eliminar ramas no fusionadas, solo para estar seguro. Pero buena respuesta!
Jonas Lomholdt
3
Aquí hay una versión de ,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
PowerShell
1
@baklazan, esto solo funcionaría en la línea de comandos de Windows 10 si tiene algunas herramientas instaladas. Probablemente tienes MINGW o alguna otra cosa y no lo sabes.
KthProg
42

Solo una nota, me actualizaría a git 1.7.10. Es posible que obtenga respuestas aquí que no funcionarán en su versión. Supongo que tendrías que anteponer el nombre de la rama refs/heads/.

PRECAUCIÓN, continúe con lo siguiente solo si realizó una copia de su carpeta de trabajo y directorio .git.

A veces simplemente continúo y borro las ramas de las que no quiero directamente .git/refs/heads. Todas estas ramas son archivos de texto que contienen los 40 caracteres sha-1 del commit al que apuntan. Tendrá información extraña en su .git/configsi tuviera configurado un seguimiento específico para cualquiera de ellos. También puede eliminar esas entradas manualmente.

Adam Dymitruk
fuente
Por fin una opción simple y pragmática. Me gusta: D
Melvyn
2
Esto no funcionará si ha empaquetado referencias, o incluso si ha clonado desde un servidor remoto a veces (lo que le proporcionará archivos empaquetados). Si sus referencias están empaquetadas, las referencias no se almacenarán en .git / refs / heads, sino que se almacenarán en un archivo llamado "paquete-referencias". Ver git-scm.com/docs/git-pack-refs .
Alexander Bird
1
Parece una mala idea eliminar la rama que ha verificado en este momento
Moberg
@Moberg Solo revisa un commit de antemano, y tu HEAD separada flotará bien.
RomainValeri
34

Pruebe el siguiente comando de shell:

git branch | grep -v "master" | xargs git branch -D

Explicación:

  • 🛒 Obtenga todas las sucursales a través de git branch | grep -v "master" comando
  • 👇 Seleccione cada rama con xargscomando
  • 💦 Eliminar rama con xargs git branch -D
Pravin
fuente
3
Aunque esta puede ser una respuesta correcta. Una línea de código no es muy útil sin una explicación de qué y cómo resuelve la pregunta original. Proporcione detalles a su respuesta.
RyanNerd
28

Para eliminar todas las sucursales locales en Linux, excepto la que está en

// hard delete

git branch -D $(git branch)
Ashish Yadav
fuente
2
Este se siente más seguro que entrar en .git y eliminar cosas.
nelsontruran
25

Me resultó más fácil usar solo el editor de texto y el shell.

  1. Escriba git checkout <TAB>en concha. Mostrará todas las sucursales locales.
  2. Cópielos en un editor de texto, elimine los que necesita conservar.
  3. Reemplace los saltos de línea con espacios. (En SublimeText es súper fácil).
  4. Concha abierta, tipo git branch -D <PASTE THE BRANCHES NAMES HERE>.

Eso es.

culebrón
fuente
No creo que puedas quitar la rama en la que estás parado.
Dong Thang
@ Dong Hay un * al lado de esa rama, ¡así que simplemente elimínalo de la lista copiada!
Melanie
12

Tuve una situación similar y recientemente encontré útil el siguiente comando.

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep>/) printf "%s", $0 }'`

Si desea mantener varias ramas, entonces

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep1>|<Branch_You_Want_to_Keep2>/) printf "%s", $0 }'`

Espero que esto ayude a alguien.

4u.Ans
fuente
1
Agradable, pero necesitaba backticks para que funcionara. En git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` realidad, creo que los tenía originalmente, pero se perdieron en el formato SO.
tassinari
10

Desde la línea de comandos de Windows, elimine todo excepto la rama actual desprotegida usando:

for /f "tokens=*" %f in ('git branch ^| find /v "*"') do git branch -D %f
kiewic
fuente
7

Si no necesita pasar por Git, también puede eliminar los encabezados en .git / refs / heads de forma manual o programática. Lo siguiente debería funcionar con ajustes mínimos en Bash:

shopt -s extglob
rm -rf .git/refs/heads/!(master)

Esto eliminará todas las sucursales locales, excepto su rama maestra. Dado que sus ramas ascendentes se almacenan en .git / refs / remotes , permanecerán intactas.

Si no está utilizando Bash, o desea recurrir muchos repositorios Git a la vez, puede hacer algo similar con GNU find:

find . \
    -path remotes -path logs -prune -o \
    -wholename \*.git/refs/heads/\* \! -name master -print0 |
xargs -0 rm -rf

La solución de búsqueda es probablemente más portátil, pero las rutas de poda y los nombres de archivo son complicados y potencialmente más propensos a errores.

Todd A. Jacobs
fuente
Frio. Visual delete :)
sandalone
5

Ninguna de las respuestas satisfizo completamente mis necesidades, así que aquí vamos:

git branch --merged | grep -E "(feature|bugfix|hotfix)/" | xargs git branch -D && git remote prune origin

Esto eliminará todas las sucursales locales que se fusionen y comiencen con feature/, bugfix/o hotfix/. Luego el control remoto aguas arribaorigin (es posible que deba ingresar una contraseña).

Funciona en Git 1.9.5.

usuario4401817
fuente
5

Basado en una combinación de una serie de respuestas aquí: si desea mantener todas las ramas que existen en forma remota pero eliminar el resto , el siguiente trazador de líneas hará el truco:

git for-each-ref --format '%(refname:short)' refs/heads | grep -Ev `git ls-remote --quiet --heads origin | awk '{print substr($2, 12)}'| paste -sd "|" -` | xargs git branch -D
Srishan Bhattarai
fuente
3

Aunque esta no es una solución de línea de comando, me sorprende que la GUI de Git aún no se haya sugerido.

Utilizo la línea de comando el 99% del tiempo, pero en este caso es demasiado lento (de ahí la pregunta original), o no sabes lo que estás a punto de eliminar cuando recurres a una manipulación de shell larga pero inteligente.

La interfaz de usuario resuelve este problema, ya que puede marcar rápidamente las ramas que desea eliminar y recordar las que desea conservar, sin tener que escribir un comando para cada rama.

Desde la interfaz de usuario, vaya a Rama -> Eliminar y Ctrl + Haga clic en las ramas que desea eliminar para que se resalten. Si desea asegurarse de que se fusionen en una rama (como dev), en Eliminar solo si se fusionó en establecer la rama local en dev. De lo contrario, configúrelo en Siempre para ignorar esta comprobación.

GitUI: eliminar sucursales locales

Dane Bouchie
fuente
1

Para powershell, esto funcionará:

git branch --format '%(refname:lstrip=2)' --merged `
    | Where-Object { $_ -ne 'master' } `
    | ForEach-Object { git branch -d $_ }
Lucas
fuente
0

El siguiente script elimina ramas. Úselo y modifíquelo bajo su propio riesgo, etc. etc.

Basado en las otras respuestas en esta pregunta, terminé escribiendo un script de bash rápido para mí. Lo llamé "gitbd" (git branch -D) pero si lo usas, puedes cambiarle el nombre a lo que quieras.

gitbd() {
if [ $# -le 1 ]
  then
    local branches_to_delete=`git for-each-ref --format '%(refname:short)' refs/heads/ | grep "$1"`
    printf "Matching branches:\n\n$branches_to_delete\n\nDelete? [Y/n] "
    read -n 1 -r # Immediately continue after getting 1 keypress
    echo # Move to a new line
    if [[ ! $REPLY == 'N' && ! $REPLY == 'n' ]]
      then
        echo $branches_to_delete | xargs git branch -D
    fi
else
  echo "This command takes one arg (match pattern) or no args (match all)"
fi
}

Ofrecerá eliminar cualquier rama que coincida con un argumento de patrón, si se pasa, o todas las ramas locales cuando se llame sin argumentos. También te dará un paso de confirmación, ya que, ya sabes, estamos eliminando cosas, así que eso es bueno.

Es un poco tonto: si no hay ramas que coincidan con el patrón, no se dará cuenta.

Un ejemplo de salida de ejecución:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 
dherman
fuente
0

Escribí un script de shell para eliminar todas las ramas locales excepto develop

branches=$(git branch | tr -d " *")
output=""
for branch in $branches 
do
  if [[ $branch != "develop" ]]; then
    output="$output $branch"
  fi
done
git branch -d $output
nhp
fuente
0

Las respuestas anteriores funcionan bien. Aquí hay otro enfoque cuando tenemos muchas ramas en el repositorio local y tenemos que eliminar muchas ramas, excepto algunas que se encuentran en la máquina local.

primero git branch se enumerarán todas las sucursales locales.

Para transponer la columna de nombres de rama en una sola fila en el archivo ejecutando un comando unix
git branch > sample.txt
Esto lo guardará en el archivo sample.txt . Y correr
awk 'BEGIN { ORS = " " } { print }' sample.txt
comando en shell. Esto transformará la columna en fila y copiará la lista de nombres de rama en una sola fila.

Y luego corre
git branch -D branch_name(s).
Esto eliminará todas las ramas enumeradas presentes en local

Deepak G
fuente
0

La forma más pragmática: asegúrese de no tener un trabajo no comprometido master, confirme / envíe si es necesario, clone una copia nueva del repositorio y elimine el antiguo.

Patrick Sanan
fuente
0

Para este propósito, puedes usar git-extras

$ git delete-merged-branches
Deleted feature/themes (was c029ab3).
Deleted feature/live_preview (was a81b002).
Deleted feature/dashboard (was 923befa).
Andriy Orehov
fuente
0

No tengo grep u otro Unix en mi caja, pero esto funcionó desde el terminal de VSCode:

git branch -d $(git branch).trim()

Utilizo la minúscula d para que no elimine las ramas no fusionadas.

También estaba en master cuando lo hice, por lo * masterque no existe, por lo que no intentó eliminar master.

Ron Newcomb
fuente
Confirmado: si no masterestá activado, este comando BORRARÁmaster .
Brett Rowberry
-1

Asegúrate de hacer esto primero

git fetch

Una vez que tenga toda la información de las sucursales remotas, use el siguiente comando para eliminar cada una de las ramas excepto la maestra

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
Meng
fuente