Liste de chaque branche et la date de sa dernière révision dans Git

138

Je dois supprimer les anciennes branches non maintenues de notre référentiel distant. J'essaie de trouver un moyen de lister les succursales distantes par leur dernière date de modification, et je ne peux pas.

Existe-t-il un moyen simple de répertorier les branches distantes de cette manière?

Roni Yaniv
la source
3
Les réponses à: stackoverflow.com/questions/5188320/… sont toutes meilleures que les réponses ici
Software Engineer

Réponses:

172

commandlinefu a 2 propositions intéressantes:

for k in `git branch | perl -pe s/^..//`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r

ou:

for k in `git branch | sed s/^..//`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";done | sort

C'est pour les branches locales, dans une syntaxe Unix. En utilisant git branch -r, vous pouvez afficher de la même manière les branches distantes:

for k in `git branch -r | perl -pe 's/^..(.*?)( ->.*)?$/\1/'`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r

Michael Forrest mentionne dans les commentaires que zsh nécessite des échappements pour l' sedexpression:

for k in git branch | perl -pe s\/\^\.\.\/\/; do echo -e git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1\\t$k; done | sort -r 

kontinuity ajoute dans les commentaires :

Si vous voulez l'ajouter à votre zshrc, l'échappement suivant est nécessaire.

alias gbage='for k in `git branch -r | perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r'

En plusieurs lignes:

alias gbage='for k in `git branch -r | \
  perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; \
  do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | \
     head -n 1`\\t$k; done | sort -r'

Remarque: la réponse de n8tr , basée sur est plus propre. Et plus vite . Voir aussi " Option de nom uniquement pour ? "git for-each-ref refs/heads
git branch --list

Plus généralement, tripleee nous rappelle dans les commentaires :

  • Préférez la $(command substitution)syntaxe moderne à la syntaxe de backtick obsolète.

(J'ai illustré ce point en 2014 avec " Quelle est la différence entre $(command)et `command`dans la programmation shell? ")

  • Ne lisez pas les lignes avecfor .
  • Passer probablement à git for-each-ref refs/remotepour obtenir les noms de branche distante au format lisible par machine
VonC
la source
1
@hansen j: intéressant, n'est-ce pas? Il a été lancé quelques mois après la sortie publique de Stack Overflow ( codeinthehole.com/archives/… ), et a été quelque peu inspiré par SO. Voir aussi commandlinefu.com/commands/tagged/67/git pour plus de git commandlinefu;)
VonC
Cette réponse donne un coup de pied au cul de stackoverflow.com/questions/5188320/… . :)
Spundun
@SebastianG pas sûr: ce serait une bonne question en soi.
VonC
+1 Assez génial comment vous pouvez ajouter /jsonà la fin de n'importe quelle URL commandlinefu.com et vous obtiendrez toutes les commandes au format JSON.
Noah Sussman
1
@tripleee Merci. J'ai édité la réponse et inclus vos commentaires pour plus de visibilité.
VonC le
121

Voici ce que j'utilise:

git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads

Voici la sortie:

2014-01-22 11:43:18 +0100       refs/heads/master
2014-01-22 11:43:18 +0100       refs/heads/a
2014-01-17 12:34:01 +0100       refs/heads/b
2014-01-14 15:58:33 +0100       refs/heads/maint
2013-12-11 14:20:06 +0100       refs/heads/d/e
2013-12-09 12:48:04 +0100       refs/heads/f

Pour les branches distantes, utilisez simplement "refs / remotes" au lieu de "refs / heads":

git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/remotes

En vous basant sur la réponse de n8tr , si vous êtes également intéressé par le dernier auteur de la branche, et si vous disposez de l'outil "colonne", vous pouvez utiliser:

git for-each-ref --sort='-committerdate:iso8601' --format='%(committerdate:relative)|%(refname:short)|%(committername)' refs/remotes/ | column -s '|' -t

Ce qui vous donnera:

21 minutes ago  refs/remotes/a        John Doe
6 hours ago     refs/remotes/b        Jane Doe
6 days ago      refs/remotes/master   John Doe

Vous pouvez appeler "git fetch --prune" avant d'avoir les dernières informations.

ocroquette
la source
5
Bonne utilisation de for-each-ref et des options de format. +1. Cela semble plus facile que les commandes auxquelles je fais référence dans ma propre réponse.
VonC
2
peaufiner un peu: ------- git for-each-ref --sort = '- authordate: iso8601' --format = '% (authordate: relative)% 09% (refname: short)' refs / heads ------- vous donne une date relative et élimine les
refs
1
Pour ceux à qui ce n'est pas immédiatement évident, je pense que cela montre des informations. strictement pour les succursales locales.
hBrent
@hBrent vous avez raison, cela n'a pas répondu exactement à la question. J'ai modifié ma réponse en conséquence.
ocroquette
Cela trie et répertorie les branches par authordate(ce qui semble être lorsque la branche a été créée pour la première fois?). Si vous passez authordateà, committerdatevous verrez les dates du dernier commit dans chaque branche. Comme ça:git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads
Logan Besecker
23

