如何恢复CVS的重大变化?

时间:2009-01-12 13:13:26

标签: version-control cvs revert

我的一位同事完全弄乱了我们主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客户端。

10 个答案:

答案 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有几个问题,你遇到这样的问题就会遇到它们。

  1. CVS是面向文件的,没有变更集或snasphot的概念。这意味着您想要还原的更改有点难以处理。提交在给定目录中是原子的,而不是在外面。

  2. 目录未进行版本控制。这意味着将删除空目录(如果您使用-P进行更新),并且必须指定-d以在结帐/更新时创建它们。

  3. 所以,为了回答你的问题,日期可能是唯一的处理方式,因为你没有使用标签来创建一些穷人的变更集版本。

    我对备份的评论是,从备份恢复整个仓库可能更容易,而不是尝试纠正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,可以有非常接近的变更集。

请参阅http://geocities.com/smcameron/cvs_changesets.html

答案 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 cvsimportgit cvsexportcommit一旦你完成所有设置就能很好地工作。即使项目仍在使用CVS,你最终也会获得git的所有强大功能。