Supprimer toutes les branches git locales


325

Je suis un processus de développement où je crée une nouvelle branche locale pour chaque nouvelle fonctionnalité ou carte d'histoire. Une fois terminé, je fusionne la branche en maître, puis je pousse.

Ce qui a tendance à se produire au fil du temps en raison d'une combinaison de paresse ou d'oubli, c'est que je me retrouve avec une grande liste de succursales locales, dont certaines (comme les pointes) peuvent ne pas avoir été fusionnées.

Je sais comment lister toutes mes branches locales et je sais comment supprimer une seule branche mais je me demandais s'il y avait une commande git qui me permet de supprimer toutes mes branches locales?

Voici la sortie de la git branch --mergedcommande.

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

Toutes les tentatives de suppression de branches répertoriées avec grep -v \*(selon les réponses ci-dessous) entraînent des erreurs:

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

J'utilise:
git 1.7.4.1
ubuntu 10.04
GNU bash, version 4.1.5 (1) -release
GNU grep 2.5.4


7
Je vous prie d'accepter la réponse de @Andrew!
Robert Siemer


@GiulioCaccin La question concerne également les branches qui n'ont peut-être pas été fusionnées et j'ai mis à jour la question pour refléter explicitement cela.
Louth

Réponses:


386

La sous-commande 'git branch -d' peut supprimer plusieurs branches. Donc, simplifiant la réponse de @ sblom mais ajoutant un xargs critique:

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

ou encore simplifié pour:

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

Surtout, comme l'a noté @AndrewC, l'utilisation git branchde scripts est déconseillée. Pour l'éviter, utilisez quelque chose comme:

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

Attention aux suppressions!

$ 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).

Cette commande signale toujours les mêmes erreurs que celles mentionnées dans les commentaires pour la réponse ci-dessous. error:branch 'STORY-123-Short-Description' not found.pour chacune des branches répertoriées.
Louth

1
Travaille pour moi; voir ci-dessus avec des détails ajoutés.
GoZoner

1
Alors, l'utilisation de git 1.7.10 a-t-elle résolu votre problème ou préférez-vous travailler directement dans le référentiel .git?
GoZoner

1
Si vous obtenez une error:branch 'STORY-123-Short-Description' not found.erreur, cela est probablement dû aux paramètres de couleur git. Cela a fonctionné pour moi (notez l' --no-coloroption):git branch --no-color --merged | grep -v \* | xargs git branch -D
marcok

3
La seule réponse sur SO que j'ai trouvé qui fonctionne. Je vous remercie!
Kevin Suttle

140

J'ai trouvé un moyen plus agréable dans un commentaire sur ce problème sur github :

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

modifier: ajout d'une option sans couleur et exclusion de la branche stable (ajoutez d'autres branches si nécessaire dans votre cas)


2
Enfin, la solution dont j'avais besoin
Code Whisperer

1
J'ai essayé cela, mais continuez à obtenir error: branch 'my-branch-name' not found.pour chaque branche. Utilisation de git version 1.8.3.4 (Apple Git-47). Une idée pourquoi?
où le

try 'git branch --merged master | grep -v master | xargs echo 'pour déboguer ce qu'il essaie exactement de supprimer? n'ont pas de meilleures idées ...
mBardos

2
Alors. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Павел Тявин

1
Apprentissage de l'utilisation des xargs avec cela. Merci
Volem

105

L'analyse de la sortie de git branchn'est pas recommandée et n'est pas une bonne réponse pour les futurs lecteurs sur Stack Overflow.

  1. git branchest ce qu'on appelle une commande de porcelaine. Les commandes de porcelaine ne sont pas conçues pour être analysées en machine et la sortie peut changer entre les différentes versions de Git.
  2. Il existe des options de configuration utilisateur qui modifient la sortie d' git branchune manière qui la rend difficile à analyser (par exemple, la colorisation). Si un utilisateur a défini, color.branchvous obtiendrez des codes de contrôle dans la sortie, cela entraînera error: branch 'foo' not found.si vous essayez de le diriger vers une autre commande. Vous pouvez contourner cela avec l' --no-colorindicateur to git branch, mais qui sait quelles autres configurations utilisateur pourraient casser les choses.
  3. git branch peut faire d'autres choses ennuyeuses à analyser, comme mettre un astérisque à côté de la branche actuellement extraite

