Supprimer les branches de suivi qui ne sont plus sur la télécommande


1173

Existe-t-il un moyen simple de supprimer toutes les branches de suivi dont l'équivalent distant n'existe plus?

Exemple:

Succursales (locales et éloignées)

  • Maître
  • origine / maître
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

Localement, je n'ai qu'une branche maître. Maintenant, je dois travailler sur bug-fix-a , donc je le vérifie, je travaille dessus et je pousse les modifications sur la télécommande. Ensuite, je fais de même avec bug-fix-b .

Succursales (locales et éloignées)

  • Maître
  • bug-fix-a
  • bug-fix-b
  • origine / maître
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

J'ai maintenant le maître des branches locales , bug-fix-a , bug-fix-b . Le responsable de la branche Master fusionnera mes modifications dans Master et supprimera toutes les branches qu'il a déjà fusionnées.

Donc, l'état actuel est maintenant:

Succursales (locales et éloignées)

  • Maître
  • bug-fix-a
  • bug-fix-b
  • origine / maître
  • origin / bug-fix-c

Maintenant, je voudrais appeler une commande pour supprimer les branches (dans ce cas bug-fix-a , bug-fix-b ), qui ne sont plus représentées dans le référentiel distant.

Ce serait quelque chose comme la commande existante git remote prune origin, mais plus comme git local prune origin.

Réponses:


1282

git remote prune origin pruneaux dépistant des branches pas sur la télécommande.

git branch --merged répertorie les branches qui ont été fusionnées dans la branche actuelle.

xargs git branch -d supprime les branches répertoriées sur l'entrée standard.

Soyez prudent en supprimant les branches répertoriées par git branch --merged. La liste peut inclure masterou d'autres branches que vous préférez ne pas supprimer.

Pour vous donner la possibilité de modifier la liste avant de supprimer des branches, vous pouvez effectuer les opérations suivantes sur une seule ligne:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches

17
La première ligne des branches fusionnées est * mastersur mon système. La commande suivante a fonctionné pour moi:git branch -d $(git branch --merged |tail -n +2)
Trendfischer

99
Si je suis sur developalors git branch --mergedinclut master! Vous ne voulez probablement pas (définitivement!) Supprimer cela. Je pense aussi que cela devrait être git branch -dlà où les minuscules -dsignifient "suppression sûre", par exemple, supprimer uniquement en cas de fusion.
thom_nic

11
Il semble une solution améliorée est fournie .
Sergey Brunov

34
Supprimé fusionné est utile, mais pas la même chose que "supprimer les branches non distantes".
dlsso

11
Utilisez simplement grep pour exclure master:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass

592

Après la commande

git fetch -p

supprime les références distantes, lorsque vous exécutez

git branch -vv

il affichera «disparu» comme état à distance. Par exemple,

$ 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

Vous pouvez donc écrire un script simple pour supprimer les branches locales qui sont devenues des télécommandes:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Notez que ce qui précède utilise la commande "porcelaine" git branchpour obtenir l'état en amont.

Une autre façon d'obtenir ce statut est d'utiliser la commande "plomberie" git for-each-refavec la variable d'interpolation %(upstream:track), qui sera [gone]comme ci-dessus.

Cette approche est quelque peu plus sûre, car il n'y a aucun risque de correspondance accidentelle sur une partie du message de validation.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

8
@KrzysztofWende - pas sur Solaris et certains BSD et certains OS X :)
jww

4
Il semble que cela supprimera également toute branche qui a "disparu" dans le dernier message de validation.
dlsso

11
@dlsso Si le dernier message de validation contient la chaîne ": gone]", alors oui, elle sera également supprimée. Vous pouvez le rendre plus robuste au détriment de la simplicité en ayant un awk / gawk supplémentaire pour supprimer le message de validation. git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
jason.rickman

2
En réponse à mon commentaire précédent (question), la branche actuelle a * comme premier champ. S'il se trouve également dans la liste des branches "disparues", $ 1 sera attribué * et sera interprété comme une spécification de fichier avec awk crachant des noms de fichiers et de dossiers. J'éliminé l'expression grep et avait awk faire tout le filtrage: awk '/: gone]/{if ($1!="*") print $1}'. Cela fonctionne maintenant comme prévu.
rhaben

