Nettoyage de vieilles branches distantes de Git

694

Je travaille à partir de deux ordinateurs différents (A et B) et stocke une télécommande git commune dans le répertoire dropbox.

Disons que j'ai deux branches, master et devel. Les deux suivent l'origine / le maître et l'origine / le développement de leurs homologues distants.

Maintenant, sur l'ordinateur A, je supprime la branche devel, sur local et distant.

git push origin :heads/devel
git branch -d devel

Fonctionnant git branch -asur l'ordinateur A, j'obtiens la liste de branches suivante.

  • Maître
  • origine / TETE
  • origine / maître

En cours git fetchd' exécution sur l'ordinateur B, je peux supprimer la branche de développement local avec git branch -d devel, mais je ne peux pas supprimer la branche de développement à distance.

git push origin :heads/devel renvoie les messages d'erreur suivants.

erreur: impossible de pousser vers une destination non qualifiée: heads / proxy3d
La spécification de destination ne correspond ni à une référence existante sur la télécommande ni ne commence par refs /, et nous ne pouvons pas deviner un préfixe basé sur la référence source.
fatal: l'extrémité distante a raccroché de façon inattendue

git branch -a répertorie toujours l'origine / le développement dans les branches distantes.

Comment nettoyer les branches distantes de l'ordinateur B?

Jayesh
la source
4
Celui qui l'a essayé m'a dit que les dépôts git dans les dossiers Dropbox sont un peu fragiles (mais sans détails supplémentaires).
Thorbjørn Ravn Andersen
5
@ ThorbjørnRavnAndersen probablement parce que vous devez attendre pour vous assurer qu'il se synchronise complètement chaque fois que vous vous engagez, avant de pouvoir être sûr qu'il peut être utilisé en toute sécurité sur l'autre machine (et une autre synchronisation est nécessaire même dans ce cas).
ataulm

Réponses:

1240

D'abord, quel est le résultat git branch -asur la machine B?

Deuxièmement, vous avez déjà supprimé heads/develsur origin, de sorte que de la raison pour laquelle vous ne pouvez pas le supprimer de la machine B.

Essayer

git branch -r -d origin/devel

ou

git remote prune origin

ou

git fetch origin --prune

et n'hésitez pas à ajouter --dry-runà la fin de votre gitdéclaration pour voir le résultat de son exécution sans l'exécuter réellement.

Documents pour git remote pruneet git branch.

Jakub Narębski
la source
50
git remote prune origintravaillé pour moi => * [pruned] origin/my-old-branch
Hari Karam Singh
126
git remote prune origin --dry-runvous montre ce qui serait supprimé sans le faire.
Wolfram Arnold
30
git fetch origin --pruneétait parfait pour supprimer les branches supprimées
Sébastien Barbieri
10
Si vous avez une succursale locale qui suit une télécommande qui a disparu, cela ne supprimera rien. Pour ceux-ci, il apparaît git branch -vvsuivi degit branch -D branchname et enfin le pruneau est le meilleur moyen.
Roman Starkov
7
Vous pouvez configurer l'élagage pour qu'il se produise automatiquement lors de l'extraction / récupération en définissant l'option suivante: git config remote.origin.prune true
Patrick James McDougle
100

Pensez à exécuter:

git fetch --prune

Régulièrement dans chaque référentiel pour supprimer les branches locales qui ont suivi une branche distante qui est supprimée (n'existe plus dans le référentiel GIT distant).

Cela peut être encore simplifié en

git config remote.origin.prune true

il s'agit d'un per-repoparamètre qui permettra à tout futur git fetch or git pullde tailler automatiquement .

Pour configurer cela pour votre utilisateur, vous pouvez également modifier le .gitconfig global et ajouter

[fetch]
    prune = true

Cependant, il est recommandé de le faire à l'aide de la commande suivante:

git config --global fetch.prune true

ou pour l'appliquer à l'échelle du système (pas seulement pour l'utilisateur)

git config --system fetch.prune true
Arif
la source
14

Voici un script bash qui peut le faire pour vous. Il s'agit d'une version modifiée du script http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git . Ma modification lui permet de prendre en charge différents emplacements distants.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi
Alex Amiryan
la source
1
Cela a éclaté sur une branche appelée "origine / fonctionnalité / ma branche", je ne sais pas pourquoi.
Stavros Korokithakis
Le problème réside dans les deux seds. Remplacer sed 's/\(.*\)\/\(.*\)/\1/g'parsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier
14

Cette commande "exécutera à sec" supprimera toutes les originbranches fusionnées distantes ( ), à l'exception de master. Vous pouvez changer cela ou ajouter des branches supplémentaires après le maître:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

S'il semble bon, retirez le --dry-run. De plus, vous pouvez d'abord tester cela sur une fourche.

weston
la source
Agréable. Mon tweak utilisant perl au lieu du 1er xargs + awk: git branch -r --merged | origine grep | grep -v '>' | grep -v master | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Andrew
6

Si git branch -raffiche un grand nombre de branches de suivi à distance qui ne vous intéressent pas et que vous souhaitez les supprimer uniquement du local, utilisez la commande suivante:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Une version plus sûre serait de supprimer uniquement les fusionnées:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Cela peut être utile pour les grands projets, où vous n'avez pas besoin des branches de fonctionnalités des autres coéquipiers, mais il existe de nombreuses branches de suivi à distance récupérées sur le clone initial.

Cependant, cette étape seule n'est pas suffisante, car ces branches de suivi à distance supprimées reviendraient lors de la prochaine git fetch .

Pour arrêter de récupérer ces branches de suivi à distance, vous devez spécifier explicitement les références à récupérer dans .git / config :

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

Dans l'exemple ci - dessus , nous ne récupérons master, developet libérer des branches, ne hésitez pas à adapter selon vos besoins.

ryenus
la source
1
Merci, la première commande a fonctionné pour moi. Vous pouvez également récupérer une seule branche avec git fetch origin branchnameou créer un alias comme ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"pour récupérer uniquement la branche actuelle (mon favori personnel). À votre santé.
GiovanyMoreno
Peut-être OT, mais que signifie le -rdrapeau? Je vois xargsa un -Rargument mais n'a rien trouvé -r. Je veux dire, en théorie, si je me souviens bien du xargsfonctionnement, même sans que -rcela fonctionne.
Aldo 'xoen' Giambelluca
J'aime cette réponse. Quelques notes (énonçant vraiment l'évidence). Il est possible de "prévisualiser" les branches qui vont être supprimées en supprimant le dernier canal et la dernière commande | xargs git branch -d. De plus, en supprimant l' -roption ( --remotes) de git branch -dnous ne nettoyons que les branches locales (ce qui peut être suffisant étant donné que par défaut git branchn'affiche pas les branches distantes de toute façon).
Aldo 'xoen' Giambelluca
Merci! C'était exactement ce dont j'avais besoin. D'autres solutions suggèrent de pousser les branches locales élaguées vers la télécommande pour les y supprimer également, mais cela n'aide pas lorsque la télécommande a été supprimée ou n'existe plus. Cette approche a supprimé les références locales aux branches distantes auxquelles je n'ai plus accès.
cautionbug
@aldo, à propos xargs -r, à savoir --no-run-if-empty, c'est une extension GNU, voici une belle explication .
ryenus
4

