Wymienienie każdej gałęzi i daty jej ostatniej wersji w Git

138

Muszę usunąć stare i nieobsługiwane gałęzie z naszego zdalnego repozytorium. Próbuję znaleźć sposób na wyświetlenie zdalnych oddziałów według daty ich ostatniej modyfikacji, ale nie mogę.

Czy istnieje łatwy sposób na utworzenie listy zdalnych oddziałów w ten sposób?

Roni Yaniv
źródło
3
Odpowiedzi na: stackoverflow.com/questions/5188320/ ... są lepsze niż odpowiedzi tutaj
Software Engineer

Odpowiedzi:

172

commandlinefu ma 2 ciekawe propozycje:

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

lub:

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

To jest dla lokalnych oddziałów, w składni Unix. Używając git branch -r, możesz w podobny sposób pokazać zdalne gałęzie:

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 wspomina w komentarzach, że zsh wymaga znaków ucieczki dla sedwyrażenia:

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 dodaje w komentarzach :

Jeśli chcesz dodać go do swojego zshrc, potrzebna jest następująca ucieczka.

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'

W wielu wierszach:

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'

Uwaga: n8tr jest odpowiedź , na podstawie git for-each-ref refs/headsjest czystsze. I szybciej .
Zobacz także „ Opcja Tylko nazwa dla git branch --list?

Mówiąc bardziej ogólnie, tripleee przypomina nam w komentarzach :

  • Preferuj nowoczesną $(command substitution)składnię zamiast przestarzałej składni odwrotnych znaczników.

(Zilustrowałem ten punkt w 2014 r. Za pomocą „ Jaka jest różnica między programowaniem powłoki $(command)i `command`w programie? ”)

  • Nie czytaj wierszy zfor .
  • Prawdopodobnie przełącz się na, git for-each-ref refs/remoteaby uzyskać nazwy zdalnych gałęzi w formacie do odczytu maszynowego
VonC
źródło
1
@hansen j: interesujące, prawda? Został uruchomiony kilka miesięcy po publicznym wydaniu Stack Overflow ( codeinthehole.com/archives/… ) i był nieco zainspirowany SO. Zobacz także commandlinefu.com/commands/tagged/67/git po więcej git commandlinefu;)
VonC
Ta odpowiedź kopie dupę stackoverflow.com/questions/5188320/… . :)
Spundun
@SebastianG nie jestem pewien: to byłoby dobre pytanie samo w sobie.
VonC
+1 Całkiem niesamowite, jak możesz dodać /jsonna końcu dowolnego adresu URL commandlinefu.com, a otrzymasz wszystkie polecenia jako JSON.
Noah Sussman
1
@tripleee Dziękuję. Zredagowałem odpowiedź i dołączyłem twoje komentarze, aby były bardziej widoczne.
VonC
121

Oto czego używam:

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

Oto wynik:

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

W przypadku oddziałów zdalnych użyj po prostu „refs / remotes” zamiast „refs / heads”:

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

Opierając się na odpowiedzi n8tr , jeśli interesuje Cię również ostatni autor w branży i masz dostępne narzędzie "kolumnowe", możesz użyć:

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

Co da ci:

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

Możesz wcześniej wywołać „git fetch --prune”, aby uzyskać najnowsze informacje.

ocroquette
źródło
5
Niezłe użycie for-each-ref i opcji formatu. +1. Brzmi łatwiej niż polecenia, do których odwołuję się w mojej odpowiedzi.
VonC,
2
trochę poprawiać: ------- git for-each-ref --sort = '- authordate: iso8601' --format = '% (authordate: względna)% 09% (refname: short)' refs / heads ------- podaje względną datę i eliminuje
sędziów
1
Dla tych, dla których nie jest to od razu oczywiste, myślę, że to pokazuje informacje. wyłącznie dla lokalnych oddziałów.
hBrent
@hBrent masz rację, nie odpowiedział dokładnie na pytanie. Odpowiednio zredagowałem odpowiedź.
ocroquette
Sortuje i wyświetla gałęzie według authordate(co wygląda na to, że gałąź została utworzona po raz pierwszy?). Jeśli zmienisz authordatena committerdate, zobaczysz daty ostatniego zatwierdzenia w każdej gałęzi. Na przykład:git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads
Logan Besecker
23

Opierając się na Olivier Croquette , lubię używać względnej daty i skracać nazwę oddziału w następujący sposób:

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

Co daje wynik:

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

Zalecam utworzenie pliku Bash w celu dodania wszystkich ulubionych aliasów, a następnie udostępnienie skryptu zespołowi. Oto przykład, aby dodać tylko ten:

#!/bin/sh

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

Następnie możesz to zrobić, aby uzyskać ładnie sformatowaną i posortowaną listę lokalnych oddziałów:

git branches
n8tr
źródło
20

Aby dodać do komentarza @VonC, wybierz preferowane rozwiązanie i dodaj je do swojej listy aliasów ~ / .gitconfig dla wygody:

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

Następnie prosta „git branchdate” wyświetla listę za Ciebie ...

