使用 ClearCase 和 Git 实现理想的工作流程

Toward an ideal workflow with ClearCase and Git

简介

这不仅仅是事实,对于少数人维护的大型项目,使用 ClearCase(而非 UCM)作为主要 SCM 是一个非常低效的解决方案。当它是企业标准时,我们坚持使用它,我们需要找到一个有效的解决方法。

ClearCase 的常用工作流由一个 master 分支、一个 develop 分支和几个新功能分支组成。

        o--------o (feature)
       /          \
  ----o--o---o-----o----o (develop)
 /        \         \
*----------o---------o (main)

例子

其实我所说的特性也可以是简单的重构,比如项目内部的大量重命名。在这个例子中,因为 ClearCase 是以文件为中心的,所以我们总是需要一个临时分支(在非 UCM CC 中没有原子签入)。创建一个新分支是痛苦的,拥有正确的配置规范是一项艰巨的任务。从这里,我看到了两个解决方案:

  1. 成为公司并开始对所有文件进行大量检查。因为 SCM 环境与 ClearCase 服务器不在同一个站点上,所以一切都变慢了。我计算每个文件 2 秒,1k 文件计算 8 分钟。第一次喝咖啡休息后,我们开始工作并签入所有文件(又浪费了 8 分钟)。一些测试、新的大规模签出、错误修​​复、大量签入、合并到 develop 分支,最终我们删除了不再有用的 feature 分支。

    在这个解决方案中,一切都很慢,消耗了大量的咖啡因,而且工作流程效率很低。我认为这不是一个好的解决方案。

  2. 因为我们想跟踪我们的更改,我们不想浪费时间 checkin/out 所有项目的文件,我们从 Git 初始化一个存储库快照视图。实际上,Git 存储库可以位于 ClearCase 之外的任何其他地方。这些更改是在 Git 的帮助下在本地进行的,一旦一切都完成,该项目就会通过 clearfsimport 推回到 ClearCase 上。在此之后,我们还需要合并 feature 分支。这是在 CC 中完成的。然后可以删除功能分支。

    此解决方案需要大量操作。此外,如果我们拼错目标视图或忘记删除所有临时文件,clearfsimport 可能会非常危险。最后但同样重要的是,最终合并必须在 CC 上完成。

快照视图

在我的示例中,我没有提到快照视图,因为它们与 Git 不兼容。根据时间戳识别的被劫持文件。如果我手动修改文件并恢复其原始修改日期,ClearCase 将看不到任何更改。这可能非常危险,下面的示例证明了这一点。

如果你不相信我,你可以试试这个:

stat -c 'touch --no-create -d "%y" "%n"' foo > restore_timestamp
echo "ClearCase will not see this" >> foo
source restore_timestamp
rm restore_timestamp

使用此机制,没有 Git 存储库可以驻留在 ClearCase 快照视图中。

分离 Git 存储库

我怀疑我们能否找到解决临时分支创建要求的方法。合并必须在 ClearCase 上完成,即使 Git 保留了所有内容。

我尝试广泛使用 Copy/Paste 来将完全独立的 Git 存储库与 ClearCase 同步。在最终合并之前,我 copy/paste 在新的 Git 分支中 develop 分支的当前状态,并尽快进行合并。最后,我使用 clearfsimport 将修改推回 develop 分支。

如果有人想在合并过程中访问该项目,此操作可能非常危险。为此,开发分支在运行过程中不得不被锁定或保留。不幸的是,这个额外的操作在 ClearCase 上非常耗时。

ClearCase“git checkout -b 功能”等效

在 Git 中,当我想创建一个新分支时,我只需键入:

 git checkout -b feature

就是这样,我可以马上处理我的新功能。在 ClearCase 上,情况有些不同。

首先,我需要在要创建分支的位置放置一个标签。从 Windows 使用 Cygwin,我可以这样做:

LABEL=my_temporary_label
VOB=vob_name
cleartool mklbtype -global -nc lbtype:${LABEL}@\${VOB}
cleartool mklabel -replace ${LABEL} `cleartool find . -cview -print -nxn | awk '{printf "%s ", [=14=]}'`
cleartool find . -cview -type l -exec 'cleartool ls %CLEARCASE_XPN%' | \
   perl -p -e 's/\/\//g' | \
   perl -p -e 's/\r//g' | \
   perl -e 'while(<>) {s@([.]/)(.*/)(.*-->\s*)@@;print;}' | \
   xargs -n1 cleartool mklabel ${LABEL}

但是,我们需要小心,因为符号链接没有展开。

然后,必须创建一个分支:

mkbrtype –c "Temporary Branch" my_temporary_branch 

要在此分支上工作,需要创建一个视图:

cleartool mkview -tag my_temporary_view \shared\path\to\viewStorage\my_temporary_view.vws

必须编辑配置规范:

element * CHECKEDOUT
element  .../lost+found -none

element * .../develop_branch/LATEST

mkbranch develop_branch
   element * /main/A_LABEL_WHERE_THE_BRANCH_IS_BRANCHED_ON
   element * /main/LATEST

end mkbranch develop_branch

至此,分支创建完成。我们可以处理我们的功能。简单吧?

在Git,我一般一天创建3-5个分支。我不认为我可以用 ClearCase 做同样的事情。我错了吗?

