получение мерзких веток определенного возраста - PullRequest
21 голосов
/ 22 марта 2011

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

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

Ответы [ 6 ]

20 голосов
/ 22 марта 2011

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

Итак, вместо этого вы хотите проверить даты рефлога.

Вы можете получить человека-читаемая форма с git reflog show --date=local mybranch:

8b733bc mybranch@{Tue Mar 22 13:21:49 2011}: commit: foo
7e36e81 mybranch@{Tue Mar 22 13:21:25 2011}: commit: bar
99803da mybranch@{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

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

Редактировать: Вот другой подход.Срок действия повторных журналов истекает во время отсечения, затем удалите ветки, чьи флажки пусты.Проблема здесь в том, что если время отсечения старше, чем время, когда ваши повторные журналы уже истекают (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
4 голосов
/ 22 марта 2011

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

Я написал в своем блоге сообщение недавно со скриптом, который перечисляет ветви в порядке возрастания даты последнего коммита в этой ветви, что я нашел полезным для ситуации, очень похожей на вашу.Сценарий основан на 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
1 голос
/ 20 августа 2015

Я получил это решение:

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

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

1 голос
/ 22 марта 2011

Вам нужно будет написать сценарий, а затем использовать его, чтобы получить дату:

git log -1 branchName --format=%ci

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

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

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

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

0 голосов
/ 22 марта 2011

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

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

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

0 голосов
/ 22 марта 2011

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

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

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

...