5
@ahmedbhs puisque la commande utilise des guillemets simples "vous devez utiliser des guillemets doubles" pour entourer la commande entière. De plus, les alias git qui sont des commandes shell (comme celle-ci) nécessitent! au début. Cela fonctionne pour moi:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
jason.rickman

307

La plupart de ces réponses ne répondent pas réellement à la question d'origine. Je l' ai fait un tas de creuser et c'était la solution que je propre trouvé. Voici une version légèrement plus approfondie de cette réponse:

  1. Découvrez votre branche par défaut. habituellementgit checkout master
  2. Courir git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Explication:

Fonctionne en élaguant vos branches de suivi, puis en supprimant celles locales qui montrent qu'elles sont "disparues" git branch -vv .

Remarques:

Si votre langue est définie sur autre chose que l'anglais, vous devrez modifier gonele mot approprié. Les succursales locales ne seront pas touchées. Les branches qui ont été supprimées sur la télécommande mais qui n'ont pas été fusionnées afficheront une notification mais ne seront pas supprimées sur la locale. Si vous souhaitez également les supprimer, passez -dà -D.


2
pour les OS français disparus doivent être changés par disparue
Mohamed EL HABIB

4
devrait ajouter LANG = en_US avant la branche git pour forcer l'anglais: git fetch --prune && LANG = en_US branche git -vv | awk '/: gone] / {print $ 1}' | xargs git branch -d
Mohamed EL HABIB

3
J'ajouterais git checkout master && ...au début de la commande.
iarroyo

2
C'est dangereux lorsque vous êtes sur une branche qui est censée être supprimée - dans ce cas, la première colonne est '*', qui est ensuite passée à xargs. Pour améliorer cela, ajoutez strip le caractère '*' avant de passer la sortie à awk: sed -e 's / ^ * //'
meeee

6
Prudent! Il y a un cas périphérique qui entraînera la suppression de toutes vos branches locales: Si vous êtes actuellement sur une branche qui a été supprimée à distance, la sortie de git branch -vvcommencera par un astérisque qui finira par être exécuté git branch -d *. Voici une version corrigée qui ignorera les lignes avec un astérisque:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm

210

Je ne répondrais pas normalement à une question qui a déjà 16 réponses, mais toutes les autres réponses sont fausses, et la bonne réponse est si simple. La question dit: "Existe-t-il un moyen simple de supprimer toutes les branches de suivi dont l'équivalent distant n'existe plus?"

Si «simple» signifie les supprimer tous en une seule fois, ni fragiles, ni dangereux, et sans dépendre d'outils que tous les lecteurs n'auront pas, alors la bonne réponse est: non.

Certaines réponses sont simples, mais elles ne font pas ce qui a été demandé. D'autres font ce qui a été demandé, mais ne sont pas simples: tous reposent sur l'analyse de la sortie Git via des commandes de manipulation de texte ou des langages de script, qui peuvent ne pas être présents sur tous les systèmes. En plus de cela, la plupart des suggestions utilisent des commandes porcelaine, dont la sortie n'est pas conçue pour être analysée par script ("porcelaine" se réfère aux commandes destinées à une opération humaine; les scripts doivent utiliser les commandes "plomberie" de niveau inférieur).

Lectures complémentaires:


Si vous voulez le faire en toute sécurité, pour le cas d'utilisation de la question (branches de suivi de récupération de place qui ont été supprimées sur le serveur mais existent toujours en tant que branches locales) et avec des commandes Git de haut niveau uniquement, vous devez

  • git fetch --prune(ou git fetch -p, qui est un alias, ou git prune remote originqui fait la même chose sans aller chercher, et n'est probablement pas ce que vous voulez la plupart du temps).
  • Notez toutes les branches distantes signalées comme supprimées. Ou, pour les retrouver plus tard, git branch -v(toute branche de suivi orpheline sera marquée "[disparu]").
  • git branch -d [branch_name] sur chaque branche de suivi orpheline

(ce que proposent certaines des autres réponses).

Si vous voulez for-each-refcréer un script pour une solution, alors est votre point de départ, comme dans la réponse de Mark Longair ici et cette réponse à une autre question , mais je ne vois pas de moyen de l'exploiter sans écrire une boucle de script shell, ou en utilisant xargs ou quelque chose .


Explication du contexte

Pour comprendre ce qui se passe, vous devez comprendre que, dans le cas du suivi des succursales, vous n'avez pas une succursale, mais trois. (Et rappelez-vous que "branche" signifie simplement un pointeur vers une validation.)

Étant donné une branche de suivi feature/X, le référentiel distant (serveur) aura cette branche et l'appellera feature/X. Votre référentiel local a une branche remotes/origin/feature/Xqui signifie: «Voici ce que la télécommande m'a dit que sa branche fonctionnalité / X était, la dernière fois que nous avons parlé», et enfin, le référentiel local a une branche feature/Xqui pointe vers votre dernier commit et est configuré pour "Piste"remotes/origin/feature/X , ce qui signifie que vous pouvez tirer et pousser pour les maintenir alignés.

À un moment donné, quelqu'un a supprimé le feature/Xsur la télécommande. A partir de ce moment, vous vous retrouvez avec votre local feature/X(dont vous ne voulez probablement plus, car le travail sur la fonctionnalité X est probablement terminé), et le vôtre remotes/origin/feature/Xest certainement inutile car son seul but était de se souvenir de l'état de la branche du serveur .

Et Git vous permettra de nettoyer automatiquement les redondants remotes/origin/feature/X- c'est ce qui se git fetch --prunepasse - mais pour une raison quelconque, il ne vous permet pas de supprimer automatiquement les vôtres feature/X... même si votre feature/Xcontient toujours les informations de suivi orphelines, il contient donc les informations pour identifier les anciennes succursales de suivi qui ont été complètement fusionnées. (Après tout, il peut vous donner les informations qui vous permettent de faire l'opération vous-même à la main.)


3
C'est une réponse beaucoup plus sûre. De plus, cela fonctionnera si vous utilisez un workflow "Squash and Merge", contrairement à la réponse sélectionnée.
Jake Levitt

3
Cela ne répond vraiment qu'à la partie facile de la question "comment trouver les branches disparues" (et cela avec la même commande que celle déjà publiée par jason.rickman en 2015) mais vous dit ensuite de supprimer toutes les branches manuellement, ce qui est exactement ce que l'OP ne veut pas faire.
Voo

4
@Voo C'est le point de la réponse: non pas pour vous dire comment le faire (c'est juste un bonus) mais pour vous dire que la réponse est qu'il n'y a pas de moyen facile et simple de le faire. Quelle est la bonne réponse à la question telle qu'elle a été formulée.
Andrew Spencer

1
"Si vous voulez le faire en toute sécurité, pour le cas d'utilisation de la question .." - ce qui annule la plupart des revendications du premier paragraphe. "[Git] peut vous donner les informations qui vous permettent de faire l'opération vous-même à la main" - nous sommes des programmeurs, donc étant donné les informations sous forme de liste (qui est affichée), la tâche est toujours simple (par exemple xargs). Il faut également git aliassimplifier un certain nombre de cas.
user2864740

2
@ user2864740 Certains lecteurs peuvent considérer que l'écriture d'un petit script bash relève de leur définition de "simple", et c'est une position parfaitement défendable, mais j'ai donné ma propre interprétation de "simple" dans le 2ème paragraphe et le reste de la réponse est cohérent avec ça. Et pour défendre mon interprétation certes restrictive, tous les utilisateurs de Git n'ont pas xargsou bash, et ils ne sont probablement pas ici à la recherche d'un défi de micro-codage, autant qu'une réponse rapide qu'ils peuvent appliquer en toute sécurité sans se distraire davantage de leur véritable objectif .
Andrew Spencer

52

J'ai trouvé la réponse ici: Comment puis-je supprimer toutes les branches git qui ont été fusionnées?

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

Assurez-vous que nous gardons le maître

