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

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

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


person Roni Yaniv    schedule 25.03.2010    source источник
comment
comment
Ответы на: заголовок stackoverflow.com/questions/5188320/ все лучше, чем ответы здесь   -  person Software Engineer    schedule 16.03.2016


Ответы (11)


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

or:

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, вам понадобится следующий 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'

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

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"> n8tr"> n8tr">, основанный на git for-each-ref refs/heads, чище. И быстрее.
См. также " Параметр" Только имя "для git branch --list?"

В более общем плане tripleee напоминает нам в комментариях:

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

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

  • Не читайте строки с for.
  • Возможно, переключитесь на git for-each-ref refs/remote, чтобы получить имена удаленных веток в машиночитаемом формате
person VonC    schedule 25.03.2010
comment
@hansen j: интересно, правда? Он был запущен через несколько месяцев после публичного выпуска Stack Overflow (codeinthehole.com/archives/) и был несколько вдохновлен SO. См. Также commandlinefu.com/commands/tagged/67/git для получения дополнительных сведений о git. commandlinefu;) - person VonC; 26.03.2010
comment
Этот ответ вызывает жопа stackoverflow.com/questions/5188320/. :) - person Spundun; 25.01.2013
comment
@SebastianG не уверен: это был бы хороший вопрос сам по себе. - person VonC; 07.03.2013
comment
+1 Замечательно, как вы можете добавить /json в конец любого URL-адреса commandlinefu.com, и вы получите все команды как JSON. - person Noah Sussman; 06.04.2013
comment
Есть идеи, почему я получаю zsh: no matches found: s/^..// при запуске? - person Michael Forrest; 19.09.2013
comment
О, по-видимому, zsh разбирает регулярное выражение. Я заставил его работать, ускользнув от всего ... for k in git branch | perl -pe s\/\^\.\.\/\/; сделать echo -e _2 _ \\ t $ k; сделано | sort -r - person Michael Forrest; 19.09.2013
comment
@MichaelForrest Интересно. Я включил ваш комментарий в ответ для большей наглядности. - person VonC; 19.09.2013
comment
Это здорово и почти то, что я хочу. Однако он подавляется (отсоединяется от xyz), что является той ситуацией, в которой я, скорее всего, захочу эту команду; и я бы хотел, чтобы он использовал цветовой код (или иным образом указывал) текущие, локальные и удаленные ветки, как это делает git branch -av. Хммм .... [начинает поправлять] - person benkc; 05.11.2014
comment
Исправить (отделенный от xyz) было достаточно просто, настроив первую команду sed на sed -e s/^..// -e 's/(detached from \(.*\))/\1/'. Затем я отвлекся, пытаясь включить тему коммита, похожую на git branch -v, что легко, но разумное ее разбиение потребует, как мне кажется, освежить свой awk. Столбцы, содержащие пробелы, - это сложно, не так ли? - person benkc; 06.11.2014
comment
Второй кажется быстрее первого (из тех, которые показывают все ветки - третий не показывает ветки с точкой в ​​своем имени). - person pevik; 19.01.2015
comment
Если вы хотите добавить его в свой zshrc, вам понадобится следующий 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' - person kontinuity; 23.08.2016
comment
@kontinuity Отлично, спасибо. Я включил ваш комментарий в ответ для большей наглядности. - person VonC; 23.08.2016
comment
Интересно, но неудивительно и несколько удручающе, что commandlinefu, похоже, разрастает целую лодку антипаттернов программирования оболочки. - person tripleee; 13.02.2020
comment
@tripleee Я был бы признателен за изменение этого моего ответа 2010 года. Я тогда был молодым дураком (я до сих пор дурак, заметьте, просто постарше) ಠ﹏ಠ - person VonC; 13.02.2020
comment
Я не могу комментировать части zsh, но я буду счастлив провести капитальный ремонт общего сценария оболочки, хотя тогда ссылки на commandlinefu и т. Д. Будут в некоторой степени недействительными. Подумывал выложить отдельный ответ с рефакторингом; может мне стоит просто сделать это и пометить это как вики сообщества, и предоставить вам, может быть, взять части или все это? - person tripleee; 13.02.2020
comment
@tripleee Конечно, я могу сослаться на ваш ответ в своем ответе. Не нужно отмечать это вики сообщества. - person VonC; 13.02.2020
comment
В конечном итоге я заново изобрел ответ n8tr, поэтому я просто оставлю несколько подсказок. Предпочитайте современный $(command substitution) синтаксис устаревшему синтаксису обратных ссылок. Не читайте строки с for. Вероятно, переключитесь на _ 3_, чтобы получить имена удаленных веток в машиночитаемом формате. - person tripleee; 13.02.2020
comment
@tripleee Спасибо. Я отредактировал ответ и включил ваши комментарии для большей наглядности. - person VonC; 13.02.2020

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

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" перед тем, как получить самую свежую информацию.

