Вывод списка каждой ветки и даты последней редакции в Git

144

Мне нужно удалить старые и неподдерживаемые ветки из нашего удаленного репозитория. Я пытаюсь найти способ перечислить удаленные ветки по дате их последнего изменения, но не могу.

Есть ли простой способ таким образом перечислить удаленные ветки?

Рони Янив
источник
3
Ответы на stackoverflow.com/questions/5188320/… все лучше, чем ответы здесь,
инженер-программист,

Ответы:

177

У commandlinefu есть 2 интересных предложения:

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

или:

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

Это для локальных веток в синтаксисе Unix. Используя git branch -r, вы можете аналогично показать удаленные ветки:

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

Майкл Форрест упоминает в комментариях, что zsh требует экранирования для sedвыражения:

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 добавляет в комментариях :

Если вы хотите добавить его в свой zshrc, вам понадобится следующий выход.

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'

В нескольких строках:

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'

Примечание: n8tr «s ответ , основанный на git for-each-ref refs/headsчище. И быстрее .
См. Также « Вариант только имени для git branch --list? »

В более общем смысле, Tripleee напоминает нам в комментариях :

  • Предпочитайте современный $(command substitution)синтаксис устаревшему синтаксису обратных ссылок.

(Я проиллюстрировал этот момент в 2014 году словами «В чем разница между программированием оболочки $(command)и `command`в чем заключается разница ? »)

  • Не читайте строки сfor .
  • Вероятно, переключитесь на, git for-each-ref refs/remoteчтобы получить имена удаленных веток в машиночитаемом формате
VonC
источник
1
@hansen j: интересно, правда? Он был запущен через несколько месяцев после публичного выпуска Stack Overflow ( codeinthehole.com/archives/… ) и был в некоторой степени вдохновлен SO. См. Также commandlinefu.com/commands/tagged/67/git для получения дополнительной информации о git commandlinefu;)
VonC
Этот ответ шокирует stackoverflow.com/questions/5188320/… . :)
Spundun
@SebastianG не уверен: это был бы хороший вопрос сам по себе.
VonC
+1 Замечательно, как вы можете добавить /jsonв конец любого URL-адреса commandlinefu.com, и вы получите все команды в формате JSON.
Ной Сассман
1
@tripleee Спасибо. Я отредактировал ответ и включил ваши комментарии для большей наглядности.
VonC
125

Вот что я использую:

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

Это результат:

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

Для удаленных веток просто используйте «refs / remotes» вместо «refs / Head»:

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

Основываясь на ответе n8tr , если вас также интересует последний автор в ветке, и если у вас есть инструмент «столбец», вы можете использовать:

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

Что даст вам:

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

Вы можете вызвать "git fetch --prune" перед тем, как получить самую свежую информацию.

окрокет
источник
5
Хорошее использование for-each-ref и параметров формата. +1. Звучит проще, чем команды, на которые я ссылаюсь в своем собственном ответе.
VonC
2
небольшая настройка: ------- git for-each-ref --sort = '- authordate: iso8601' --format = '% (authordate: relative)% 09% (refname: short)' refs / Heads ------- дает вам относительную дату и исключает ссылки / головы
n8tr
1
Для тех, кому это не сразу очевидно, я думаю, что это показывает информацию. строго для местных отделений.
hBrent
@hBrent, вы правы, он не дал точного ответа на вопрос. Я соответствующим образом отредактировал свой ответ.
ocroquette
Это сортирует и перечисляет ветки по authordate(что, похоже, было при первом создании ветки?). Если вы измените значение authordateна, committerdateто вы увидите даты самой последней фиксации в каждой ветке. git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads
Вот
24

Основываясь на Olivier Croquette , мне нравится использовать относительную дату и сокращать имя ветки следующим образом:

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

Что дает вам результат:

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

Я рекомендую создать файл Bash для добавления всех ваших любимых псевдонимов, а затем поделиться скриптом с вашей командой. Вот пример, чтобы добавить только этот:

#!/bin/sh

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

Затем вы можете просто сделать это, чтобы получить хорошо отформатированный и отсортированный список локальных веток:

git branches
n8tr
источник
20

Просто чтобы добавить комментарий от @VonC, выберите предпочтительное решение и для удобства добавьте его в список псевдонимов ~ / .gitconfig:

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