Vous pouvez vous assurer que master, ou toute autre branche d'ailleurs, ne soit pas supprimée en en ajoutant une autre grepaprès la première. Dans ce cas, vous iriez:

git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d

Donc, si nous voulions garder master, developet stagingpar exemple, nous irions:

git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d

Faites-en un alias

Comme il est un peu long, vous voudrez peut-être ajouter un alias à votre .zshrcou .bashrc. Le mien s'appelle gbpurge(pour 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'

Rechargez ensuite votre .bashrcou .zshrc:

. ~/.bashrc

ou

. ~/.zshrc

8
Utile, mais pas la même chose que "supprimer les branches non distantes"
dlsso

Greate answer @karlingen, je l'ai en permanence en tant que gbpurge dans tous mes environnements de développement
Peter Dolan

50

Solution Windows

Pour 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 $_}

Explication

git checkout master passe à la branche principale

git remote update origin --prune élagage des branches éloignées

git branch -vvobtient une sortie détaillée de toutes les branches ( référence git )

Select-String -Pattern ": gone]" obtient uniquement les enregistrements où ils ont été supprimés de la télécommande.

% { $_.toString().Trim().Split(" ")[0]} obtenir le nom de la succursale

% {git branch -d $_} supprime la branche


3
Merci pour cela, même si j'ai dû ajouter un .Trim()après .toString()pour supprimer deux espaces avant le nom de la branche.
Matthew

2
Merci pour cette commande. J'ai dû changer le git branch -dpour git branch -Dsinon j'obtiens l'erreur la branche n'est pas complètement fusionnée.
markieo

1
@markieo Vous le savez probablement déjà, mais pour quelqu'un d'autre - git branch -Dest destructeur et supprimera le travail local que vous n'avez pas encore poussé. -dest toujours sûr, soyez prudent -D.
Nate Barbettini

33

Le motif correspondant à «disparu» dans la plupart des autres solutions était un peu effrayant pour moi. Pour être plus sûr, cela utilise l' --formatindicateur pour extraire l' état de suivi en amont de chaque branche .

J'avais besoin d'une version compatible avec Windows, donc cela supprime toutes les branches répertoriées comme "disparues" à l'aide de Powershell:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

La première ligne répertorie le nom des branches locales dont la branche en amont est "disparue". La ligne suivante supprime les lignes vides (qui sont sorties pour les branches qui ne sont pas "disparues"), puis le nom de la branche est passé à la commande pour supprimer la branche.


6
L' --formatoption semble être relativement nouvelle; J'avais besoin de mettre à niveau git de 2.10.quelque chose à 2.16.3 pour l'obtenir. Voici ma modification pour les systèmes Linux:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
bxm

2
C'est la meilleure solution jusqu'à présent. Une suggestion est d'utiliser refname:short. Ensuite, vous pouvez supprimer la ligne% { $_ -replace '^refs/heads/', '' }
ioudas

2
Ceci est une excellente solution pour les fenêtres. Je l'utilise comme ça car il est plus lisible git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }Aussi probablement une bonne idée d'utiliser à la -dplace de -D. La suppression forcée ne devrait pas être nécessaire pour les branches qui ne sont plus sur la télécommande.
Rubanov

31

Supprimez toutes les branches qui ont été fusionnées dans master, mais n'essayez pas de supprimer master lui-même:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

ou ajoutez un alias:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Explication:

git checkout master caisse principale de caisse

git pull origin master s'assurer que la succursale locale a fusionné toutes les modifications à distance

git fetch -p supprimer les références aux branches distantes qui ont été supprimées

git branch -d $(git branch master --merged | grep master -v) supprimez toutes les branches qui ont été fusionnées en master, mais n'essayez pas de supprimer le master lui-même


3
Une remarque, cela est très utile mais cela supprimera également les branches qui n'ont jamais été poussées vers la télécommande. Il est plus sûr de ne lister que les différences, puis de copier ce que vous voulez vraiment supprimer dans la git branch -Dcommande
Zefiryn

Juste pour clarifier, Zefiryn fait référence à l'utilisation de l'option -D qui ne fait pas partie de la ligne unique.
cs01

