1145 votes

Comment élaguer les branches de suivi locales qui n'existent plus sur le site distant ?

Avec git remote prune origin Je peux supprimer les branches locales qui ne sont plus sur le site distant.

Mais je veux aussi supprimer les branches locales qui ont été créées à partir de ces branches distantes (une vérification si elles ne sont pas fusionnées serait bien).

Comment faire ?

11 votes

5 votes

One-liner, multiplateforme, ne donne pas l'impression que le chat a dormi sur votre clavier : npx git-removed-branches (marche à blanc) ou npx git-removed-branches --prune (pour de vrai). Vous devez déjà avoir node.js installés. Voir aussi réponses ci-dessous pour plus de détails.

0 votes

Je pense généralement que ces choses doivent être faites délibérément et non pas automatiquement, sinon vous risquez de supprimer quelque chose que vous ne vouliez pas supprimer. Je m'en tiendrais donc à git branch -d localBranchName et git push origin --delete remoteBranchName.

1258voto

Schleis Points 9098

Après l'élagage, vous pouvez obtenir la liste des branches distantes avec git branch -r . La liste des branches avec leur branche de suivi à distance peut être récupérée avec git branch -vv . En utilisant ces deux listes, vous pouvez donc trouver les branches de suivi à distance qui ne figurent pas dans la liste des télécommandes.

Cette ligne devrait faire l'affaire (nécessite bash o zsh ne fonctionne pas avec le shell Bourne standard) :

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

Cette chaîne récupère la liste des branches distantes et la transmet à la fonction egrep par l'intermédiaire de l'entrée standard. Et filtre les branches qui ont une branche de suivi à distance (en utilisant git branch -vv et le filtrage pour ceux qui ont origin ), puis la première colonne de cette sortie, qui sera le nom de la branche. Enfin, nous transmettons tous les noms de branches à la commande delete branch.

Puisqu'il utilise le -d il ne supprimera pas les branches qui n'ont pas été fusionnées dans la branche sur laquelle vous vous trouvez lorsque vous exécutez cette commande.

17 votes

Cela a parfaitement fonctionné pour moi. D'une certaine manière, git fetch -p n'est pas toujours suffisante ?

25 votes

Malheureusement, cela ne fonctionne pas avec Git Bash sous Windows. sh.exe": cannot make pipe for process substitution: Function not implemented sh.exe": egrep -v -f /dev/fd/0: No such file or directory fatal: branch name required Des idées ?

2 votes

Cela s'explique par /dev/fd/0 n'existe pas pour stdout dans Windows, je ne sais pas quel serait l'équivalent.

590voto

jackocnr Points 3491

Si vous souhaitez supprimer toutes les branches locales qui sont déjà fusionnées dans master, vous pouvez utiliser la commande suivante :

git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d

Si vous utilisez main comme branche principale, vous devez modifier la commande en conséquence :

git branch --merged main | grep -v '^[ *]*main$' | xargs git branch -d

Plus d'informations .

5 votes

Cela a parfaitement fonctionné, je pense ! Quelqu'un pourrait-il m'expliquer si cette réponse fait quelque chose de différent de la réponse acceptée ?

0 votes

Est-il possible d'en faire un alias git global ? J'ai essayé mais cela n'a pas fonctionné : git config --global alias.cleaner "branch --merged master | grep -v 'master$' | xargs branch -d"

0 votes

Les branches se terminant par "master" ne seront pas supprimées. J'utilise git branch --merged master | grep -v '^ master$' | xargs git branch -d juste parce qu'il correspond à la façon dont il est formaté dans la sortie de la branche git

240voto

twalberg Points 19804

Parmi les informations présentées par git help fetch , il y a ce petit élément :

 -p, --prune
        After fetching, remove any remote-tracking branches which no longer exist on the remote.

Alors, peut-être, git fetch -p est ce que vous recherchez ?

EDIT : Ok, pour ceux qui débattent encore de cette réponse 3 ans après les faits, voici un peu plus d'informations sur la raison pour laquelle j'ai présenté cette réponse...