yngve
źródło
3
+1 za pokazanie, jak go używać z .gitconfig! Również fwiw Zmieniłem ciąg formatu na: --format='%(authordate)%09%(objectname:short)%09%(refname)'który również pobiera krótki skrót każdej gałęzi.
Noah Sussman
Miły. Dodałbym "| tac" na końcu, aby posortować go w odwrotnej kolejności, tak aby niedawno dotknięte gałęzie były szybko widoczne.
Ben
1
Nie musisz | tac, tylko --sort='authordate'zamiast-authordate
Kristján
4

Oto, co wymyśliłem po przejrzeniu tego .

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

PREV_REFWyboru jest usunąć duplikaty, jeśli więcej niż jeden punkty odgałęzienia do tej samej popełnić. (Podobnie jak w lokalnym oddziale, który istnieje również w zdalnym).

PAMIĘTAJ, że zgodnie z żądaniem OP git branch --mergedi git branch --no-mergedsą przydatne w identyfikowaniu oddziałów, które można łatwo usunąć.

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

go2null
źródło
3

Posortowane zdalne gałęzie i data ostatniego zatwierdzenia dla każdej gałęzi.

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
źródło
1
Dziękuję za odpowiedź na pytanie OP dotyczące pilota.
arcseldon
1

Zrobiłem dwa warianty w oparciu o odpowiedź VonC .

Mój pierwszy wariant:

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

Obsługuje lokalne i zdalne gałęzie ( -a), obsługuje stan odłączonej głowy (dłuższe polecenie sed, chociaż rozwiązanie jest trochę prymitywne - po prostu zastępuje informacje o odłączonej gałęzi słowem kluczowym HEAD), dodaje w zatwierdzeniu temat (% s ), i umieszcza rzeczy w kolumnach za pomocą znaków potoku dosłownego w ciągu formatu i przekazuje wynik końcowy do column -t -s "|". (Możesz użyć dowolnego separatora, o ile jest to coś, czego nie oczekujesz w pozostałej części wyniku).

Mój drugi wariant jest dość hakerski, ale naprawdę chciałem czegoś, co nadal ma wskaźnik „to jest gałąź, na której aktualnie jesteś”, tak jak robi to polecenie gałęzi.

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

Powoduje to, *że that oznacza bieżącą gałąź w słowo kluczowe, a gdy treść pętli widzi słowo kluczowe, zamiast tego ustawia flagę i nic nie wyświetla. Flaga jest używana do wskazania, że ​​dla następnego wiersza należy zastosować inne formatowanie. Jak powiedziałem, jest to totalnie hacky, ale działa! (Przeważnie. Z jakiegoś powodu moja ostatnia kolumna staje się nieaktualna w bieżącej linii gałęzi).

benkc
źródło
Niestety informacje zawarte w odpowiedzi VonC nie stanowią doskonałej podstawy do tworzenia skryptów. Zobacz tutaj git-blame.blogspot.com/2013/06/…
Andrew C
Hmm. To pokazuje sposób na uzyskanie nazwy bieżącej gałęzi, jeśli ma nazwę. Czy istnieje [preferowany] sposób uzyskania listy oddziałów przyjaznej dla komputera? (I w jakiś sposób można odróżnić bieżącą gałąź, albo bezpośrednio od tego wyjścia, albo poprzez pytanie git „czy to jest to samo odniesienie co HEAD?”)
benkc
git for-each-refto przyjazny dla skryptów sposób przetwarzania gałęzi. Musisz raz uruchomić symbolic-ref, aby uzyskać aktualną gałąź.
Andrew C
+1 za wysiłek, ale to była rzeczywiście moja stara odpowiedź. stackoverflow.com/a/16971547/6309 lub (bardziej kompletny) stackoverflow.com/a/19585361/6309 może obejmować mniej „sed”.
VonC
1

Zrobiłem prosty alias, nie jestem pewien, czy dokładnie o to pytałem, ale jest prosty

Zrobiłem to, ponieważ chciałem wyświetlić wszystkie gałęzie, a nie tylko moje lokalne gałęzie, które robią tylko powyższe polecenia

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

Możesz przejść wyżej do, grep originaby uzyskać tylko źródła

Wyświetla wszystkie gałęzie wraz z datą ostatniej modyfikacji, pomaga mi zdecydować, który z nich powinienem pobrać dla najnowszej wersji

Skutkuje to poniższym typem wyświetlania

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

Spróbuj i daj mi znać, jeśli to pomogło, szczęśliwy gitting

Basav
źródło
Ładnie i prosto. Bez specjalnego sosu.
MrMas
0

Lub możesz użyć mojego skryptu 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
źródło
0

Oto funkcja, którą możesz dodać do swojego bash_profile, aby to ułatwić.

Użycie w repozytorium Git:

  • branch drukuje wszystkie lokalne oddziały
  • branch -r wypisuje wszystkie zdalne gałęzie

Funkcjonować:

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
źródło
0

W programie PowerShell poniżej przedstawiono gałęzie na pilocie, które są już scalone i mają co najmniej dwa tygodnie ( author:relativeformat zaczyna wyświetlać tygodnie zamiast dni po dwóch tygodniach):

$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
źródło