1
Ou juse les minuscules git branch -dqui devraient émettre un avertissement sur les branches non poussées.
acme

16
git fetch -p

Cela élagera toutes les branches qui n'existent plus sur la télécommande.


64
cela supprime les références distantes, mais pas les succursales locales elles-mêmes. Bien qu'il s'agisse d'une commande utile, je ne pense pas que cela réponde à la question d'OP.
thataustin

Quelle? Cela supprime les succursales locales pour moi.
Alex Hall

1
@AlexHall Le référentiel distant a une branche X; vous git checkout X; maintenant votre dépôt a une branche de suivi (locale) Xet une branche distante origin/X; le référentiel distant supprime X; vous git fetch-p; dans votre référentiel local, non seulement origin/Xmais aussi Xont été supprimés. C'est ce que vous dites?
Andrew Spencer

16

Encore une autre réponse pour la pile, s'inspirant largement de la réponse de Patrick (que j'aime parce qu'elle semble éliminer toute ambiguïté sur l'endroit où gone]correspondra legit branch sortie) mais en ajoutant un * nix plié.

Dans sa forme la plus simple:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

Je l'ai enveloppé dans un git-gonescript sur mon chemin:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - Le --format option semble assez récente; J'avais besoin de mettre à niveau git de 2.10.quelque chose à 2.16.3 pour l'obtenir.

EDIT: ajusté pour inclure une suggestion refname:shortde Benjamin W.

NB2 - J'ai seulement testé en bash, d'où le hashbang, mais probablement portable sh.


Vous ne pouvez pas sauter la sedpartie en utilisant %(refname:short)dans la première ligne?
Benjamin

Semble fonctionner pour moi, et je l'ai maintenant comme un alias Git soigné - la solution la plus propre de tous ici!
Benjamin

2.13 introduit --format. Une autre façon de sauter la sedpartie est d'utiliser git update-ref -d. Notez que cela est probablement quelque peu dangereux, l'utilisation git for-each-refest plus sûre ici (donnée --shell).
gsnedders

Excellente réponse, et cela m'a aidé à répondre à mes propres questions lorsque je patauge --formatpour le faire moi-même. Juste une question: pourquoi le #!bash? Tout ici shme semble portable .
Toby Speight

C'est juste mon passe-partout normal, et je n'avais pas testé ailleurs.
bxm

15

Pourrait être utile à certains, une seule ligne simple pour effacer toutes les succursales locales sauf master et develop

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

Réponse géniale! J'aime la façon dont on peut facilement jouer avec le 'git branch | grep -v "master" | grep -v "develop"genre de choses avant de s'engager à ajouter la partie suppression de la commande. 👏😊
finneycanhelp

Mais cela ne répond pas à la question ci-dessus. Cela supprimera les branches même si la télécommande est toujours là.
Jim.B

13

Cela supprimera toutes les branches locales fusionnées, à l'exception de la référence principale locale et de celle actuellement utilisée:

git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

Et cela supprimera toutes les branches ayant déjà été supprimées du référentiel distant référencé par " origine ", mais sont toujours disponibles localement dans " télécommandes / origine ".

git remote prune origin

git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d Explication: je préfère remplacer le git branch --mergedpar git branch -vvpour afficher le statut (disparu) car le précédent git branch --mergedpeut également montrer le maître
jpmottin

13

Je ne pense pas qu'il existe une commande intégrée pour ce faire, mais il est sûr de faire ce qui suit:

git checkout master
git branch -d bug-fix-a

Lorsque vous utilisez -d, git refusera de supprimer la branche à moins qu'elle ne soit complètement fusionnée dans HEADou sa branche de suivi à distance en amont. Ainsi, vous pouvez toujours parcourir la sortie de git for-each-refet essayer de supprimer chaque branche. Le problème avec cette approche est que je soupçonne que vous ne voulez probablement pas bug-fix-dêtre supprimé simplement parce qu'il origin/bug-fix-dcontient son historique. Au lieu de cela, vous pouvez créer un script quelque chose comme ceci:

#!/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

Attention: je n'ai pas testé ce script - à n'utiliser qu'avec précaution ...