讨论

所提出的两个解决方案都不太好,因为它们都需要在 ClearCase 上进行大量耗时的操作(创建分支、设置视图、签入、签出、合并、删除分支)。

我正在寻找一种不涉及复杂操作的解决方案。我仍然相信 Git 可能是一个很好的盟友,但 ClearCase 和 Git 如何协同工作?

我想我们可以使用一些脚本。我最近发现 git-cc 这可能是一个好的开始。不幸的是,这个项目还不成熟。

我还没有研究过这种方法,但我认为有一个解决方案,我们可以在 Git 中使用 ClearCase 快照视图。在进行任何更改之前必须保存每个文件的时间戳:

 find . -type f -exec stat -c 'touch--no-create -d "%y" "%n"' {} \; > restore

从那里,我们可以在 Git 上工作,一旦到了将更改推送到 ClearCase 或只是从开发分支中提取更改的时间,就可以在所有文件上恢复原始时间戳,但自上次同步以来修改的文件:

 source ./restore
 git diff --name-only SHA1 SHA2 | xargs touch

问题

在 Whosebug 上,人们喜欢精确的问题,而不是基于主要观点的问题。因此,在这个相当长的介绍之后,我终于可以问我的问题了:

我已经尝试了很多不同的方法来改进我使用 ClearCase 的工作流程,但是使用 以文件为中心 SCM 的大型项目不是直截了当。我相信 Git 会有很大帮助,但我需要找到一个允许本地 git 存储库与 ClearCase 同步的工作流,并且如果可能的话,不需要临时分支。

可以吗?

Actually, what I call a feature could be also a simple refactoring, such as a massive renaming inside the project. In this example, and because ClearCase is file-centric, we always need a temporary branch (no atomic checkin in non-UCM CC).
Creating a new branch is painful and having the right config-spec is a struggling task

所以...不创建临时分支?
如果要与 Git 协作使用,仅在 Git 存储库中创建该功能分支,在 Git 存储库中进行最终合并,然后 clearfsimport 主 ClearCase 视图中的结果。

来自VonC

的可能解决方案

VonC 中,他建议不要使用中间分支并使用 Git 管理所有内容。

我想通过一个例子来展示他的方法。我们从 ClearCase 上的这个配置开始:

  o------o----o (develop)
 /        \ 
*----------o (main)

想法是使用 Git 来促进新功能的开发,最终将合并到 develop 分支。

我们首先将 ClearCase 项目复制到本地文件夹并初始化一个 Git 存储库(如果 Git 存储库不存在)。

WORKSPACE=~/foo
cp `cleartool ls -r | grep '@@' | sed 's/@@.*$//'` $WORKSPACE
cd $WORKSPACE
git init
git add .
git commit -m "Initial commit"
git checkout -b feature

我们花了一些时间在自己的本地 Git 分支上开发该功能:

                  x----x--x---x----x (feature on Git)
                 /
                x---------- (master on Git)
               /
  o------o----o------o----o (develop)
 /        \ 
*----------o (main)

一天结束时,是时候从 ClearCase 同步可能的更改了:

git checkout master
git --ls-files | xargs rm
cd $CCVIEW
cleartool ls -r | grep '@@' | sed 's/@@.*$//' > $WORKSPACE/ccview
cd $WORKSPACE
cat ccview | xargs -n1 cp {} $WORKSPACE    
cat ccview | xargs git add 
git commit -m "Imported from CC"

现在我们已经在 feature 分支上进行了多次提交,并且 master Git 分支与 ClearCase 同步。

                  x----x--x---x----x (feature on Git)
                 /
                x-----------o (master on Git)
               /           /
  o------o----o------o----o (develop)
 /        \ 
*----------o (main)

我们一定不要忘记在整个合并过程中锁定ClearCase View。这是为了防止其他开发人员看到他们自己的更改被 clearfsimport 删除。要锁定 ClearCase 分支很容易:

cleartool lock brtype:$BR_NAME 

然后可以在 Git:

上完成合并
git checkout master
git merge feature

feature Git 分支与 master 合并。

                  x----x--x---x----x (feature on Git)
                 /                  \
                x-----------o--------o (master on Git)
               /           /
  o------o----o------o----o (develop)
 /        \ 
*----------o (main)

可以将修改推回 ClearCase

OUT="$(mktemp -d)"
cp -v --parents `git ls-files | sed 's/[^ ]*\.gitignore//g'` $OUT
clearfsimport -comment 'clearfsimport' -rec -unco -nset $OUT $CVIEW    
rm -rf $OUT

并且可以解除锁以重新授权分支上的更改

cleartool unlock brtype:$BR_NAME

                  x----x--x---x----x (feature on Git)
                 /                  \
                x-----------o--------o (master on Git)
               /           /          \
  o------o----o------o----o------------o (develop)
 /        \ 
*----------o (main)

除非我们需要继续,否则 Git 存储库和本地工作区可能会被删除。

  o------o----o------o----o------------o (develop)
 /        \ 
*----------o (main)

在此解决方案中,我们没有在 ClearCase 上使用中间分支,所有合并过程都发生在 Git 上。保留了 ClearCase 历史记录。唯一不好的地方就是最后合并需要锁开发分支。

@VonC,如有错误请随时修改我的答案