我的git存储库中有一些旧的分支,它们不再处于活跃的开发状态。我想存档这些分支,这样它们在运行git branch -l -r时默认不会显示。我不想删除它们,因为我想保留历史。我该怎么做呢?
我知道可以在refs/heads之外创建一个ref。例如:refs/archive/old_branch。这样做有什么后果吗?
我的git存储库中有一些旧的分支,它们不再处于活跃的开发状态。我想存档这些分支,这样它们在运行git branch -l -r时默认不会显示。我不想删除它们,因为我想保留历史。我该怎么做呢?
我知道可以在refs/heads之外创建一个ref。例如:refs/archive/old_branch。这样做有什么后果吗?
当前回答
要归档超过n个月或n年的分支,运行这个bash脚本。
#!/bin/bash
# Average days in a month - 30.436875
# Hours in a day 24
# Minutes in an hour 60
# Seconds in a minute 60
months_in_year=12
days_in_month=30.436875
hours_in_day=24
minutes_in_hour=60
seconds_in_minute=60
# Input is x months or x years
# $1 an integer
# $2 a time metric
# Name of the script, follows through simlinks
script_name="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
if [ $# -le 1 ]; then
echo "Usage: ./${script_name} [1-9] [month(s)/year(s)]"
exit 1
fi
time_period=$1
time_metric=$2
if [[ ${time_metric} =~ "month" ]]; then minimum_branch_age_in_seconds=$( echo "scale=4; $time_period * $days_in_month * $hours_in_day * $minutes_in_hour * $seconds_in_minute" | bc); fi
if [[ ${time_metric} =~ "year" ]]; then minimum_branch_age_in_seconds=$( echo "scale=4; $time_period * $months_in_year * $days_in_month * $hours_in_day * $minutes_in_hour * $seconds_in_minute" | bc); fi
echo "minimum_branch_age: $1 $2"
echo "minimum_branch_age_in_seconds: ${minimum_branch_age_in_seconds%.*}"
git for-each-ref refs/remotes | while read commit type ref;do
current=$(date +%s)
headcd=$(git log -1 --pretty=%cd --date=format:%s ${commit})
age_in_seconds=$((current-headcd))
if [[ ${age_in_seconds} -ge ${minimum_branch_age_in_seconds%.*} ]];then
branch=$(echo $ref | sed 's=refs/remotes/origin/==g')
age_in_months=$( echo "scale=4; $age_in_seconds / $days_in_month / $hours_in_day / $minutes_in_hour / $seconds_in_minute" | bc)
echo "archiving $branch - age in seconds - $age_in_seconds - age in months - $age_in_months "
git tag archive/${branch} ${branch}
git push -d origin ${branch}
git branch -D ${branch}
echo "Unarchive with: git checkout -b ${branch} archive/${branch}"
fi
done
谢谢杰里米炖的肉。
其他回答
在Git中,分支只是一个指向某个提交的指针。因此,删除一个分支只会删除一个指针,即使分支从未合并,也不会删除相关的代码。因此,“归档”本地分支就像记住指针名称一样简单(提交哈希)。你可以在。/git/refs/heads目录下找到这些信息。或者,您可以简单地将分支到提交的映射复制到如下所示的文本文件中。
git branch -v > /path/to/backup/branches.txt
删除分支之后,可以使用以下命令在本地恢复它。
git branch <branch_name> <commit_hash>
下面是它的别名:
arc = "! f() { git tag archive/$1 $1 && git branch -D $1;}; f"
这样加起来:
git config --global alias.arc '! f() { git tag archive/$1 $1 && git branch -D $1;}; f'
请记住,git已经有了archive命令,所以不能使用archive作为别名。
你还可以定义alias来查看“存档”分支的列表:
arcl = "! f() { git tag | grep '^archive/';}; f"
关于添加别名
是的,你可以使用git update-ref创建一个带有非标准前缀的ref。如。
归档分支:git update-ref refs/ Archive /old-topic topic && git branch -D topic 恢复分支(如果需要):git分支topic refs/archive/old-topic
带有非标准前缀的引用(这里是Refs /archive)不会出现在通常的git分支,git日志或git标签上。不过,您可以使用git for-each-ref列出它们。
我使用以下别名:
[alias]
add-archive = "!git update-ref refs/archive/$(date '+%Y%m%d-%s')"
list-archive = for-each-ref --sort=-authordate --format='%(refname) %(objectname:short) %(contents:subject)' refs/archive/
rem = !git add-archive
lsrem = !git list-archive
此外,你可能想要配置像push = +refs/archive/*:refs/archive/*这样的远程来自动推送归档的分支(或者只指定一个推送,比如git push origin refs/archive/*:refs/archive/*)。
另一种方法是在删除分支之前在某个地方写下SHA1,但它有局限性。没有任何引用的提交将在3个月后被GC - d(或几个星期后没有reflog),更不用说手动的git GC -prune。由refs指向的提交对GC是安全的。
编辑:通过@ap: git-attic找到了一个相同思想的perl实现
编辑^2:在一篇博客文章中,Gitster自己也使用了同样的技术。他把它命名为git hold。
杰里米的回答原则上是正确的,但恕我直言,他指定的命令不太正确。
下面是如何在不签出分支的情况下将一个分支归档到一个标签中(因此,在删除该分支之前,不必签出到另一个分支):
> git tag archive/<branchname> <branchname>
> git branch -D <branchname>
下面是如何恢复一个分支:
> git checkout -b <branchname> archive/<branchname>
我认为正确的方法是标记分支。如果你在标记了分支之后删除了它,那么你就有效地保留了这个分支,但它不会使你的分支列表变得混乱。
如果您需要返回分支,只需检查标签。它将有效地从标记中恢复分支。
归档并删除分支:
git tag archive/<branchname> <branchname>
git branch -d <branchname>
在一段时间后恢复分支:
git checkout -b <branchname> archive/<branchname>
分支的历史记录将被保留,就像您标记它时一样。