获取特定年龄的 git 分支

发布于 2024-10-26 04:16:01 字数 184 浏览 1 评论 0原文

我的组织正在广泛使用 git 分支。结果,我们在过去的一年里已经生产了 2000 多个分支。我们现在正在尝试采取一种策略来清理所有具有一定年龄的旧分支。我知道如何删除分支,但我找不到一种简单的方法来列出具有给定年龄的头的所有分支。该计划是建立一个 cron 定期删除给定年龄的所有分支,除了某些列表中的分支。

以前有人尝试过类似的事情吗?

My organization is using git branching extensively. As a result, we have produced over 2000 branches in the past year. We are now trying to adopt a strategy for cleaning up all the old branches that are of some given age. I know how to delete branches, but I can't find a straightforward way to list all of the branches with heads of a given age. The plan is to set up a cron that periodically deletes all branches of a given age, except those that are on some list.

Has anyone tried anything like this before?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

人海汹涌 2024-11-02 04:16:01

使用提交者日期的答案是一个很好的方向......如果您想删除指向旧提交的分支。但您可能想删除实际上旧的分支;如果您今天创建一个分支指向去年的提交,您不希望它被擦除!

因此,您想检查转发日期。

您可以使用 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 来转换人类可读的截止日期,然后对于每个分支,我检查引用日志的最后日期是否在截止日期之前,如果是,则删除该分支。您可以在其中添加针对白名单的检查,以避免意外删除您关心的内容。 (编辑:如果分支超过 90 天,这不会删除它们,因为它们的引用日志已经是空的...取决于您在这种情况下想要做什么,真的。您可以回退到检查提交者日期,此时应该非常安全。)

编辑:这是另一种方法。在截止时间使 reflog 过期,然后删除 reflog 为空的分支。这里的问题是,如果截止时间早于您的引用日志已经过期的时间(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

The answers using committer dates are a good direction... if you want to delete branches that point to old commits. But you might want to delete branches which are actually old; if you create a branch today pointing to a commit from last year, you don't want it wiped!

So, you want to examine the reflog dates instead.

You can get a human-readable form with 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

(You might also like --date=relative)

The entry on the top is the most recent thing that happened on that branch, so that's the bit we care about. Unfortunately, there's no log format placeholder for just the date, so to grab out just the date, we do a little work:

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

Of course, for scripting, that's not very useful, so let's go ahead and get the epoch time instead:

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

Now we're getting somewhere!

#!/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

An example script! I used date to convert a human-readable date for the cutoff, then for each branch, I checked if the reflog's last date was before the cutoff, and if so, deleted the branch. You could add in a check against a whitelist there, to save yourself from accidentally deleting something you care about. (Edit: if the branches are older than 90 days, this won't delete them, because their reflogs will already be empty... up to you what you want to do in that case, really. You could fall back to checking the committer date, which ought to be pretty safe at that point.)

Edit: Here's another approach. Expire the reflogs at the cutoff time, then delete the branches whose reflogs are empty. The problem here is that if the cutoff time is older than the time when your reflogs already expire (90 days) it'll really just be deleting branches older than 90 days instead. You could work around that, of course.

#!/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
厌倦 2024-11-02 04:16:01

更新:如 Jefromicebewee 在下面指出,此解决方案查看每个分支提示处提交的“提交者日期”,在某些情况下,这还不够好 - 如果您关心的话,请使用前者的示例最近基于更旧的分支创建的分支,您需要使用引用日志,如 Jefromi 的回答。我认为对于很多情况来说这已经足够好了,所以我留下答案而不是删除它......

我做了一个 最近关于此的博客文章,其中有一个脚本按上次提交日期的升序列出分支在那个分支上,我发现它对于与你的情况非常相似的情况很有用。该脚本基于 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

Update: as Jefromi and cebewee point out below, this solution looks at the 'committer date' of the commit at each branch tip, and in some situations this wouldn't be good enough - to use the former's example, if you care about branches which were recently created based on much older branches, you'd need to use the reflog as in Jefromi's answer. I think that for plenty of situations this is good enough, though, so I'm leaving the answer rather than deleting it...

I did a blog post on this recently, with a script that lists branches in increasing order of the date of the last commit on that branch, which I've found useful for a very similar situation to yours. The script is based around 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
鹿港小镇 2024-11-02 04:16:01

您需要编写脚本,然后使用它来获取日期:

git log -1 branchName --format=%ci

这应该为您提供可以订购的日期。

现在您只需要迭代分支:

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

希望这会有所帮助。

You will need to script it and then use this to grab the date:

git log -1 branchName --format=%ci

this should give you date that you can order by.

Now you just need to iterate over the branches:

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

hope this helps.

土豪 2024-11-02 04:16:01

我最终得到了这个解决方案:

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 约定进行分支。

I've ended up with this solution:

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

Also It filters branches by a given patter, since we're using try-XX convention for branching.

浴红衣 2024-11-02 04:16:01

要查明分支上次更改的时间(相对于分支中上次提交的日期),您需要使用引用日志。 git reflogbranchName -1--date=relative 显示分支的最新引用日志条目以及上次更改分支的日期。

有多种不同的日期格式,请选择一种易于解析以适合您的用例的格式。

此解决方案的一个问题是,reflog 默认在 IIRC 90 天后过期。因此,如果分支上的最后一次更改早于 90 天(并且您执行了 gc),则您不会获得有关该分支的任何信息。您可以通过更改引用日志的过期时间来规避此问题,请参阅 git-config 了解这一点。

To find out when a branch last changed (opposed to the date of the last commit in a branch), you need to utilize the reflog. git reflog branchName -1--date=relative displays for a branch the newest reflog entry and the date of the last change to the branch.

There are various different date formats, choose one which is easy to parse for your use case.

A problem with this solution is that the reflog expires by default in IIRC 90 days. So, if the the last change on a branch is older then 90 days (and you dould a gc), you do not get any information about this branch. You circumvent this by changing the expire time for the reflog, see git-config for this.

情深缘浅 2024-11-02 04:16:01

一个非常简单的解决方案,但并不总是有效:

只需查看 .git/refs/heads/ 并按修改日期排序。

请注意,如果存储库较新或其他原因,这将不起作用,因为 git 根本不跟踪此类信息。但是,当您拥有一个不会发生太大变化的中央存储库时,它在未来可能会工作得很好。

A very simple solution, which does not always work:

Just look at .git/refs/heads/ and sort by modification date.

Note that this won't work if the repository is newer or something, as git simply doesn't track such information. But it might work very well in the future, when you have a central repository which otherwise doesn't change much.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文