À partir d' Olivier Croquette , j'aime utiliser une date relative et raccourcir le nom de la succursale comme ceci:

git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads

Ce qui vous donne une sortie:

21 minutes ago  nathan/a_recent_branch
6 hours ago        master
27 hours ago    nathan/some_other_branch
29 hours ago    branch_c
6 days ago      branch_d

Je recommande de créer un fichier Bash pour ajouter tous vos alias préférés, puis de partager le script avec votre équipe. Voici un exemple pour ajouter seulement celui-ci:

#!/bin/sh

git config --global alias.branches "!echo ' ------------------------------------------------------------' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------'"

Ensuite, vous pouvez simplement le faire pour obtenir une liste de branches locales bien formatée et triée:

git branches
n8tr
la source
20

Juste pour ajouter au commentaire de @VonC, prenez votre solution préférée et ajoutez-la à votre liste d'alias ~ / .gitconfig pour plus de commodité:

[alias]  
    branchdate = !git for-each-ref --sort='-authordate' --format='%(refname)%09%(authordate)' refs/heads | sed -e 's-refs/heads/--'

Puis un simple "git branchdate" imprime la liste pour vous ...

yngve
la source
3
+1 pour montrer comment l'utiliser avec .gitconfig! Aussi, j'ai changé la chaîne de format en: --format='%(authordate)%09%(objectname:short)%09%(refname)'qui récupère également le hachage court de chaque branche.
Noah Sussman
Agréable. J'ajouterais "| tac" à la fin pour le trier dans l'ordre inverse afin que les branches récemment touchées soient rapidement visibles.
Ben
1
Vous n'avez pas besoin de | tac, juste --sort='authordate'au lieu de-authordate
Kristján
4

Voici ce que j'ai trouvé après avoir également examiné cela .

for REF in $(git for-each-ref --sort=-committerdate --format="%(objectname)" \
    refs/remotes refs/heads)
do
    if [ "$PREV_REF" != "$REF" ]; then
        PREV_REF=$REF
        git log -n1 $REF --date=short \
            --pretty=format:"%C(auto)%ad %h%d %s %C(yellow)[%an]%C(reset)"
    fi
done

La PREV_REFvérification consiste à supprimer les doublons si plus d'une branche pointe vers le même commit. (Comme dans une branche locale qui existe également dans la télécommande.)

Notez que par la demande OP, git branch --mergedet git branch --no-mergedsont utiles pour identifier les branches qui peuvent être facilement supprimées.