Le responsable de git a ceci à dire sur les scripts autour de la git branchsortie

Pour découvrir ce qu'est la branche actuelle, les utilisateurs occasionnels / imprudents peuvent avoir écrit un script autour de la branche git, ce qui est faux. Nous déconseillons activement l'utilisation de toute commande Porcelain, y compris la branche git, dans les scripts, car la sortie de la commande est susceptible d'être modifiée pour aider le cas d'utilisation de la consommation humaine.

Les réponses qui suggèrent de modifier manuellement les fichiers dans le .gitrépertoire (comme .git / refs / heads) sont également problématiques (les références peuvent être dans .git / pack-refs à la place, ou Git peut changer leur disposition interne à l'avenir).

Git fournit la for-each-refcommande pour récupérer une liste de branches.

Git 2.7.X introduira l' --mergedoption pour que vous puissiez faire quelque chose comme ci-dessous pour trouver et supprimer toutes les branches fusionnées dansHEAD

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

Git 2.6.X et les versions antérieures, vous devrez répertorier toutes les branches locales, puis les tester individuellement pour voir si elles ont été fusionnées (ce qui sera beaucoup plus lent et légèrement plus compliqué).

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

git branch --no-color 2>/dev/null?
nobar

5
C'est une amélioration à coup sûr. Vous aurez toujours le problème d'avoir à filtrer les *, et cela fait des choses amusantes si quelqu'un l'exécute à partir de la tête détachée. Le problème principal est cependant git branchune commande porcelaine, et il n'y a aucune garantie que la sortie ne changera pas dans une future version de git.
Andrew C

Merci @AndrewC - c'est à la fois une réponse à la question sur les mystérieuses erreurs "branche non trouvée" et une solution de travail en utilisant une commande plus appropriée! 👍
Jason

2
Comment les commandes GIT «Porcelaine» et «non-Porcelaine» sont-elles identifiées?
GoZoner

1
Serait probablement une amélioration utile pour exclure «dev» et «master» par défaut?
PandaWood

66

La manière la plus simple de supprimer toutes les branches mais de conserver d'autres comme "develop" et "master" est la suivante:

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

très utile !


8
Vous avez ressuscité un fil séculaire et publié une réponse pratiquement identique à un fil existant, c'est-à-dire bogué et il manque les changements de sécurité qu'il avait. Ce n'est pas une bonne réponse.
Andrew C

6
Cette réponse est claire dans la sortie de la tuyauterie de la branche git, en la modifiant et en la passant à la branche git -D. Pas besoin d'être méchant.
Pam

Cette solution a fonctionné pour moi. Supprimé toutes les succursales locales.
Prad

1
Cela ne supprimera aucune branche contenant le mot develop ou master comme 'develop_feature' ou 'master_feature'.
django

C'EST LA RÉPONSE QUE JE RECHERCHAIS 👆🏻
Konrad G

62

Pour supprimer toutes les branches sauf celle que vous avez actuellement extraite:

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

Je recommanderais de passer git branch -D $bà an echo $bles premières fois pour vous assurer qu'il supprime les branches que vous souhaitez.


1
avec cette commande, je reçois, error:branch 'a_branch_name' not found.je peux voir ce que vous essayez de faire et j'ai joué avec la commande, mais pour une raison quelconque, git ne semble pas aimer les noms de branche fournis ...
Louth

hmmm. pour aider au dépannage, il serait utile de voir un exemple de sortie degit branch --merged
sblom

mes noms de succursales sont au formatSTORY-123-Short-Description
Louth

et quand vous courez git branch --merged, vous obtenez une liste avec un de ceux sur chaque ligne?
sblom

1
dit-il littéralement error:branch 'a_branch_name' not found.? Ou se plaint-il d'un des noms de branche de votre git branchsortie ci-dessus?
sblom

52

La commande ci-dessous supprimera toutes les branches locales à l'exception de la branche principale.

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

La commande ci-dessus

  1. lister toutes les branches
  2. Dans la liste, ignorez la branche principale et prenez le reste des branches
  3. supprimer la branche

4
J'utiliserais d' git branch | grep -v "master" | xargs git branch -dabord pour ne pas supprimer les branches non fusionnées, juste pour être sûr. Mais belle réponse!
Jonas Lomholdt

3
Voici une version ,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
PowerShell

1
@baklazan, cela ne fonctionnerait qu'en ligne de commande Windows 10 si certains outils étaient installés. Vous avez probablement MINGW ou quelque chose de ce genre et vous ne le savez pas.
KthProg

42

Juste une note, je voudrais passer à git 1.7.10. Vous obtiendrez peut-être des réponses ici qui ne fonctionneront pas sur votre version. Je suppose que vous devrez préfixer le nom de la branche avec refs/heads/.

ATTENTION, procédez comme suit uniquement si vous avez fait une copie de votre dossier de travail et de votre répertoire .git.

Il m'arrive parfois d'aller de l'avant et de supprimer les branches dont je ne veux pas directement .git/refs/heads. Toutes ces branches sont des fichiers texte qui contiennent les 40 caractères sha-1 du commit vers lequel ils pointent. Vous aurez des informations superflues dans votre .git/configsi vous aviez un suivi spécifique configuré pour l'un d'eux. Vous pouvez également supprimer ces entrées manuellement.


Enfin une option simple et pragmatique. J'aime ça: D
Melvyn

2
Cela ne fonctionnera pas si vous avez compressé des références, ou même si vous avez parfois cloné à partir d'un serveur distant (qui vous fournira des fichiers compressés). Si vos références sont emballées, les références ne seront pas stockées dans .git / refs / heads, elles seront stockées dans un fichier appelé "pack-refs". Voir git-scm.com/docs/git-pack-refs .
Alexander Bird

1
Il semble que ce soit une mauvaise idée de supprimer la branche que vous avez consultée en ce moment
Moberg

@Moberg Vérifiez simplement un commit au préalable et votre HEAD détaché flottera très bien.
RomainValeri

34

Essayez la commande shell suivante:

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

Explication:

  • 🛒 Obtenez toutes les branches via la git branch | grep -v "master"commande
  • 👇 Sélectionnez chaque branche avec la xargscommande
  • 💦 Supprimer la branche avec xargs git branch -D

3
Bien que cela puisse être une bonne réponse. Une ligne de code n'est pas très utile sans une explication de quoi et comment cela résout la question d'origine. Veuillez fournir des détails à votre réponse.
RyanNerd

28

Pour supprimer toutes les succursales locales sous Linux, sauf celle sur laquelle vous vous trouvez

// hard delete

git branch -D $(git branch)

2
Celui-ci se sent plus en sécurité que d'entrer dans .git et de supprimer des éléments.
nelsontruran

25

J'ai trouvé plus facile d'utiliser simplement l'éditeur de texte et le shell.

  1. Tapez git checkout <TAB>dans la coquille. Affiche toutes les succursales locales.
  2. Copiez-les dans un éditeur de texte, supprimez ceux que vous devez conserver.
  3. Remplacez les sauts de ligne par des espaces. (Dans SublimeText, c'est super facile.)
  4. Ouvrez le shell, tapez git branch -D <PASTE THE BRANCHES NAMES HERE>.

C'est tout.


Je ne pense pas que vous puissiez supprimer la branche sur laquelle vous vous tenez.
Dong Thang

@Dong Il y a un * à côté de cette branche, il vous suffit donc de la supprimer de la liste copiée!
Melanie

12

J'ai eu un genre de situation similaire et j'ai récemment trouvé la commande suivante utile.

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

Si vous souhaitez conserver plusieurs branches, alors

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

j'espère que cela aide quelqu'un.


1
Bien mais j'avais besoin de backticks pour le faire fonctionner - git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` En fait, je pense que vous les aviez à l'origine mais ils se sont perdus dans le formatage SO.
tassinari

10

Dans la ligne de commande Windows, supprimez tout sauf la branche en cours d'extraction à l'aide de:

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

7

Si vous n'avez pas besoin de passer par Git lui-même, vous pouvez également supprimer les têtes sous .git / refs / heads manuellement ou par programme. Les éléments suivants devraient fonctionner avec un ajustement minimal sous Bash:

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

Cela supprimera toutes les succursales locales à l'exception de votre branche principale. Puisque vos branches en amont sont stockées sous .git / refs / remotes , elles resteront intactes.

Si vous n'utilisez pas Bash, ou si vous souhaitez récupérer de nombreux référentiels Git à la fois, vous pouvez faire quelque chose de similaire avec GNU find:

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

La solution de recherche est probablement plus portable, mais l'élagage des chemins et des noms de fichiers est délicat et potentiellement plus sujet aux erreurs.


Cool. Visual delete :)
sandalone

5

Aucune des réponses n'a pleinement satisfait mes besoins, alors c'est parti:

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

Cela supprimera toutes les branches locales fusionnées et commençant par feature/, bugfix/ou hotfix/. Ensuite, la télécommande en amont originest élaguée (vous devrez peut-être saisir un mot de passe).

Fonctionne sur Git 1.9.5.


5

Sur la base d'une combinaison d'un certain nombre de réponses ici - si vous souhaitez conserver toutes les branches qui existent sur la télécommande mais supprimer le reste , la ligne suivante fera l'affaire:

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

3

Bien que ce ne soit pas une solution en ligne de commande, je suis surpris que l' interface graphique Git n'ait pas encore été suggérée.

J'utilise la ligne de commande 99% du temps, mais dans ce cas, c'est bien trop lent (d'où la question d'origine), ou vous ne savez pas ce que vous êtes sur le point de supprimer lorsque vous avez recours à une manipulation de shell longue mais intelligente.

L'interface utilisateur résout ce problème car vous pouvez rapidement cocher les branches que vous souhaitez supprimer et vous rappeler celles que vous souhaitez conserver, sans avoir à taper une commande pour chaque branche.

Dans l'interface utilisateur, accédez à Branche -> Supprimer et Ctrl + Cliquez sur les branches que vous souhaitez supprimer afin qu'elles soient mises en surbrillance. Si vous voulez être sûr qu'ils sont fusionnés dans une branche (par exemple dev), sous Supprimer uniquement si fusionné dans définir la branche locale sur dev. Sinon, définissez-le sur Toujours pour ignorer cette vérification.

GitUI: supprimer les branches locales


1

Pour PowerShell, cela fonctionnera:

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

0

Le script suivant supprime les branches. Utilisez-le et modifiez-le à vos risques et périls, etc. etc.

Sur la base des autres réponses de cette question, j'ai fini par écrire un script bash rapide pour moi-même. Je l'ai appelé "gitbd" (branche git -D) mais si vous l'utilisez, vous pouvez le renommer comme vous le souhaitez.

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
}

