Existe-t-il un moyen simple de supprimer toutes les branches de suivi dont l’équivalent distant n’existe plus?
Exemple:
Branches (local et distant)
Localement, je n'ai qu'une branche maîtresse. Maintenant, je dois travailler sur bug-fix-a, donc je le vérifie, je travaille dessus et envoie les modifications à la télécommande. Ensuite, je fais la même chose avec bug-fix-b.
Branches (local et distant)
Maintenant, j'ai des branches locales master, bug-fix-a, bug-fix-b. Le responsable de la branche principale fusionnera mes modifications dans maître et supprimera toutes les branches qu’il a déjà fusionnées.
Donc, l'état actuel est maintenant:
Branches (local et distant)
Maintenant, je voudrais appeler une commande pour supprimer des branches (dans ce cas bug-fix-a, bug-fix-b), qui ne sont plus représentées dans la télécommande dépôt.
Ce serait quelque chose comme la commande existante git remote Prune Origin
, mais plutôt comme git local Prune Origin
.
git remote Prune Origin
élague les branches de suivi non sur la télécommande.
git branch --merged
liste les branches qui ont été fusionnées dans la branche actuelle.
xargs git branch -d
supprime les branches listées sur l'entrée standard.
Faites attention en supprimant les branches listées par git branch --merged
. La liste peut inclure master
ou 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 procéder comme suit:
git branch --merged >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
Après la commande
git fetch -p
supprime les références distantes, lorsque vous exécutez
git branch -vv
il affichera "parti" comme statut distant. 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
Ainsi, vous pouvez écrire un script simple pour supprimer les branches locales qui sont passées à distance:
git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done
La plupart de ces réponses ne répondent pas réellement à la question initiale. J'ai fait beaucoup de recherches et this était la solution la plus propre que j'ai trouvée. Voici une version légèrement plus complète de cette réponse:
git checkout master
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 qui indiquent qu'elles sont "parties" dans git branch -vv
.
Notes:
Si votre langue est définie sur autre chose que l'anglais, vous devrez remplacer gone
par le mot approprié. Les branches qui sont uniquement locales ne seront pas touchées. Les branches qui ont été supprimées à distance mais n'ont pas été fusionnées afficheront une notification mais ne seront pas supprimées en local. Si vous souhaitez également les supprimer, remplacez -d
par -D
.
Normalement, je ne répondrais pas à 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 en une fois, ni fragile, ni dangereux, et sans recourir à des outils dont ne disposeront pas tous les lecteurs, la bonne réponse est: non.
Certaines réponses sont simples, mais ils ne font pas ce qui a été demandé. D'autres font ce qui a été demandé, mais ne sont pas simples: ils reposent tous sur l'analyse de la sortie de Git à l'aide de commandes de manipulation de texte ou de 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 de porcelaine, dont la sortie n'est pas conçue pour être analysée par script ("porcelaine" désigne les commandes destinées à une opération humaine; les scripts doivent utiliser les commandes de "niveau" de niveau inférieur).
Lectures complémentaires:
git branch
sortie dans un script .git remote Prune
, git Prune
, git fetch --Prune
Si vous voulez le faire en toute sécurité, pour le cas d'utilisation de la question (branches de suivi de ramassage ramassées qui ont été supprimées sur le serveur mais existent toujours en tant que branches locales) et uniquement avec les commandes Git de haut niveau,
git fetch --Prune
(ou git fetch -p
, qui est un alias, ou git Prune remote Origin
qui fait la même chose sans récupérer et qui n'est probablement pas ce que vous voulez la plupart du temps).git branch -v
(toute branche de suivi orpheline sera marquée "[partie]").git branch -d [branch_name]
sur chaque branche de suivi orpheline(ce que proposent certaines des autres réponses).
Si vous souhaitez créer un script pour une solution, alors for-each-ref
est votre point de départ, comme dans réponse de Mark Longair ici et cette réponse à une autre question , mais je peux ne voyez pas un moyen de l'exploiter sans écrire une boucle de script Shell, ni utiliser xargs ou quelque chose comme ça.
Pour comprendre ce qui se passe, vous devez comprendre que, dans le cas du suivi de branches, vous n’avez pas une branche, mais trois. (Et rappelez-vous que "branche" signifie simplement un pointeur sur un commit.)
Avec 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/X
qui signifie "C'est ce que la télécommande m'a dit que sa fonction était/la branche X était, la dernière fois que nous avons parlé", et enfin, le référentiel local a une branche feature/X
qui pointe vers votre dernier commit et est configuré pour "suivre" 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/X
de la télécommande. À partir de ce moment, vous restez avec votre feature/X
local (ce que vous ne voulez probablement plus, car le travail sur la fonctionnalité X est probablement terminé), et votre remotes/Origin/feature/X
qui est certainement inutile car son seul but était de se souvenir de l'état de la branche du serveur.
Et Git vous laissera nettoyer automatiquement le remotes/Origin/feature/X
redondant - c'est ce que git fetch --Prune
fait - mais pour une raison quelconque, il ne vous permet pas de supprimer automatiquement votre propre feature/X
... même si votre feature/X
contient toujours les informations de suivi orphelines, il dispose donc des informations lui permettant d'identifier les anciennes branches de suivi entièrement fusionnées. (Après tout, il peut vous donner l'information qui vous permet de faire l'opération à la main vous-même.)
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
Vous pouvez vous assurer que master
, ou toute autre branche, ne soit pas supprimé en ajoutant un autre grep
après le premier. 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
, develop
et staging
par exemple, nous irions:
git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d
Comme il est un peu long, vous voudrez peut-être ajouter un alias à votre .zshrc
ou .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 .bashrc
ou .zshrc
:
. ~/.bashrc
ou
. ~/.zshrc
La solution semble être ici - https://stackoverflow.com/a/1072178/133986
En bref, git remote Prune
fait la magie
Supprimez toutes les branches qui ont été fusionnées dans le maître, mais n'essayez pas de supprimer le maître 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
branche de commande principale
git pull Origin master
s'assurer que la branche locale a fusionné toutes les modifications à distance
git fetch -p
supprime les références aux branches distantes supprimées
git branch -d $(git branch master --merged | grep master -v)
supprimer toutes les branches qui ont été fusionnées dans le maître, mais n'essayez pas de supprimer le maître lui-même
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 $_}
git checkout master
passe à la branche principale
git remote update Origin --Prune
élague les branches distantes
git branch -vv
obtient une sortie détaillée de toutes les branches ( référence git )
Select-String -Pattern ": gone]"
ne récupère que les enregistrements où ils ont été supprimés.
% { $_.toString().Trim().Split(" ")[0]}
récupère le nom de la branche
% {git branch -d $_}
supprime la branche
Le motif correspondant à "disparu" dans la plupart des autres solutions m'a un peu effrayé. Pour plus de sécurité, ceci utilise le drapeau --format
pour extraire le numéro de chaque branche statut de suivi en amont .
J'avais besoin d'une version compatible avec Windows, donc cela supprime toutes les branches répertoriées comme "ayant disparu" à 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 indique le nom des branches locales dont la branche en amont est "partie". La ligne suivante supprime les lignes vierges (qui sont générées pour les branches qui ne sont pas "parties"), puis le nom de la branche est transmis à la commande pour supprimer la branche.
git fetch -p
Cela supprimera toutes les branches qui ne sont pas suivies à distance.
Pourrait être utile à certains, simple ligne à effacer toutes les branches locales, sauf maître et développer
git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
Ceci supprimera toutes les branches locales fusionnées sauf la référence principale locale et 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 "Origin", mais sont toujours disponibles localement dans "télécommandes/Origin".
git remote Prune Origin
Je ne pense pas qu'il existe une commande intégrée pour le faire, mais vous pouvez effectuer les opérations suivantes en toute sécurité:
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 HEAD
ou sa branche de suivi à distance en amont. Donc, vous pouvez toujours faire une boucle sur la sortie de git for-each-ref
et essayer de supprimer chaque branche. Le problème avec cette approche est que je suppose que vous ne voulez probablement pas que bug-fix-d
soit supprimé simplement parce que Origin/bug-fix-d
contient son historique. Au lieu de cela, vous pouvez créer un script du type suivant:
#!/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 - utilisez-le avec précaution ...
Encore une autre réponse pour la pile, tirant beaucoup de réponse de Patrick (ce qui me plaît car cela semble éliminer toute ambiguïté quant à la correspondance entre gone]
et le git branch
sortie) mais en ajoutant un * nix plié:
git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" \
| sed 's,^refs/heads/,,;/^$/d' \
| xargs git branch -D
J'ai ce résumé dans un script git-gone
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)%(end)" \
| sed 's,^refs/heads/,,;/^$/d'
}
main() {
DELETE=false
while [ $# -gt 0 ] ; do
case "${1}" in
(-[dD] | --delete) DELETE=true ;;
esac
shift
done
get_gone | action
}
main "${@}"
NB - L’option --format
semble être relativement nouvelle; Je devais mettre à jour git de 2.10.quelque chose à 2.16.3 pour l'obtenir.
Basé sur les informations ci-dessus, cela a fonctionné pour moi:
git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`
Il supprime toutes les branches locales avec ': gone] '
sur distant.
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 à distance et supprime la branche locale qui n’est plus disponible en distance.
Rien de tout cela n'était vraiment juste pour moi. Je voulais quelque chose qui purge 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'étaient jamais configurées pour suivre une branche distante (c'est-à-dire: mes branches de développement locales). De plus, je voulais une ligne simple 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 grep
et awk
pour créer cette commande simple.
C'est finalement ce qui s'est retrouvé 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 commande git config --global ...
pour l'ajouter facilement en tant que 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'option -d
pour git branch
plutôt que -D
, comme dans ma configuration actuelle. J'utilise -D
parce que je ne veux pas entendre Git se plaindre des branches non fusionnées. Vous voudrez peut-être aussi cette fonctionnalité. Si c'est le cas, utilisez simplement -D
au lieu de -d
à la fin de cette commande de configuration.
git pull -p
Si nous utilisons -p avec pull, cela supprimera toutes les branches supprimées du local.
Tirant fortement d'un nombredeautreréponses ici, j'ai fini avec ce qui suit (git 2.13 et ci-dessus seulement, je crois), qui devrait fonctionner sur tout 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-ref
au lieu de branch
(car branch
est une commande "porcelaine" conçue pour une sortie lisible par l'homme, et non pour un traitement par machine) et utilise son argument --Shell
obtenir une sortie correctement échappée (cela nous permet de ne pas nous inquiéter des caractères dans le nom de la référence).
Basé sur Astuce Git: supprimer les anciennes branches locales , qui ressemble à solution de jason.rickman J'ai mis en place une commande personnalisée appelée git gone en utilisant 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 "parties":
$ 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
Vous pouvez ensuite appuyer sur la gâchette en utilisant git gone -d
ou git gone -D
.
"$BRANCH/.*: gone]"
où $BRANCH
serait normalement Origin
. Cela ne fonctionnera probablement pas si votre sortie Git est localisée en français, etc.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
}
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
J'utilise une méthode courte pour faire le tour, je vous recommande de faire la même chose car cela pourrait vous faire gagner quelques heures et vous donner plus de visibilité
Il suffit d’ajouter l’extrait suivant dans votre fichier .bashrc (.bashprofile on macos).
git-cleaner() { git fetch --all --Prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
- Chercher toutes les télécommandes
- N'obtenez que les branches fusionnées de git
- Supprimer de cette liste les branches "protected/important"
- Supprimer le reste (par exemple, les 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)
Je ne sais pas pour combien de temps, mais j'utilise maintenant git-up, qui s'en occupe.
Je fais git up
et il commence à dépister de nouvelles branches et supprime les anciennes.
Soyons clairs: ce n'est pas une commande git prête à l'emploi - https://github.com/aanand/git-up
En outre, il bloque également l’arbre encrassé et fait des rebases avec juste git up
.
J'espère que ça va être utile pour quelqu'un
Voici une solution que j'utilise pour le poisson Shell. Testé sur Mac OS X 10.11.5
, fish 2.3.0
et 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 définir le base_branch
correct. Dans ce cas, j'utilise develop
comme branche de base, mais cela pourrait être n'importe quoi.
Cette partie est très importante: grep -v "\(master\|$base_branch\|\*\)"
. Cela garantit que vous ne supprimez pas le maître ou votre branche de base.
J'utilise git branch -d <branch>
à titre de précaution supplémentaire, afin de ne pas supprimer les branches qui n'ont pas été complètement fusionnées avec HEAD en amont ou actuel.
Un moyen simple de tester consiste à remplacer git branch -d $f
par echo "will delete $f"
.
Je suppose que je devrais également ajouter: UTILISER AT VOTRE PROPRE RISQUE!