Tout d'abord, le PO indique qu'il souhaite "supprimer également les branches locales qui ont été créées à partir de ces branches distantes [qui ne sont plus sur la branche distante]". Cela n'est pas possible sans ambiguïté en git . Voici un exemple.

Disons que j'ai un dépôt sur un serveur central, et qu'il a deux branches, appelées A y B . Si je clone ce repo sur mon système local, mon clone aura des refs locales (pas encore de branches réelles) appelées origin/A y origin/B . Supposons maintenant que je fasse ce qui suit :

git checkout -b A origin/A
git checkout -b Z origin/B
git checkout -b C <some hash>

Les faits pertinents ici sont que, pour une raison quelconque, j'ai choisi de créer une branche sur mon repo local qui a un nom différent de son origine, et j'ai également une branche locale qui n'existe pas (encore) sur le repo d'origine.

Supposons maintenant que je supprime les deux A y B sur le repo distant et mettre à jour mon repo local ( git fetch d'une forme ou d'une autre), ce qui fait que mes refs locaux origin/A y origin/B à disparaître. Maintenant, mon repo local a encore trois branches, A , Z y C . Aucune d'entre elles n'a de branche correspondante sur le repo distant. Deux d'entre elles ont été "créées à partir de ... branches distantes", mais même si je sais qu'il y avait une branche appelée B sur l'origine, je n'ai aucun moyen de le savoir. Z a été créé à partir de B Il a été renommé au cours du processus, probablement pour une bonne raison. En réalité, sans un processus externe enregistrant les métadonnées relatives à l'origine des branches, ou sans une personne connaissant l'histoire, il est impossible de dire laquelle des trois branches, le cas échéant, le PO vise pour la suppression. En l'absence d'informations externes qui git n'est pas automatiquement maintenue pour vous, git fetch -p est à peu près aussi proche que possible, et toute méthode automatique pour tenter littéralement ce que le PO a demandé court le risque de supprimer trop de branches, ou d'en manquer certaines que le PO aurait voulu supprimer.

Il existe également d'autres scénarios, par exemple si je crée trois branches distinctes de origin/A tester trois approches différentes de quelque chose, et ensuite origin/A disparaît. J'ai maintenant trois branches, qui ne peuvent évidemment pas toutes correspondre en termes de nom, mais qui ont été créées à partir de origin/A Il s'agit donc d'une interprétation littérale de la question du PO qui nécessiterait la suppression de ces trois éléments. Toutefois, cela n'est peut-être pas souhaitable, si l'on peut même trouver un moyen fiable de les faire correspondre...

126 votes

Cela ne supprime pas les branches locales, mais seulement les pointeurs distants vers les branches.

7 votes

Il ne supprime que ces branches locales, qui n'existent pas dans les branches distantes ET sur lesquelles vous n'avez jamais fait de checkout.

17 votes

Vous devriez lire la question plus attentivement, comme le fait remarquer Jaap. Les personnes qui votent pour cette réponse devraient également lire le contenu réel de la question.

3voto

NHDaly Points 878

Je ne suis pas sûr de savoir comment le faire en une seule fois, mais git git branch -d <branchname> supprimera une branche locale UNIQUEMENT si elle est complètement fusionnée. Notez le d minuscule.

git branch -D <branchname> (notez le D majuscule) supprimera une succursale locale, quel que soit son statut de fusion.

0 votes

Sous Windows, les autres réponses n'ont pas fonctionné pour moi. L'utilisation de cette réponse avec le simple commutateur -D a fonctionné (même si la branche avait déjà été "supprimée").

0 votes

Peut-on le faire pour toutes les branches en même temps ?

3voto

daniilyar Points 159

La variante de Schleis ne fonctionne pas pour moi (Ubuntu 12.04), alors laissez-moi vous proposer mes variantes (claires et brillantes :) :

Variante 1 (je préfère cette option) :

git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D 

Variante 2 :

a. Course à sec :

comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | awk '{print "git branch -D " $1}'

b. Enlever les branches :

comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X