J'ai pris la liberté de modifier le script. Il ne donne toujours aucune garantie, mais il fonctionne et semble fonctionner maintenant.
fwielstra

13

TL; DR:

Supprimez TOUTES les succursales locales qui ne sont pas distantes

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

Supprimez TOUTES les branches locales qui ne sont pas distantes ET qui sont entièrement fusionnées ET qui ne sont pas utilisées comme indiqué dans de nombreuses réponses auparavant.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

Explication

  • git fetch -p va tailler toutes les branches qui n'existent plus sur la télécommande
  • git branch -vv imprimera les branches locales et les branches élaguées seront étiquetées avec gone
  • grep ': gone]' sélectionne uniquement la branche disparue
  • awk '{print $1}' filtrer la sortie pour afficher uniquement le nom des branches
  • xargs git branch -D fera une boucle sur toutes les lignes (branches) et forcera la suppression de cette branche

Pourquoi git branch -Det pas git branch -dautre chose pour les succursales qui ne sont pas complètement fusionnées.

error: The branch 'xxx' is not fully merged.

1
vouliez-vous dire à distance au lieu de maître?
tinos

8

Vous pouvez faire ceci:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d

7

Sur la base des informations ci-dessus, cela a fonctionné pour moi:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

Il supprime toutes les succursales locales qui sont ': gone] 'distantes.


1
Il semble que cela supprimera également toute branche qui a "disparu" dans le dernier message de validation.
dlsso

Il supprimera également toute branche qui a gonen'importe où dans son nom.
bfontaine

3
"git branch -D git branch -vv | grep ': gone]' | awk '{print $ 1}' | xargs`" Cela a fait le travail pour moi.
Muthu Ganapathy Nathan

7
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

La commande ci-dessus peut être utilisée pour récupérer des branches qui sont fusionnées et supprimées dans la télécommande et elle supprime la branche locale qui n'est plus disponible dans la télécommande


La meilleure solution jusqu'à présent, bien que je l'ai modifiée grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Dpour forcer la suppression de tout
Shoaib

Dangereux si l'un de vos noms de branche contient la sous-chaîne gonen'importe où (par exemple usingonefunction).
Toby Speight

7

Rien de tout cela ne me convenait vraiment. Je voulais quelque chose qui purgerait toutes les branches locales qui suivaient une branche distante, sur origin, où la branche distante a été supprimée ( gone). Je ne voulais pas supprimer les branches locales qui n'avaient jamais été configurées pour suivre une branche distante (c'est-à-dire mes branches de développement locales). Je voulais aussi un simple one-liner qui utilise simplement git, ou d'autres outils CLI simples, plutôt que d'écrire des scripts personnalisés. J'ai fini par utiliser un peu de grepet awkpour faire cette commande simple.

C'est finalement ce qui s'est terminé dans mon ~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

Voici une git config --global ...commande pour ajouter facilement ceci comme 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'

REMARQUE: Dans la commande config, j'utilise l' -doption git branchplutôt que -D, comme je le fais dans ma configuration réelle. J'utilise -Dparce que je ne veux pas entendre Git se plaindre de branches non fusionnées. Vous pouvez également souhaiter cette fonctionnalité. Si c'est le cas, utilisez simplement -Dplutôt -dqu'à la fin de cette commande de configuration.


J'aime l'approche de l'alias git. Question rapide: Pourquoi faire git branch -vvet chercher : gone]et ne pas faire git branch -vet ne pas vouloir [gone]?
lalibi

@lalibi, bonne question. Je ne m'en souviens pas. Je soupçonne que quelque chose ne se présentait pas avec un seul v. Si git branch -v | grep '[gone]'ça marche pour vous, allez-y. Cela semble un peu plus propre.
Karl Wilbur

4

Basé sur Git Tip: Deleting Old Local Branches , qui ressemble à la solution de jason.rickman, j'ai implémenté une commande personnalisée à cet effet appelée git gone using 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 combine l'élagage et la liste des branches "disparues":

$ 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

Ensuite, vous pouvez appuyer sur la gâchette à l'aide de git gone -dou git gone -D.

