Comment tailler les branches de suivi local qui n'existent plus sur distant
Avec git remote prune origin
Je peux supprimer les branches locales qui ne sont plus sur la télécommande.
Mais je veux aussi supprimer les branches locales qui ont été créées à partir de ces branches distantes (vérifier si elles sont non fusionnées serait bien).
Comment puis-je faire cela?
24 réponses
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
. Donc, en utilisant ces deux listes, vous pouvez trouver les branches de suivi à distance qui ne sont pas dans la liste des télécommandes.
Cette ligne devrait faire l'affaire (nécessite bash
ou zsh
, ne fonctionnera pas avec la norme Bourne shell):
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 obtient la liste des branches distantes et la passe dans egrep
via la norme entrée. Et filtre les branches qui ont une branche de suivi à distance (en utilisant git branch -vv
et en filtrant pour celles qui ont origin
) puis en obtenant la première colonne de cette sortie qui sera le nom de la branche. Enfin passer tous les noms de branche dans la commande delete branch.
Comme il utilise l'option -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.
Rappelez-vous également que vous devrez exécuter git fetch --prune
d'abord , sinon {[0] } verra toujours les branches distantes.
Si vous souhaitez supprimer toutes les branches locales déjà fusionnées dans master, vous pouvez utiliser la commande suivante:
git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
Parmi les informations présentées par git help fetch
, il y a ce petit article:
-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 le fait, voici un peu plus d'informations sur pourquoi j'ai présenté cette réponse...
Tout d'abord, L'OP dit qu'ils veulent "supprimer également les branches locales qui ont été créées à partir de ces branches distantes [qui ne sont plus sur la télécommande]". Ce n'est pas sans ambiguïté possible dans git
. Voici un exemple.
Disons que j'ai une pension sur un serveur central, et il a deux branches, appelé A
et B
. Si je clone ce repo sur mon système local, mon clone aura des refs locaux (pas encore de branches réelles) appelés origin/A
et origin/B
. Maintenant, disons que je fais 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 j'ai choisi pour une raison quelconque de créer une branche sur mon repo local qui a un nom différent de son origine, et j'ai aussi une branche locale qui ne le fait pas (encore) existe sur le repo d'origine.
Disons maintenant que je supprime à la fois les branches A
et B
sur le repo distant et met à jour mon repo local (git fetch
d'une certaine forme), ce qui fait disparaître mes refs locaux origin/A
et origin/B
. Maintenant, mon repo local a trois branches encore, A
, Z
, et C
. Aucun d'entre eux n'a de branche correspondante sur le repo distant. Deux d'entre eux ont été "créés à partir ... les branches distantes", mais même si je sais qu'il y a une branche appelée B
sur l'origine, je n'ai aucun moyen pour savoir que Z
a été créé à partir de B
, car il a été renommé dans le processus, probablement pour une bonne raison. Donc, vraiment, sans un processus externe d'enregistrement des métadonnées d'origine de branche, ou un humain qui connaît l'histoire, il est impossible de dire laquelle des trois branches, le cas échéant, l'OP vise pour la suppression. Sans certaines informations externes que git
ne maintient pas automatiquement pour vous, git fetch -p
est à peu près aussi proche que vous pouvez obtenir, et toute méthode automatique pour littéralement tenter quoi le PO demandé court le risque de supprimer trop de branches, ou d'en manquer certaines que le PO voudrait autrement supprimer.
Il y a aussi d'autres scénarios, comme si je crée trois branches distinctes sur origin/A
pour tester trois approches différentes de quelque chose, puis origin/A
s'en va. Maintenant, j'ai trois branches, qui ne peuvent évidemment pas toutes correspondre au nom, mais elles ont été créées à partir de origin/A
, et donc une interprétation littérale de la question OPs nécessiterait de supprimer les trois. Cependant, cela peut ne pas être souhaitable, si vous pouviez même trouver un moyen fiable de les faire correspondre...
Cela supprimera les branches locales pour lesquelles les branches de suivi à distance ont été élaguées. (Assurez-vous que vous êtes sur master
branche!)
git checkout master
git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -d
Détails:
-
git branch -vv
affiche "disparu" pour les branches locales que la télécommande a été élaguée.mybranch abc1234 [origin/mybranch: gone] commit comments
-
-d
vérifiera s'il a été fusionné (-D
le supprimera indépendamment)error: The branch 'mybranch' is not fully merged.
On peut configurer Git pour supprimer automatiquement les références aux branches distantes supprimées lors de la récupération:
git config --global fetch.prune true
Lorsque vous appelez git fetch
ou git pull
par la suite, les références aux branches distantes supprimées sont automatiquement supprimées.
Il y a un paquet npm soigné qui le fait pour vous (et il devrait fonctionner multi-plateforme).
Installez-le avec: npm install -g git-removed-branches
Puis git removed-branches
vous montrera toutes les branches locales périmées, et git removed-branches --prune
pour les supprimer réellement.
Il répertorie les branches locales dont la branche de suivi à distance est supprimée de la télécommande
$ git remote prune origin --dry-run
Si vous voulez dé-référencer ces branches locales de local qui ne sont pas suivies
$ git remote prune origin
Si vous utilisez Windows et Powershell, vous pouvez utiliser ce qui suit pour supprimer toutes les branches locales qui ont été fusionnées dans la branche actuellement extraite:
git branch --merged | ? {$_[0] -ne '*'} | % {$_.trim()} | % {git branch -d $_}
Explication
- répertorie la branche actuelle et les branches qui y ont été fusionnées
- Filtre la branche courante
- nettoie tous les espaces de début ou de fin de la sortie
git
pour chaque nom de branche restant - supprime les branches locales fusionnées
Ça vaut le coup courir git branch --merged
par lui-même d'abord juste pour s'assurer qu'il va seulement supprimer ce que vous attendez de lui.
(porté/automatisé à partir de http://railsware.com/blog/2014/08/11/git-housekeeping-tutorial-clean-up-outdated-branches-in-local-and-remote-repositories/.)
Solution Windows
Pour Microsoft Windows Powershell:
git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Split(" ")[0]} | % {git branch -d $_}
Explication
git checkout master
passe à la branche maître
git remote update origin --prune
pruneaux branches distantes
git branch -vv
obtient une sortie détaillée de toutes les branches (git de référence)
Select-String -Pattern ": gone]"
obtient uniquement les enregistrements où ils ont été supprimés de la télécommande.
% { $_.toString().Split(" ")[0]}
obtenir le nom de la branche
% {git branch -d $_}
supprime la branche
Je ne sais pas comment tout faire en même temps, mais git git branch -d <branchname>
ne supprimera une branche locale que si elle est complètement fusionnée. Notez les minuscules D.
git branch -D <branchname>
(Remarque Le capital D) supprimera une succursale locale quel que soit son statut fusionné.
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'ont jamais été configurées pour suivre une branche distante (c'est-à-dire: mes branches de développement locales). En outre, je voulais 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 grep
et awk
pour faire cette commande simple, puis l'ai ajouté comme alias 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 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: L'utilisation de l'indicateur -D
à git branch
peut être très dangereuse. Donc, dans la commande config ci-dessus, j'utilise l'option -d
pour git branch
plutôt que -D
; j'utilise -D
dans ma configuration réelle. J'utilise -D
parce que je ne veux pas entendre Git se plaindre des branches non fusionnées, je veux juste qu'elles disparaissent. Vous pouvez également vouloir cette fonctionnalité. Si c'est le cas, utilisez simplement -D
au lieu de -d
à la fin de cette commande de configuration.
Encore plus court et plus sûr one-liner:
git branch -d $(git branch --merged | cut -c 3-)
Assurez-vous de commander à la branche qui n'est pas encore fusionnée, avant de l'exécuter. Parce que vous ne pouvez pas supprimer la branche que vous êtes actuellement enregistré.
Sur la base des réponses ci-dessus, je suis venu avec cette solution d'une ligne:
git remote prune origin; git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
En utilisant une variante sur la réponse de @wisbucky, j'ai ajouté ce qui suit en tant qu'alias à mon fichier ~/.gitconfig
:
pruneitgood = "!f() { \
git remote prune origin; \
git branch -vv | perl -nae 'system(qw(git branch -d), $F[0]) if $F[3] eq q{gone]}'; \
}; f"
Avec cela, un simple git pruneitgood
nettoiera les deux branches locales et distantes qui ne sont plus nécessaires après les fusions.
Vous pouvez utiliser cette commande:
git branch --merged master | grep -v "\* master" | xargs -n 1 git branch -d
Git Clean: supprime les Branches déjà fusionnées y compris la décomposition de la commande
La variante de Schleis ne fonctionne pas pour moi (Ubuntu 12.04), alors laissez-moi proposer mes variantes (claires et brillantes:):
Variante 1 (je préférerais cette option):
git for-each-ref --format='%(refname:short) %(upstream)' refs/heads/ | awk '$2 !~/^refs\/remotes/' | xargs git branch -D
Variante 2:
A. essai à 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. supprimer les branches:
comm -23 <( git branch | grep -v "/" | grep -v "*" | sort ) <( git br -r | awk -F '/' '{print $2}' | sort ) | xargs git branch -D
J'ai transformé la réponse acceptée en un script robuste. Vous le trouverez dans mon dépôt git-extensions .
$ git-prune --help
Remove old local branches that do not exist in <remote> any more.
With --test, only print which local branches would be deleted.
Usage: git-prune [-t|--test|-f|--force] <remote>
Voici une adaptation de la réponse de @ wisbucky pour les utilisateurs de Windows:
for /f "tokens=1" %i in ('git branch -vv ^| findstr ": gone]"') DO git branch %i -d
J'utilise posh-Git et malheureusement PS n'aime pas le naked for
, alors j'ai créé un script de commande ol simple nommé PruneOrphanBranches.cmd:
@ECHO OFF
for /f "tokens=1" %%i in ('git branch -vv ^| findstr ": gone]"') DO CALL :ProcessBranch %%i %1
GOTO :EOF
:ProcessBranch
IF /I "%2%"=="-d" (
git branch %1 %2
) ELSE (
CALL :OutputMessage %1
)
GOTO :EOF
:OutputMessage
ECHO Will delete branch [%1]
GOTO :EOF
:EOF
Appelez-le sans paramètres pour voir une liste, puis appelez-le avec "- d "pour effectuer la suppression réelle ou" - D " pour toutes les branches qui ne sont pas complètement fusionnées mais que vous voulez supprimer de toute façon.
Essayez ceci dans git bash, pour récupérer et élaguer les références aux branches supprimées, puis élaguer les branches locales qui suivaient celles supprimées:
git fetch -p && git branch -d `git branch -vv | grep ': gone]' | awk '{print $1}' | xargs`
N'oubliez pas de commander d'abord une branche qui ne sera pas supprimée, de sorte que cela ne bloque pas la suppression de la branche.
La version Powershell de git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
git branch --merged master | %{ if($_ -notmatch '\*.*master'){ git branch -d "$($_.Trim())" }}
Cela supprimera toutes les branches locales qui ont été fusionnées dans master, pendant que vous êtes sur la branche master .
git checkout master
pour passer.
Sur la base des réponses ci-dessus, j'utilise ce liner plus court:
git remote prune origin | grep pruned | awk 'BEGIN{FS="/"} ; { print $2 }' | xargs git branch -d
Supprime toute branche qui n'est pas à jour avec master
git co master && git branch | sed s/\*/\ / | xargs git branch -d 2> /dev/null
Je suis sûr que git remote prune origin
est ce que vous voulez.
Vous pouvez l'exécuter comme git remote prune origin --dry-run
pour voir ce queferait sans apporter de modifications.
Utilisation de L'interface graphique? Procédure manuelle, mais rapide et facile.
$ git gui
Sélectionnez "Branche - > Supprimer". Vous pouvez sélectionner plusieurs branches avec ctrl-click (windows) et les supprimer toutes.