Затем простой "git branchdate" распечатает список для вас ...

Ингве
источник
3
+1 за демонстрацию того, как использовать его с .gitconfig! Также fwiw я изменил строку формата на: --format='%(authordate)%09%(objectname:short)%09%(refname)'которая также получает короткий хеш каждой ветки.
Ной Сассман
Ницца. Я бы добавил «| tac» в конец, чтобы отсортировать его в обратном порядке, чтобы ветки, к которым недавно прикасались, были быстро видны.
Бен
1
Вам не нужно | tac, просто --sort='authordate'вместо-authordate
Кристьян
4

Вот что я придумал после того, как просмотрел это .

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_REFПроверка удалить дубликаты , если более чем одна ветвь указывает на то передай. (Как и в локальной ветке, которая существует и на удаленном компьютере.)

ЗАМЕТЬТЕ, что в соответствии с запросом OP git branch --mergedи git branch --no-mergedполезны для определения того, какие ветки можно легко удалить.

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

go2null
источник
3

Отсортированные удаленные ветки и дата последней фиксации для каждой ветки.

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
Спасибо, что ответили на вопрос OP относительно пульта дистанционного управления.
arcseldon
1

Я сделал два варианта, основываясь на ответе VonC .

Мой первый вариант:

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

Это обрабатывает локальные и удаленные ветки ( -a), обрабатывает состояние отдельной головы (более длинная команда sed, хотя решение довольно грубое - она ​​просто заменяет информацию об отключенной ветке ключевым словом HEAD), добавляет в тему фиксации (% s ) и помещает объекты в столбцы с помощью буквальных вертикальных символов в строке формата и передает конечный результат в column -t -s "|". (Вы можете использовать что угодно в качестве разделителя, если этого не ожидаете в остальной части вывода.)

Мой второй вариант довольно хакерский, но я действительно хотел что-то, у кого все еще есть индикатор «это ветка, в которой вы сейчас находитесь», как это делает команда ветки.

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

Это превращает метку, *которая отмечает текущую ветвь, в ключевое слово, и когда тело цикла видит это ключевое слово, оно вместо этого устанавливает флаг и ничего не выводит. Флаг используется, чтобы указать, что для следующей строки следует использовать альтернативное форматирование. Как я уже сказал, это полностью взломано, но это работает! (В основном. По какой-то причине мой последний столбец выходит за пределы текущей ветки.)

Benkc
источник
К сожалению, информация в ответе VonC не является хорошей основой для написания сценариев. См. Здесь git-blame.blogspot.com/2013/06/…
Эндрю Си
Хм. Это показывает способ получить имя текущей ветки, если у нее есть имя. Есть ли [предпочтительный] способ получить удобный для машины список веток? (И какой-то способ отличить текущую ветвь, либо от этого вывода напрямую, либо через вопрос git «это то же самое ref, что и HEAD?»)
benkc 05
git for-each-refэто удобный для скриптов способ обработки ветвей. Вам нужно будет запустить символическую ссылку один раз, чтобы получить текущую ветку.
Andrew C
+1 за усилия, но это действительно был мой старый ответ. stackoverflow.com/a/16971547/6309 или (более полный) stackoverflow.com/a/19585361/6309 может включать меньше sed.
VonC
1

Я сделал простой псевдоним, не уверен, что это именно то, что просили, но это просто

Я сделал это, так как хотел перечислить все ветки, а не только мои локальные ветки, которые выше команды делают только

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

Вы можете перенаправить вверх, grep originчтобы получить только происхождение

В нем перечислены все ветки вместе с последней измененной датой, что помогает мне решить, какую из них мне выбрать для последней версии.

Это приводит к отображению типа ниже

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

Попробуйте и дайте мне знать, помогло ли это, счастливый gitting

Basav
источник
Красиво и просто. Никакого специального соуса.
MrMas
0

Или вы можете использовать мой 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

Вот функцию, которую вы можете добавить в свой bash_profile, чтобы упростить эту задачу.

Использование в репозитории Git:

  • branch печатает все местные отделения
  • branch -r печатает все удаленные ветки

Функция:

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
источник
0

В PowerShell ниже показаны ветки на пульте дистанционного управления, которые уже объединены и имеют возраст не менее двух недель ( author:relativeформат начинает отображать недели вместо дней через две недели):

$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}
Дэйв Нили
источник