Remarques

  • L'expression régulière que j'ai utilisée est "$BRANCH/.*: gone]"$BRANCHserait normalement origin. Cela ne fonctionnera probablement pas si votre sortie Git est localisée en français, etc.
  • Sebastian Wiesner l'a également porté aux utilisateurs de Rust pour Windows. Celui-là est aussi appelé git gone .

Cela devrait probablement être la réponse acceptée - git goneressemble à un alias pour git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, ce qui résout le problème du PO.
alex

4

S'inspirant largement d'un certain nombre d' autres réponses ici, je me suis retrouvé avec ce qui suit (git 2.13 et supérieur uniquement, je crois), qui devrait fonctionner sur n'importe quel shell de type UNIX:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

Cela utilise notamment for-each-refau lieu de branch(comme branchc'est une commande "porcelaine" conçue pour une sortie lisible par l'homme, pas un traitement machine) et utilise son --shellargument pour obtenir une sortie correctement échappée (cela nous permet de ne nous soucier d'aucun caractère dans le nom de la référence).


Cela fonctionne pour moi, mais ce serait aussi bien si vous pouviez expliquer ce que font les autres étapes de la commande. Par exemple, je ne sais pas ce que cela [ ! -z "$ref" ]signifie. Je pense qu'un multi liner aurait déjà aidé. Mais merci encore pour votre contribution!
KevinH

4

Encore une autre réponse, car aucune des solutions ne répond à mes besoins d'élégance et de multiplateforme:

Commande pour supprimer les branches locales non distantes:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

Pour l'intégrer à gitconfig afin qu'il puisse être exécuté avec git branch-prune:

Frapper

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Besoin d'aide pour trouver une commande universelle pour PowerShell et bash)

Pourquoi cette réponse est la meilleure?

  • Offre une solution complète: ajoute un git branch-prune commande à votre git
  • Fonctionne très bien à partir de Windows PowerShell
  • L'idée de base est @ jason.rickman de » méthode de pare - balles à l' aidegit for-each-ref
  • L'analyse et le filtrage sont effectués sans --filteraucune dépendance externe requise

Explication:

  • Ajoute un nouvel alias à votre ~\.gitconfig. Après avoir exécuté cela, vous pouvez simplement fairegit branch-prune
  • À l'intérieur de cet alias:
    • Récupère les branches avec le --prune drapeau, qui "taille les branches de suivi à distance qui ne sont plus à distance"
    • Les utilisations git for-each-refet --filter, pour obtenir une liste des branches sont [gone](pas de télécommande)
    • Parcourt cette liste et supprime la branche en toute sécurité

1
Merci, @ jerry-wu pour avoir amélioré l'incroyable de cette solution à l'infini.
Himura

@ jerry-wu et votre dernière modification de la commande git config ne fonctionne pas dans PowerShell ((
Himura

1

Je suis venu avec ce script bash. Il garde toujours les branches 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
}

1

J'utilise une méthode courte pour faire le tour, je vous recommande de faire de même car cela pourrait gagner quelques heures et vous donner plus de visibilité

Ajoutez simplement l'extrait suivant dans votre .bashrc (.bashprofile sur macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Récupérer toutes les télécommandes
  2. Obtenir uniquement les branches fusionnées de git
  3. Supprimer de cette liste les branches "protégées / importantes"
  4. Retirez le reste (par exemple, branches propres et fusionnées)

Vous devrez éditer la regex grep afin de l'adapter à vos besoins (ici, cela empêche la suppression de master, preprod et dmz)


git fetch --all --prunea fait l'affaire. Merci!
LeOn - Han Li

1

Cela a fonctionné pour moi:

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

oh, je l'ai posté deux fois sur ... viens de le voir lors de l'examen des messages. Mais vous pourriez vraiment pointer vers le gars qui a fourni cette commande au lieu de prendre cela comme le vôtre!
Dwza

Je l'obtiens d'un forum n'essayez pas d'être intelligent, prenez simplement la réponse ou ignorez-la
Fareed Alnamrouti

Même si vous pouviez ... de toute façon ... je ne suis pas venu ici pour en discuter avec vous. Comme vous l'avez dit ... prenez mon commentaire ou ignorez-le;)
Dwza

0

Je ne sais pas pour combien de temps, mais j'utilise git-up maintenant, qui s'en occupe.

Je le fais git upet il commence à suivre les nouvelles branches et supprime les anciennes.

Juste pour être clair, ce n'est pas une commande git prête à l'emploi - https://github.com/aanand/git-up

BTW, il cache également un arbre sale et fait des rebases toujours avec juste git up.

J'espère que ça sera utile pour quelqu'un


2
Cela ne supprime pas les branches locales qui n'existent pas sur le serveur.
Ashley

0

Voici une solution que j'utilise pour la coquille de poisson. Testé sur Mac OS X 10.11.5, fish 2.3.0et 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

Quelques notes:

Assurez-vous de régler le bon base_branch. Dans ce cas, j'utilise developcomme branche de base, mais cela pourrait être n'importe quoi.

Cette partie est très importante: grep -v "\(master\|$base_branch\|\*\)". Il garantit que vous ne supprimez pas le maître ou votre branche de base.

J'utilise git branch -d <branch>comme une précaution supplémentaire, afin de ne pas supprimer toute branche qui n'a pas été complètement fusionnée avec HEAD en amont ou actuelle.

Un moyen facile de tester est de le remplacer git branch -d $fpar echo "will delete $f".

Je suppose que je devrais également ajouter: UTILISER À VOS PROPRES RISQUES!


0

J'ai écrit un script Python en utilisant GitPython pour supprimer les branches locales qui n'existent pas à distance.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

J'espère que quelqu'un le trouvera utile, veuillez ajouter des commentaires si j'ai raté quelque chose.


0

Si vous utilisez zshshell avec Oh My Zshinstallé, la façon la plus simple de le faire en toute sécurité est d'utiliser la saisie semi-automatique intégrée.

Déterminez d'abord les branches que vous souhaitez supprimer avec:

~ git branch --merged

  branch1
  branch2
  branch3
* master

cela vous montrera une liste des branches déjà fusionnées

Une fois que vous en connaissez quelques-uns que vous souhaitez supprimer, tapez:

~ git branch -d 

Tout ce que vous avez à faire est d'appuyer sur [tab] et il vous montrera une liste des succursales locales. Utilisez tab-complete ou appuyez simplement sur [tab] à nouveau et vous pouvez les parcourir pour sélectionner une branche avec [enter].

Onglet Sélectionnez les branches encore et encore jusqu'à ce que vous ayez une liste de branches que vous souhaitez supprimer:

~ git branch -d branch1 branch2 branch3

Maintenant, appuyez simplement sur Entrée pour supprimer votre collection de branches.

Si vous n'utilisez pas zsh sur votre terminal ... Téléchargez-le ici.


0

J'aime utiliser des tuyaux car cela rend la commande plus facile à lire.

C'est ma solution si vous souhaitez supprimer toutes les branches sauf master.

git branch | grep -v master | xargs -n 1 git branch -D

Pour supprimer d'autres branches correspondant à vos critères, modifiez le premier et le deuxième bloc.

git branch --merged | grep feature_name | xargs -n 1 git branch -D

-3

Voici la réponse simple qui a fonctionné pour moi en utilisant un client git:

Supprimez complètement le référentiel de votre ordinateur, puis vérifiez à nouveau.

Pas de détournement avec des scripts risqués.


2
Qu'en est-il des succursales sur
lesquelles

@ MailoSvětel s'ils sont sur votre télécommande, vous pouvez simplement les tirer à nouveau (n'oubliez pas de valider et de pousser votre dernier travail sur votre télécommande!)
Juan Carlos Ospina Gonzalez

Dans ma question et dans la plupart des réponses, nous essayons d'éviter un travail inutile. En d'autres termes: ce que je dois faire, c'est simplement supprimer les branches, je ne travaillerai plus. Supprimer le référentiel, le cloner et recommencer le suivi des branches, est pour moi beaucoup de travail inutile. En plus de cela, du travail pourrait se perdre :(
Mailo Světel
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.