web-dev-qa-db-fra.com

Lister toutes les branches locales sans télécommande

Problème: je veux un moyen de supprimer toutes les branches locales que j'ai qui n’ont pas de télécommande. Il est assez facile de canaliser les noms des branches dans un git branch -D {branch_name}, mais comment puis-je obtenir cette liste en premier lieu?

Par exemple:

Je crée une nouvelle branche sans télécommande:

$ git co -b no_upstream

Je liste toutes mes branches, il n'y en a qu'une avec une télécommande

$ git branch -a
master
* no_upstream
remotes/Origin/HEAD -> Origin/master
remotes/Origin/master

Quelle commande puis-je exécuter pour obtenir no_upstream comme réponse?

Je peux exécuter git rev-parse --abbrev-ref --symbolic-full-name @{u} et cela montrera qu'il n'a pas de télécommande:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Mais comme il s’agit d’une erreur, cela ne me permettra pas de l’utiliser ni de le diriger vers d’autres commandes. J'ai l'intention de l'utiliser comme un script Shell alias'd de git-delete-unbranched ou peut-être créer un bijou très simple comme git-branch-delete-orphans

Toute aide serait appréciée! Merci

54
JC Denton

J'ai récemment découvert git branch -vv qui est la version "très détaillée" de la commande git branch.

Il génère les branches avec les branches distantes si elles existent, au format suivant:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [Origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [Origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

Une fois que vous avez cette sortie joliment formatée, il vous suffit simplement de la glisser dans cut et awk pour obtenir votre liste:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

Résultats dans la sortie suivante:

25-timeout-error-with-many-targets
65-digest-double-publish

La partie cut normalise simplement les données en supprimant les deux premiers caractères (y compris *) de la sortie avant de les transmettre à awk

La partie awk imprime la première colonne s'il n'y a pas de crochet entre la troisième colonne.

Bonus: créer un alias

Facilitez l’exécution en créant un alias dans votre fichier global .gitconfig (ou ailleurs):

[alias]
  local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'

Important: La barre oblique inverse doit être échappée dans l'alias sinon vous aurez un fichier gitconfig non valide.

Bonus: Filtrage à distance

Si, pour une raison quelconque, vous disposez de plusieurs télécommandes de suivi pour différentes branches, il est assez facile de spécifier la télécommande sur laquelle vous souhaitez effectuer le contrôle. Il suffit d'ajouter le nom de la télécommande au modèle awk. Dans mon cas, c'est Origin pour que je puisse faire ceci:

git branch -vv | cut -c 3- | awk '$3 !~/\[Origin/ { print $1 }'
64
Jeremy Baker

git branch (sans aucune option) répertorie uniquement les branches locales, mais vous ne savez pas si elles suivent ou non une branche distante.

Habituellement, ces branches locales devraient être supprimées une fois fusionnées dans master (comme indiqué dans ce numéro de git-sweep ):

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

Ce n'est pas aussi complet que vous voulez, mais c'est un début.

Avec --merged, seules les branches fusionnées dans la validation nommée (c’est-à-dire les branches dont les validations des astuces sont accessibles à partir de la validation nommée) seront répertoriées.

24
VonC

Édition tardive: mieux c'est 

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

sur GNU/n'importe quoi

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

S'il y avait probablement plus d'une poignée de branches, il y aurait de meilleures façons, en utilisant comm -23 sur la sortie de git branch|sed|sort et git config -l|sed|sort.

14
jthill

J'ai un problème similaire. Je veux supprimer toutes les branches locales qui suivaient les branches distantes qui sont maintenant supprimées. Je trouve que git remote Prune Origin était insuffisant pour supprimer les branches que je voulais disparaître. Une fois la télécommande supprimée, je veux que le local s’éloigne aussi. Voici ce qui a fonctionné pour moi:

De mon ~/.gitconfig:

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

EDIT: Comme demandé, 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'

NOTE: J'ai changé le -d en -D dans ma configuration réelle car je ne veux pas entendre Git se plaindre des branches non fusionnées. Vous pouvez voulez aussi cette fonctionnalité. Si c'est le cas, utilisez simplement -D au lieu de -d à la fin de cette commande.

En outre, FWIW, votre fichier de configuration global serait presque toujours ~/.gitconfig.

EDIT: (Correctif OSX) Tel qu'écrit, cela ne fonctionne pas sous OSX à cause de l'utilisation de xargs -r (merci, Korny ). 

Le -r permet d'empêcher xargs d'exécuter git branch -d sans nom de branche, ce qui entraînera un message d'erreur "fatal: branch name required". Si le message d'erreur ne vous dérange pas, vous pouvez simplement supprimer l'argument -r en xargs et le tour est joué. 

Cependant, si vous ne voulez pas voir un message d'erreur (et qui peut vraiment vous en vouloir), vous aurez besoin de quelque chose d'autre qui vérifie si un tuyau est vide. Si vous pouvez utiliser ifne de moreutils . Vous devez insérer ifne avant xargs, ce qui empêchera xargs de s'exécuter avec des données vides. NOTE: ifne considère que rien n'est pas vide, cela inclut les lignes vides, vous pouvez donc toujours voir ce message d'erreur. Je n'ai pas testé cela sur OSX. 

Voici cette ligne git config avec ifne:

git config --global alias.Prune-branches '!git remote Prune Origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'
13
Karl Wilbur

Cela fonctionne pour moi:

git branch -vv | grep -v Origin 

(Si votre télécommande porte un nom autre que Origin, remplacez-le).

Ceci listera toutes les branches qui ne suivent pas une télécommande, ce qui ressemble à ce que vous recherchez.

11
ebr

Mise en oeuvre de powershell brute: (si Origin est votre seule télécommande)

@($branches = git br -r; git branch | %{ echo $_ | sed 's/..//' }) `
   | %{ if (($branches | ss "Origin/$_") -eq $null) { `
          echo "git branch -D $_" `
        } `
      }
2
nbergen

Voici quelque chose que j'ai utilisé dans PowerShell avec des commentaires pour expliquer son travail. Pour tenter de clarifier ce qui se passe, je n'ai utilisé aucune commande PS abrégée. N'hésitez pas à le compresser au niveau de cryptage souhaité :)

$verboseList = @(git br -vv)
foreach ($line in $verboseList)
{    
    #get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    #check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    #check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[Origin/"))
    if ($remoteGone -or $isLocal)
    {
        #print the branch name
        $branch
    }
}
2
grahamesd

Je sinthetize ma propre commande git pour obtenir les branches Origin/***: gone:

git remote Prune Origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote Prune Origin && git branch -vv imprimera les branches en mode prolixe

cut -c 3- enlèvera les tout premiers caractères

grep ': gone]' imprimera uniquement les branches gone remote 

awk '{print $1}' imprimera le nom de la succursale

xargs -n1 -r echo git branch -d imprimera la commande git branch -d pour supprimer les branches (-n1 gérera une commande par heure, -r pour éviter d'émettre une commande si aucune branche n'est présente)

ASTUCE: supprimer la commande "echo" pour exécuter les commandes au lieu de n'imprimer que, j'ai laissé cela dans la commande pour vérifier les commandes avant d'envoyer à git.

CONSEIL 2: émettez git branch -D si et seulement si vous êtes sûr de vouloir supprimer les branches non fusionnées

0
fiorentinoing