Listando cada filial e a data da última revisão no Git


138

Preciso excluir ramificações antigas e não mantidas do nosso repositório remoto. Estou tentando encontrar uma maneira de listar as ramificações remotas pela data da última modificação, e não consigo.

Existe uma maneira fácil de listar ramificações remotas dessa maneira?



3
As respostas para: stackoverflow.com/questions/5188320/… são todas melhores do que as respostas aqui
Software Engineer

Respostas:


172

commandlinefu tem 2 proposições interessantes:

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

Isso é para ramificações locais, em uma sintaxe Unix. Usando git branch -r, você também pode mostrar ramificações remotas:

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 menciona nos comentários que o zsh requer escapes para a sedexpressão:

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 acrescenta nos comentários :

Se você quiser adicioná-lo ao seu zshrc, é necessário o seguinte escape.

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'

Em várias linhas:

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'

Nota: a resposta do n8tr , baseada em, é mais limpa. E mais rápido . Consulte também " Opção somente nome para ? "git for-each-ref refs/heads
git branch --list

De um modo mais geral, o triplicado nos lembra nos comentários :

  • Prefira $(command substitution)sintaxe moderna a sintaxe obsoleta de backtick.

(Ilustrei esse ponto em 2014 com " Qual é a diferença entre $(command)e `command`na programação de shell? ")

  • Não leia linhas comfor .
  • Provavelmente mude para git for-each-ref refs/remotepara obter nomes de filiais remotas em formato legível por máquina

1
@ Hansen j: interessante, não é? Foi lançado alguns meses após o lançamento público do Stack Overflow ( codeinthehole.com/archives/… ) e foi inspirado pelo SO. Veja também commandlinefu.com/commands/tagged/67/git para obter mais informações sobre o comando git commandlinefu;)
VonC

Esta resposta chuta o traseiro de stackoverflow.com/questions/5188320/… . :)
Spundun

@SebastianG não tenho certeza: isso seria uma boa pergunta por si só.
VonC 07/03

+1 Incrível como você pode adicionar /jsonao final de qualquer URL commandlinefu.com e você receberá todos os comandos como JSON.
Noah Sussman

1
@tripleee Obrigado. Editei a resposta e incluí seus comentários para obter mais visibilidade.
VonC

121

Aqui está o que eu uso:

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

Esta é a saída:

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

Para ramificações remotas, basta usar "refs / remotes" em vez de "refs / heads":

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

Com base na resposta do n8tr , se você também estiver interessado no último autor do ramo e se tiver a ferramenta "coluna" disponível, poderá usar:

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

O que lhe dará:

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

Você pode chamar "git fetch --prune" antes para ter as informações mais recentes.


5
Bom uso das opções for-each-ref e format. +1. Parece mais fácil do que os comandos que refiro na minha própria resposta.
VonC 23/01/19

2
ajustando um pouco: ------- git para-cada-ref --ort = '- authordate: iso8601' --format = '% (authordate: relativo)% 09% (refname: short)' refs / heads ------- fornece uma data relativa e elimina os refs / heads
n8tr

1
Para quem não é imediatamente óbvio, acho que isso mostra informações. estritamente para filiais locais.
Hbrent

@ hBrent você está certo, não respondeu exatamente a pergunta. Eu editei minha resposta de acordo.
Ocroquette

Isso classifica e lista as ramificações por authordate(que parece ser quando a ramificação foi criada pela primeira vez?). Se você alterar authordatepara committerdate, verá as datas da confirmação mais recente em cada ramificação. Assim:git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads
Logan Besecker

23

Com base no Olivier Croquette , eu gosto de usar uma data relativa e encurtar o nome da filial assim:

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

O que fornece saída:

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

Eu recomendo criar um arquivo Bash para adicionar todos os seus aliases favoritos e depois compartilhar o script para sua equipe. Aqui está um exemplo para adicionar apenas este:

#!/bin/sh

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

Em seguida, você pode fazer isso para obter uma lista de filiais locais bem formatada e classificada:

git branches

20

Apenas para adicionar ao comentário do @VonC, pegue sua solução preferida e adicione-a à sua lista de alias ~ / .gitconfig por conveniência:

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

Então um simples "git branchdate" imprime a lista para você ...


