我的一位同事完全弄乱了我们主CVS存储库中目录的内容。我需要将整个模块恢复到去年年底的状态。请问CVS命令是什么?
他添加并删除了数百个文件,因此简单的“从旧结帐和提交复制文件”是不够的。
我有RTFM和STFW,我试过这个:
cvs co modulename # Note no -P option
cvs up -jHEAD -jMAIN:2008-12-30 modulename
但这不起作用 - 他创建的新文件被删除,但旧的文件和目录不会被复活。 (我没有承诺)。
我可能会为此编写一个shell脚本,但这个功能肯定已经在CVS中了吗?
更新:一些澄清:
我可以在特定日期获得模块的本地结帐。问题是如何将其重新纳入CVS。
我确实有备份,但使用像CVS这样的修订控制系统的要点是它应该很容易获得任何历史状态。下次发生这样的事情时,我可能没有足够的幸运能够进行备份(例如每天备份,所以我可能会失去一天的工作量。)
我知道CVS已经老了,我们应该转向更新的东西。但是在拥有大量基于CVS的工具(结账和构建脚本,夜间构建服务器等)的大型团队中,此类移动的时间成本相当可观。 (评估,更新脚本,测试,迁移,培训,丢失开发人员时间,并行维护两个系统,因为旧分支仍然需要CVS)。因此,这必须有计划和由管理层安排。
更新#2:我将在此开始赏金。 要获得赏金资格,您必须解释如何使用普通的CVS命令恢复,而不是使用hacky shell脚本。
更新#3:服务器为CVS 1.12.13。通过pserver访问。我可以在Linux PC上使用相同版本的CVS,或在Windows上使用CVSNT 2.0.51d客户端。
答案 0 :(得分:27)
实际上,您最初的方法非常接近解决方案。问题是,基于日期的加入不能正确处理已删除的文件和目录。您需要先为要加入的代码库设置标记:
mkdir code_base1 && cd code_base1
cvs co -D "2008-12-30" modulename
cvs tag code_base_2008_12_30
现在进行基于连接标记,减去现在和2008-12-30之间的所有更改:
cd .. && mkdir code_base2 && cd code_base2
cvs co modulename
cvs update -d -j HEAD -j code_base_2008_12_30 # use -d to resurrect deleted directories
比较code_base1和code_base2的内容。它们应该是相同的,除了CVS元信息。最后将代码提交到2008-12-30,作为新的HEAD:
cvs commit -m "Revert all changes this year"
请注意,标记您希望加入的代码不起作用,因为当使用-D时,rtag也无法正确处理已删除的文件和目录:
cvs rtag -D "2008-12-30" code_base_2008_12_30 modulename
答案 1 :(得分:4)
CVS有几个问题,你遇到这样的问题就会遇到它们。
CVS是面向文件的,没有变更集或snasphot的概念。这意味着您想要还原的更改有点难以处理。提交在给定目录中是原子的,而不是在外面。
目录未进行版本控制。这意味着将删除空目录(如果您使用-P
进行更新),并且必须指定-d
以在结帐/更新时创建它们。
所以,为了回答你的问题,日期可能是唯一的处理方式,因为你没有使用标签来创建一些穷人的变更集版本。
我对备份的评论是,从备份恢复整个仓库可能更容易,而不是尝试纠正CVS不擅长的事情。
我会鼓励你 - 但这是另一个主题 - 尽快更改版本控制。相信我,我已经在FreeBSD project内长时间处理CVS并快速了解CVS是多么可恶......请参阅here了解我对版本控制软件的一些看法。
答案 2 :(得分:2)
我相信你的第二个命令也应该是结账,而不是更新。我无法用逻辑证明这一点,因为CVS世界中没有逻辑,但它对我有用。试试这个:
cvs co -P modulename
cvs co -P -jHEAD -jMAIN:2008-12-30 modulename
如果您要还原HEAD以外的分支,例如X,在两个命令中传递-rX参数:
cvs co -P -rX modulename
cvs co -P -rX -jHEAD -jMAIN:2008-12-30 modulename
答案 3 :(得分:1)
我仍然有兴趣知道是否有更简单的方法。 (肯定有一种更简单的方法)。我最终做的是,在使用bash的Linux PC上:
# Get woking copy we're going to change
cd ~/work
rm -rf modulename
cvs up -dP modulename
cd modulename
# Remove all files
find . -name CVS -prune -o -type f -print | xargs cvs rm -f
# Get the old revision
cd ~
mkdir scratch
cd scratch
cvs -q co -D 2008-12-31 modulename
cd modulename
# Copy everything to the working dir and do "cvs add" on it
find . -name CVS -prune -o -type f -print | \
xargs tar c | \
(cd ~/work/modulename && tar xv | \
xargs cvs add)
# Check everything is OK before we commit
cd ~/work/modulename
cvs -nq up
# it gave me an error on readme.txt because I'd deleted and then added it, so:
mv readme.txt x # save good rev
cvs add readme.txt # resurrect the bad rev
mv x readme.txt # clobber file with good rev
# Commit it
cvs commit -m "Revert all changes this year"
# Delete now-empty directories
cvs -q up -dP
# Double-check everything is back how it was
diff -ur -xCVS ~/scratch/modulename ~/work/modulename
然后我发现仍然存在差异 - 我的同事添加了包含空格的文件名,这些文件名未被上述过程删除。我不得不另外删除它们。 (我应该使用find ... -print0
而不是-print
,并将-0
参数传递给xargs
。我只是没有意识到有空格的文件。)
答案 4 :(得分:1)
您可以查看cvsps。谷歌吧。
此外,有了quilt(或Andrew Morton的补丁脚本,这就是被子开始的那样)和cvsps,可以有非常接近的变更集。
答案 5 :(得分:0)
您是否尝试过使用-d
选项? (构建子目录)
据我记忆所及,cvs co
暗示了这一点,但cvs up
却暗示了这一点。
答案 6 :(得分:0)
根据http://www.astro.ku.dk/~aake/MHD/docs/CVS.html,您需要以下内容:
cvs update -D "30 Dec 2008 23:59"
答案 7 :(得分:0)
如果您有存储库的备份(服务器上的实际RCS文件,例如磁带上),您可以将CVS服务器上的该文件夹恢复到之前的状态。在执行此操作之前不要忘记停止CVS服务器(并在之后重新启动)。
答案 8 :(得分:0)
很大的问题,没有完整的答案,只是提示你的脚本来处理文件名中的空格。
而不是
find ... | xargs tar c - | ...
尝试放
find ... | perl -e '@names = <>;' -e 'chomp @names;' -e 'system( "tar", "c", "-", @names);' | ...
这样,您的存档创建(或类似操作)不会受到名称中的空格的影响,在调用tar之前会跳过shell argv解析。
还有一件事,关于它实际运行的机会:如果有一个CVS到SVN实用程序,使用它(我假设这样的实用程序会从“CVS阁楼”中删除已删除的文件),并且 if 它将每个时刻保存为项目级别检查点(因为SVN与CVS不同),使用SVN及时获取正确的时刻。很多ifs ......
答案 9 :(得分:0)
如果您或同事对git感到满意,可以使用git cvsimport
创建一个镜像CVS存储库的git存储库。在git中恢复提交/更改集是微不足道的(使用git revert
)。然后,您可以使用git cvsexportcommit
将恢复提交发送到CVS。
这听起来可能过于复杂,但根据我的经验,git cvsimport
和git cvsexportcommit
一旦你完成所有设置就能很好地工作。即使项目仍在使用CVS,你最终也会获得git的所有强大功能。