Подтвердить что ты не робот

Получение git ветвей определенного возраста

Моя организация широко использует разветвление git. В результате за последний год мы выпустили более 2000 веток. Сейчас мы пытаемся принять стратегию для очистки всех старых ветвей, которые имеют определенный возраст. Я знаю, как удалять ветки, но я не могу найти простой способ перечислить все ветки с головами определенного возраста. Планируется создать cron, который периодически удаляет все ветки определенного возраста, кроме тех, которые находятся в каком-то списке.

Кто-нибудь пробовал что-нибудь подобное раньше?

4b9b3361

Ответ 1

Ответы, использующие даты коммиттера, являются хорошим направлением... если вы хотите удалить ветки, указывающие на старые коммиты. Но вы можете удалить ветки, которые на самом деле старые; если вы создаете ветку сегодня, указывая на фиксацию с прошлого года, вы не хотите, чтобы она стиралась!

Итак, вы хотите проверить даты reflog вместо.

Вы можете получить удобочитаемую форму с помощью git reflog show --date=local mybranch:

8b733bc [email protected]{Tue Mar 22 13:21:49 2011}: commit: foo
7e36e81 [email protected]{Tue Mar 22 13:21:25 2011}: commit: bar
99803da [email protected]{Tue Mar 22 13:20:45 2011}: branch: Created from otherbranch

(Вам также может понравиться --date=relative)

Запись в верхней части - это самое последнее, что произошло на этой ветке, так что бит, о котором мы заботимся. К сожалению, нет места для формата журнала только для даты, поэтому, чтобы вытащить только дату, мы немного поработаем:

git log -g -n 1 --date=local --pretty=%gd mybranch | sed 's/.*{\(.*\)}/\1/'
# Prints "Mon Mar 21 13:23:26 2011"

Конечно, для сценариев это не очень полезно, поэтому отпустите и получите время в эпоху:

git log -g -n 1 --date=raw --pretty=%gd mybranch | sed 's/.*{\(.*\) .*/\1/'
# Prints 1300731806

Теперь мы куда-то попадаем!

#!/bin/bash
cutoff_date=$(date --date="July 23, 2010" +%s)
git for-each-ref refs/heads --format='%(refname)' | while read branch; do
    reflog_date=$(git log -g -n 1 --date=raw --pretty=%gd $branch -- | sed 's/.*{\(.*\) .*/\1/')
    if [ -n "$reflog_date" && "$reflog_date" -lt "$cutoff_date" ]; then
        git branch -D ${branch#refs/heads/}
    fi
done

Пример script! Я использовал date для преобразования прочитанной человеком даты для обрезания, затем для каждой ветки я проверил, была ли последняя дата reflog перед отключением, и если это так, удалите ветвь. Вы можете добавить чек против белого списка, чтобы спасти себя от случайного удаления чего-то, о чем вы заботитесь. (Изменить: если ветки старше 90 дней, это не будет их удалять, потому что их лог файлы уже будут пустыми... до вас, что вы хотите сделать в этом случае. Действительно, вы можете вернуться к проверке дата коммиттера, которая должна быть довольно безопасной в этот момент.)

Изменить: Здесь другой подход. Истерируйте логги на время отсечки, а затем удалите ветки, чьи логги пусты. Проблема заключается в том, что если время отсечения больше, чем время, когда ваши логгисты уже истекают (90 дней), это действительно просто удаляет ветки старше 90 дней. Конечно, вы можете обойти это.

#!/bin/bash

# Git lets you use very readable time formats!
cutoff_time="1 year ago"
# other examples:
# cutoff_time="July 23, 2010"
# cutoff_time="yesterday"

git for-each-ref refs/heads --format='%(refname)' | egrep -v 'master|other-whitelisted-branch' |
while read branch; do
    git reflog expire --expire="$cutoff_time" $branch
    if [ "$(git reflog show -1 $branch | wc -l)" -eq 0 ]; then
        git branch -D ${branch#refs/heads/}
    fi
done

Ответ 2

Обновление: как Jefromi и cebewee ниже, это решение рассматривает "дата коммиттера" фиксации на каждом конце ветки, и в некоторых ситуациях это не будет достаточно хорошим - чтобы использовать предыдущий пример, если вам нравятся ветки, которые были недавно созданы на основе гораздо более старых ветвей, вам нужно будет используйте reflog, как в Jefromi answer. Я думаю, что для многих ситуаций это достаточно хорошо, поэтому я оставляю ответ, а не удаляю его...

В последнее время я сделал сообщение в блоге с script, в котором перечислены ветки в порядке возрастания даты последнего фиксации на этой ветке, которую я нашел полезной для очень похожей ситуации для вас. script основан на git for-each-ref --sort=committerdate:

#!/bin/sh
for C in $(git for-each-ref --sort=committerdate refs/heads --format='%(refname)')
do
    git show -s --format="%ci $C" "$C"
done

Ответ 3

Вам понадобится script, а затем используйте это, чтобы захватить дату:

git log -1 branchName --format=%ci

это должно дать вам дату, которую вы можете заказать.

Теперь вам просто нужно перебирать ветки:

for branch in $(git branch -r); do yourscript $branch; done

надеюсь, что это поможет.

Ответ 4

Я закончил с этим решением:

for k in $(git branch -r | awk -F/ '/\/Your_prefix_here/{print $2}' | sed /\*/d); do
   if [ -z "$(git log -1 --since='Jul 31, 2015' -s origin/$k)" ]; then
     echo deleting "$(git log -1 --pretty=format:"%ct" origin/$k) origin/$k";
   fi;
done

Также он фильтрует ветки по заданному patter, так как мы используем соглашение try-XX для ветвления.

Ответ 5

Чтобы узнать, когда последняя ветвь изменилась (в отличие от даты последнего фиксации в ветке), вам нужно использовать reflog. git reflog branchName -1--date=relative отображает для ветки самую новую запись reflog и дату последнего изменения в ветку.

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

Проблема с этим решением заключается в том, что reflog истекает по умолчанию в IIRC 90 дней. Итак, если последнее изменение в ветки старше 90 дней (и вы сделали gc), вы не получите никакой информации об этой ветке. Вы обходите это, изменяя время истечения для reflog, см. git-config для этого.

Ответ 6

Очень простое решение, которое не всегда работает:

Просто посмотрите .git/refs/heads/ и отсортируйте по дате изменения.

Обратите внимание, что это не будет работать, если репозиторий более новый или что-то, поскольку git просто не отслеживает такую ​​информацию. Но в будущем это может сработать очень хорошо, когда у вас есть центральный репозиторий, который в противном случае ничего не изменит.