Subversion将外部更新为date

我正在SVN控制下build立一个大型的项目。 代码库的许多部分正在作为外部检查,但是正在被其他人积极地处理。
我想更新我的整个工作副本,外部和所有,以便它在特定的时间点反映各个仓库的头。 我最初的尝试是:

svn up -r'{20090324}' 

这将当前目录更新为指定date,但将所有外部更新为当前date。 一次更新一个外部工作正常。
我明白,由于外部的性质,单个更新不能使用修订版号,但为什么它不能与date一起使用?
达到我所期望的时间点效果的最佳方式是什么,而不必维护一个脚本来硬编码各种外部?

我正在运行一个Linux系统。

这是低效的,因为它比(通常)需要的更频繁地调用svn更新。 否则,它是一个甜蜜的短暂的:

Unix的:

 find . -name .svn -execdir svn update -r {2010-08-30} \; 

视窗:

 forfiles /m .svn /s /c "cmd /c svn up -r {2010-08-30}" 

当使用svn:externals时,使用没有修订号的外部通常是个不错的主意。 这意味着很难将外部版本与包含项目的版本关联起来; 我知道这很困难,从试图追踪包含外部项目的项目中的一些历史logging,我不得不猜测哪个版本与包含项目中的版本相对应(有时是因为有人更新了外部项目而更早然后更新了包含的项目,有时候是因为某人在外部结帐中直接编辑了文件,然后提交了它)。

相反,正如提示框中提到的,在Subversion书籍的外部部分 ,你应该总是提交一个修订号。 这样,无论您何时检出包含项目的特定修订版本,外部的相应修订版本也将被检出。 这意味着更多的工作,因为每次都必须更新svn:externals属性中的修订号(我们写了一个脚本来自动完成),但从长远来看,这是一个更好的解决scheme。

编辑 :这里是我们使用的脚本的骨架(一个rake任务),方便地更新外部并保持一切同步。

 desc 'Update external for this project (rake update_external r=17789)' task :update_external do |t| rev = ENV['r'] rev =~ /^\d+$/ or raise "Invalid SVN revision number: r=<#{rev}>" # Update the project. sh "svn update" URL = 'svn+ssh://example.com/external/trunk' sh "svn propset svn:externals 'external -r#{rev} #{URL}' containing/directory" # Update again -- to put the externals back to the right revision. sh "svn update" end 

这是我迄今发现的问题的最佳解决scheme(这是一个棘手的问题 – 破坏者开发人员应该将其修复在核心中)。 这个例子特别涉及到mplayer,但你应该很容易看到逻辑。

 ; fetch the rev I want without including the externals svn checkout -r "$REV" --ignore-externals \ svn://svn.mplayerhq.hu/mplayer/trunk ; grab the date of that rev from the svn info output DATE=`svn info trunk|sed -n '/^Last Changed Date/s/.*: \(.*\) (.*/\1/p'` ; fetch the externals using that date svn checkout -r "{$DATE}" \ svn://svn.mplayerhq.hu/ffmpeg/trunk/libavutil \ svn://svn.mplayerhq.hu/ffmpeg/trunk/libavformat \ svn://svn.mplayerhq.hu/ffmpeg/trunk/libavcodec \ svn://svn.mplayerhq.hu/ffmpeg/trunk/libpostproc 

我还没有一个完美的解决scheme,但是这一个接近:

 svn propget svn:externals | sed -e 's/ .*$//g' | xargs svn up -r'{20090324}' 

这在我的情况下工作,因为没有recursion的外部,所有的外部定义在目录或修订号码中没有空格,所以正则expression式可以很容易砍掉尾随存储库path。

我相信有更好的正则expression式可以一般地解决这个问题。

编辑:其实我越想这个,我看到的问题就越多。 其中最大的一个就是它使用当前版本的svn:externals,而不是指定date版本的svn:externals。 这比我第一次想到的还要复杂。

基于Dave Cohen的回答,但速度相当快:

 find . -name '.svn' -execdir svn up --ignore-externals -r '{2014-02-05}' \; 

这是棘手的,恐怕我不能提供一个很好的解决scheme,你现在的情况 – 但布赖恩已经给出了如何避免它的答案。

避免归结为一点库理论 – 基本上不可能修改任何源代码为您的项目没有相应的修改出现在主干。

通过指定所有外部标签或特定修订版本,在没有对外部引用进行更改的情况下,不会在主项目历史logging中出现更改。 但是如果你把一个外部的东西指向一个移动的后备箱,那么外部的改变就不会出现在主项目的时间轴上 – 让你处于你所处的位置。

就个人而言,我认为外部应该作为独立的项目来处理和发布,因此所有的外部都指向标签。 在繁重的并行开发过程中,将外部“切换”为主干,或者将不稳定的开发分支暂时指向外部主干,但主干项目主干总是指向稳定的外部,这是一个有意识的升级决定。 这种观点可能是你的情况矫枉过正,但值得看到其他的可能性。

好的实用程序,将冻结外部给定的path。 我们使用这个util来从主干创build一个标签后冻结外部:

http://svnxf.codeplex.com/

这里的问题是,你和你的同事没有使用你的外部显式修订号。 你应该立即开始 !

直觉上来说,我可能会认为从特定date检出某些东西会recursion地将外部查找“挂钩”到该date,即使在外部指向某个HEAD版本的情况下也是如此。 但是,事实并非如此。

修改/date/等您更新主要WC不会传递到外部,当他们正在更新。 如果没有外部定义中规定的具体修订,他们将始终跟踪他们所指的任何内容。 如果你在那里指定一个修订版本,那么这是唯一的修订版本。 我很确定你要做的事情是不可能的 – 这是我试图用来解决我遇到的问题的方法,正如我在这个问题中所描述的那样。 (我从来没有解决过这个问题,虽然我认为那里提到的代理想法可以做到,但这可能不会帮助你)

正如我最近有一个类似的问题,我写了一个脚本来签出一个特定版本的存储库,同时还检查了该修订date的外部: https : //gist.github.com/3413952

有用的,如果你需要find一个错误的来源,并希望有类似git的平分function。

让svn为你做recursion。

临时文件和tee只在这里,所以你可以看到完整的输出:

 SVN_UP_OUTPUT=$(mktemp SVN_UP_OUTPUT.XXXXX) svn up -r$REVISION | tee $SVN_UP_OUTPUT cat $SVN_UP_OUTPUT | egrep '^Fetching external' | egrep -o "'.*'" | sed -e "s/'//g" | while read DIR;do echo $$ svn up -r$REVISION "$DIR" svn up -r$REVISION "$DIR" done rm $SVN_UP_OUTPUT 

如果你不关心输出,可以缩写为:

 svn up -r$REVISION | egrep '^Fetching external' | egrep -o "'.*'" | sed -e "s/'//g" | while read DIR;do svn up -r$REVISION "$DIR" done 

当然,在你的情况下:

 REVISION='{20090324}'