Il proposera de supprimer toutes les branches qui correspondent à un argument de modèle, s'il est transmis, ou toutes les branches locales lorsqu'elles sont appelées sans argument. Cela vous donnera également une étape de confirmation, car, vous savez, nous supprimons des choses, donc c'est bien.

C'est un peu stupide - s'il n'y a pas de branches qui correspondent au motif, il ne s'en rend pas compte.

Un exemple de sortie:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 

0

J'ai écrit un script shell afin de supprimer toutes les branches locales sauf 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

0

Les réponses ci-dessus fonctionnent bien. Voici une autre approche lorsque nous avons beaucoup de branches dans le référentiel local et que nous devons supprimer de nombreuses branches, sauf quelques-unes qui se trouvent dans la machine locale.

Première git branch liste toutes les succursales locales.

Transposer la colonne des noms de branche en une seule ligne dans le fichier en exécutant une commande unix
git branch > sample.txt
Cela l'enregistrera dans le fichier sample.txt . Et courir
awk 'BEGIN { ORS = " " } { print }' sample.txt
commande dans le shell. Cela transformera la colonne en ligne et copiera la liste des noms de branche sur une seule ligne.

Et puis courez
git branch -D branch_name(s).
Cette action supprimera toutes les succursales répertoriées présentes dans le réseau local.


0

La manière la plus pragmatique: assurez-vous que vous n'avez pas de travail non engagé master, validez / push si nécessaire, clonez une nouvelle copie du référentiel et supprimez l'ancienne.


0

Pour cela, vous pouvez utiliser git-extras

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

0

Je n'ai pas grep ou autre unix sur ma boîte mais cela a fonctionné depuis le terminal de VSCode:

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

J'utilise le d minuscule pour ne pas supprimer les branches non fusionnées.

J'étais également sur master quand je l'ai fait, donc * mastern'existe pas donc il n'a pas essayé de supprimer master.


Confirmé: Sinon master, cette commande sera supprimée master.
Brett Rowberry

-1

Assurez-vous de le faire en premier

git fetch

Une fois que vous disposez de toutes les informations sur les succursales distantes, utilisez la commande suivante pour supprimer toutes les succursales sauf le maître

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.