person ocroquette    schedule 23.01.2014
comment
Хорошее использование for-each-ref и параметров формата. +1. Звучит проще, чем команды, на которые я ссылаюсь в своем собственном ответе. - person VonC; 23.01.2014
comment
небольшая настройка: ------- git for-each-ref --sort = '- authordate: iso8601' --format = '% (authordate: relative)% 09% (refname: short)' refs / Heads ------- дает относительную дату и исключает ссылки / головы - person n8tr; 29.05.2014
comment
Для тех, кому это не сразу очевидно, я думаю, что это показывает информацию. строго для местных отделений. - person hBrent; 23.07.2016
comment
@hBrent, вы правы, он не дал точного ответа на вопрос. Я соответствующим образом отредактировал свой ответ. - person ocroquette; 24.07.2016
comment
Это сортирует и перечисляет ветки по authordate (что, похоже, было при первом создании ветки?). Если вы измените authordate на committerdate, вы увидите даты самого последнего коммита в каждой ветке. Вот так: git for-each-ref --sort='-committerdate:iso8601' --format=' %(committerdate:iso8601)%09%(refname)' refs/heads - person Logan Besecker; 09.02.2017
comment
Для большинства коммитов даты автора и коммита совпадают, но это не всегда так. Наиболее очевидным является выбор изменения: исходная дата автора сохраняется по умолчанию, но дата фиксации установлена ​​на «сейчас». В этих случаях дата фиксации действительно более полезна, чем дата автора, чтобы судить об активности в ветке, поэтому я обновил команды, чтобы использовать данные фиксации. Спасибо, что подняли этот вопрос! - person ocroquette; 10.02.2017

Создание 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
person n8tr    schedule 29.05.2014

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

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

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

person yngve    schedule 27.02.2013
comment
+1 за демонстрацию того, как использовать его с .gitconfig! Также fwiw я изменил строку формата на: --format='%(authordate)%09%(objectname:short)%09%(refname)', который также получает короткий хеш каждой ветки. - person Noah Sussman; 04.04.2013
comment
Хороший. Я бы добавил | tac до конца, чтобы отсортировать его в обратном порядке, чтобы быстро были видны недавно затронутые ветви. - person Ben; 01.10.2013
comment
Вам не нужно | tac, просто --sort='authordate' вместо -authordate - person Kristján; 01.12.2015

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

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

person go2null    schedule 18.06.2015

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

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

Я сделал два варианта на основе 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 "|"

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

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

В 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}
person Dave Neeley    schedule 24.01.2017

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

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

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

person Basav    schedule 12.12.2019
comment
Красиво и просто. Никакого специального соуса. - person MrMas; 28.01.2020

Или вы можете использовать мой сценарий 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++;
    }
?>
person Ladislav Prskavec    schedule 24.05.2012

Вот функцию, которую вы можете добавить в свой 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
}
person enderland    schedule 14.03.2016