La suppression est toujours une tâche difficile et peut être dangereuse !!! Par conséquent, exécutez d'abord la commande suivante pour voir ce qui va se passer:

git push --all --prune --dry-run

En faisant cela comme ci-dessus, git obtiendrez une liste de ce qui se passerait si la commande ci-dessous était exécutée.

Exécutez ensuite la commande suivante pour supprimer toutes les branches du référentiel distant qui ne se trouvent pas dans votre référentiel local:

git push --all --prune
Timothy LJ Stewart
la source
10
Cette commande semble dangereuse ... Elle a réussi à supprimer ce que je voulais (et n'a pas pu faire avec au moins quatre des réponses ci-dessus). Mais il a également supprimé quatre autres branches de développement. Git suce absolument ...
Jww
2
Ces succursales ne devaient pas se trouver dans votre section locale. Cependant, tout n'est pas perdu. Git commit, Git reflog puis git reset --hard <checksum>. Vous pouvez littéralement effectuer n'importe quel commit (ou enregistrer) et d'autres avec cela. La branche n'est qu'une étiquette, la suppression de l'étiquette ne supprime pas la sauvegarde ... elle aura toujours une somme de contrôle. Faites-moi savoir si je peux vous aider
Timothy LJ Stewart
3
Bien sûr, vous voudrez les récupérer assez rapidement car le garbage collector de git supprimera éventuellement les commits non référencés par les branches.
Andrew
1
Il est bon d'ajouter -n(exécution à sec) à cette commande afin que vous puissiez prévisualiser les modifications, puis si tout va bien, appelez-le à nouveau sans -n.
mati865
1
D'accord avec @GuiWeinmann - C'est trop dangereux, en particulier sans un appel spécifique pour au moins exécuter cela en mode sec en premier.
Vivek M. Chawla
2

Voici comment le faire avec SourceTree (v2.3.1):
1. Cliquez sur Récupérer
2. Cochez "Tailler les branches de suivi ..."
3. Appuyez sur OK
4. 😀

entrez la description de l'image ici

coco
la source
1

Je vais devoir ajouter une réponse ici, car les autres réponses ne couvrent pas mon cas ou sont inutilement compliquées. J'utilise github avec d'autres développeurs et je veux juste que toutes les branches locales dont les télécommandes ont été (éventuellement fusionnées et) supprimées d'un github PR soient supprimées en une seule fois de ma machine. Non, des choses comme git branch -r --mergedne couvrent pas les branches qui n'ont pas été fusionnées localement, ou celles qui n'ont pas du tout été fusionnées (abandonnées), etc., une solution différente est donc nécessaire.

Quoi qu'il en soit, la première étape, je l'ai obtenue à partir d'autres réponses:

git fetch --prune

Un essai à sec git remote prune originsemblait faire la même chose dans mon cas, j'ai donc opté pour la version la plus courte pour rester simple.

Maintenant, un git branch -vdevrait marquer les branches dont les télécommandes sont supprimées comme [gone]. Par conséquent, tout ce que je dois faire est de:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

Aussi simple que cela, il supprime tout ce que je veux pour le scénario ci-dessus.

La xargssyntaxe la moins courante est qu'elle fonctionne également sur Mac et BSD en plus de Linux. Attention, cette commande n'est pas un run à sec donc elle va forcer-supprimer toutes les branches marquées comme [gone]. Évidemment, cela étant rien ne disparaît pour toujours, si vous voyez des branches supprimées dont vous vous souvenez que vous vouliez les conserver, vous pouvez toujours les supprimer (la commande ci-dessus aura répertorié leur hachage lors de la suppression, donc simple) git checkout -b <branch> <hash>.

Équateur
la source
0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

Taillez les mêmes branches à partir des références locales et distantes (dans mon exemple de origin).

Jan Winter
la source