[ https://git-scm.com/docs/git-branch]

go2null
la source
3

Branches distantes triées et date de la dernière validation pour chaque branche.

for branch in `git branch -r | grep -v HEAD`;do echo -e `git show --format="%ci %cr" $branch | head -n 1` \\t$branch; done | sort -r
shweta
la source
1
Merci d'avoir répondu à la question OP concernant la télécommande.
arcseldon du
1

J'ai fait deux variantes, basées sur la réponse de VonC .

Ma première variante:

for k in `git branch -a | sed -e s/^..// -e 's/(detached from .*)/HEAD/'`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`;done | sort | column -t -s "|"

Cela gère les branches locales et distantes ( -a), gère l'état de tête détachée (la commande sed plus longue, bien que la solution soit un peu grossière - elle remplace simplement les informations de la branche détachée par le mot clé HEAD), ajoute le sujet de validation (% s ), et met les choses dans des colonnes via des caractères de tube littéraux dans la chaîne de format et en passant le résultat final à column -t -s "|". (Vous pouvez utiliser n'importe quoi comme séparateur, du moment que c'est quelque chose que vous ne vous attendez pas dans le reste de la sortie.)

Ma deuxième variante est assez piratée, mais je voulais vraiment quelque chose qui a toujours un indicateur de "c'est la branche sur laquelle vous êtes actuellement" comme le fait la commande branch.

CURRENT_BRANCH=0
for k in `git branch -a | sed -e 's/\*/CURRENT_BRANCH_MARKER/' -e 's/(detached from .*)/HEAD/'`
do
    if [ "$k" == 'CURRENT_BRANCH_MARKER' ]; then
        # Set flag, skip output
        CURRENT_BRANCH=1
    elif [ $CURRENT_BRANCH == 0 ]; then
        echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`
    else
        echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset* %Cgreen$k%Creset |%s" $k --`
        CURRENT_BRANCH=0
    fi
done | sort | column -t -s "|"

Cela transforme le *qui marque la branche actuelle en un mot-clé, et lorsque le corps de la boucle voit le mot-clé, il définit à la place un indicateur et ne produit rien. L'indicateur est utilisé pour indiquer qu'une mise en forme alternative doit être utilisée pour la ligne suivante. Comme je l'ai dit, c'est totalement hacky, mais ça marche! (Surtout. Pour une raison quelconque, ma dernière colonne se fait distancer sur la ligne secondaire actuelle.)

benkc
la source
Malheureusement, les informations contenues dans la réponse de VonCs ne sont pas une bonne base pour la création de scripts. Voir ici git-blame.blogspot.com/2013/06/…
Andrew C
Hmm. Cela montre un moyen d'obtenir le nom de la branche actuelle, si elle a un nom. Existe-t-il un moyen [préféré] d'obtenir une liste de branches conviviale? (Et un moyen de distinguer la branche actuelle, soit à partir de cette sortie directement, soit en demandant d'une manière ou d'une autre à git "est-ce la même référence que HEAD?")
benkc
git for-each-refest la manière conviviale de traiter les branches. Vous devrez exécuter symbolic-ref une fois pour obtenir la branche actuelle.
Andrew C
+1 pour l'effort, mais c'était en effet une vieille réponse à moi. stackoverflow.com/a/16971547/6309 ou (plus complet) stackoverflow.com/a/19585361/6309 peut impliquer moins de «sed».
VonC
1

J'ai fait un simple alias, je ne sais pas si c'est exactement ce que j'ai demandé, mais c'est simple

J'ai fait cela car je voulais lister toutes les branches et pas seulement mes branches locales, ce que les commandes ci-dessus ne font que

alias git_brs="git fetch && git branch -av --format='\''%(authordate)%09%(authordate:relative)%09%(refname)'\'"

Vous pouvez diriger ci-dessus grep originpour obtenir uniquement les origines

Cela répertorie toutes les branches avec la dernière date de modification, m'aide à décider laquelle je dois tirer pour la dernière version

Il en résulte un type d'affichage ci-dessous

Wed Feb 4 23:21:56 2019 +0230   8 days ago      refs/heads/foo
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/heads/master
Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/heads/bar
Wed Feb 11 16:34:00 2019 +0230  2 days ago      refs/heads/xyz
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/HEAD
Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/remotes/origin/foo
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/master
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/bar
Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/xyz

Essayez de me faire savoir si cela a aidé, joyeux gitting

Basav
la source
Sympa et simple. Pas de sauce spéciale.
MrMas le
0

Ou vous pouvez utiliser mon script PHP, https://gist.github.com/2780984

#!/usr/bin/env php
<?php
    $local = exec("git branch | xargs $1");
    $lines = explode(" ", $local);
    $limit = strtotime("-2 week");
    $exclude = array("*", "master");
    foreach ($exclude as $i) {
        $k = array_search($i, $lines);
        unset($lines[$k]);
    }
    $k = 0;
    foreach ($lines as $line) {
        $output[$k]['name'] = $line;
        $output[$k]['time'] = exec('git log '.$line.' --pretty=format:"%at" -1');
        if ($limit>$output[$k]['time']) {
            echo "This branch should be deleted $line\n";
            exec("git branch -d $line");
        }
        $k++;
    }
?>
Ladislav Prskavec
la source
0

Voici une fonction que vous pouvez ajouter à votre bash_profile pour vous faciliter la tâche.

Utilisation dans un référentiel Git:

  • branch imprime toutes les succursales locales
  • branch -r imprime toutes les branches distantes

Fonction:

branch() {
   local pattern="s/^..//"
   local arg=""
   if [[ $@ == "-r" ]]; then
      pattern="s/^..(.*?)( ->.*)?$/\1/"
      arg=" -r "
      echo '-r provided'
   fi
   for k in $(git branch $arg | perl -pe "$pattern"); do
      echo -e $(git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1)\\t$k
   done | sort -r
}
Enderland
la source
0

Dans PowerShell, ce qui suit montre les branches de la télécommande qui sont déjà fusionnées et qui datent d'au moins deux semaines (le author:relativeformat commence à afficher des semaines au lieu de jours à deux semaines):

$safeBranchRegex = "origin/(HEAD|master|develop)$";
$remoteMergedBranches = git branch --remote --merged | %{$_.trim()};
git for-each-ref --sort='authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/remotes | ?{$_ -match "(weeks|months|years) ago" -and $_ -notmatch "origin/(HEAD|master|qa/)"} | %{$_.substring($_.indexof("origin/"))} | ?{$_ -in $remoteMergedBranches}
Dave Neeley
la source