3
+1 para mostrar como usá-lo com .gitconfig! Também fwiw mudei a string de formato para: --format='%(authordate)%09%(objectname:short)%09%(refname)'que obtém o hash curto de cada ramificação também.
Noah Sussman

Agradável. Eu adicionaria "| tac" ao final para classificá-lo na ordem inversa, para que os ramos tocados recentemente sejam visíveis rapidamente.
Ben

1
Você não precisa | tac, apenas em --sort='authordate'vez de-authordate
Kristján

4

Aqui está o que eu vim depois de também revisar isso .

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

A PREV_REFverificação é para remover duplicatas se mais de uma ramificação apontar para o mesmo commit. (Como em uma filial local que também existe no controle remoto.)

NOTA de que pelo pedido OP, git branch --mergede git branch --no-mergedsão úteis na identificação de quais ramos podem ser facilmente eliminados.

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


3

Ramificações remotas classificadas e a data da última confirmação para cada ramificação.

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

1
Obrigado por responder a pergunta do OP referente ao controle remoto.
Arcseldon 31/07/2015

1

Eu fiz duas variantes, com base na resposta de VonC .

Minha primeira 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 "|"

Isso lida com branches locais e remotos ( -a), lida com o estado de cabeça destacada (o comando sed mais longo, embora a solução seja meio grosseira - apenas substitui as informações da ramificação desanexada pela palavra-chave HEAD), adiciona o assunto de confirmação (% s ) e coloca as coisas em colunas por meio de caracteres de pipe literal na string de formato e passando o resultado final para column -t -s "|". (Você pode usar o que quer que seja como separador, desde que seja algo que você não espera no restante da saída.)

Minha segunda variante é bastante hacky, mas eu realmente queria algo que ainda tivesse um indicador de "este é o ramo em que você está atualmente", como o comando branch faz.

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 "|"

Isso transforma o *que marca o ramo atual em uma palavra-chave e, quando o corpo do loop vê a palavra-chave, define um sinalizador e não gera nada. O sinalizador é usado para indicar que uma formatação alternativa deve ser usada para a próxima linha. Como eu disse, é totalmente hacky, mas funciona! (Principalmente. Por alguma razão, minha última coluna está sendo superada pela linha de ramo atual.)


Infelizmente, as informações na resposta do VonCs não são uma excelente base para scripts. Veja aqui git-blame.blogspot.com/2013/06/…
Andrew C

Hmm. Isso mostra uma maneira de obter o nome da ramificação atual, se ela tiver um nome. Existe uma maneira [preferida] de obter uma lista de filiais otimizada para máquina? (E de alguma forma para distinguir o ramo atual, seja de que a produção diretamente ou por meio de alguma forma pedindo git "é este o mesmo ref como chefe?")
benkc

git for-each-refé a maneira amigável de script de processar ramificações. Você precisaria executar o simbólico-ref uma vez para obter a ramificação atual.
Andrew C

+1 para o esforço, mas isso foi realmente uma velha resposta da mina. stackoverflow.com/a/16971547/6309 ou (mais completo) stackoverflow.com/a/19585361/6309 pode envolver menos 'sed'.
VonC

1

Eu fiz um alias simples, não tenho certeza se é exatamente isso que foi solicitado, mas é simples

Fiz isso como queria listar todos os ramos, não apenas os ramos locais, que os comandos acima fazem apenas

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

Você pode canalizar acima grep originpara obter apenas origens

Isso lista todos os ramos, juntamente com a última data de modificação, me ajuda a decidir qual deles devo extrair para a versão mais recente

Isso resulta no tipo de exibição abaixo

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

Tente e deixe-me saber se ajudou, feliz


Agradável e simples. Sem molho especial.
MrMas 28/01

0

Ou você pode usar meu 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++;
    }
?>

0

Aqui está uma função que você pode adicionar ao seu bash_profile para facilitar isso.

Uso quando em um repositório Git:

  • branch imprime todas as filiais locais
  • branch -r imprime todas as ramificações remotas

Função:

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
}

0

No PowerShell, o seguinte mostra ramificações no controle remoto que já foram mescladas e com pelo menos duas semanas (o author:relativeformato começa a exibir semanas em vez de dias em duas semanas):

$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}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.