Получение git ветвей определенного возраста
Моя организация широко использует разветвление git. В результате за последний год мы выпустили более 2000 веток. Сейчас мы пытаемся принять стратегию для очистки всех старых ветвей, которые имеют определенный возраст. Я знаю, как удалять ветки, но я не могу найти простой способ перечислить все ветки с головами определенного возраста. Планируется создать cron, который периодически удаляет все ветки определенного возраста, кроме тех, которые находятся в каком-то списке.
Кто-нибудь пробовал что-нибудь подобное раньше?
Ответы
Ответ 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 просто не отслеживает такую информацию. Но в будущем это может сработать очень хорошо, когда у вас есть центральный репозиторий, который в противном случае ничего не изменит.