7

将 Rational ClearCase v. 7.0.1.1 与 UCM 一起使用,我在使用 ClearCase 的“从流传递到备用目标”功能时遇到了问题。

想象一下,我们有一个项目集成流和两个从它派生的开发人员流 A 和 B。现在我更改了流 A 中的一个文件。我希望拥有流 B 的开发者能够使用我的工作,而无需我将文件传送到集成流,因此我从流 A 传送到备用目标流 B。

到目前为止,一切都很好。我继续对文件进行另一项更改,但流 B 开发人员不需要此更改,因此我不将其交付给他。

再过一段时间,我将我的工作交付给主集成流。这很好用,尽管我想知道为什么 ClearCase 将合并标记为普通的“合并”而不是“合并(琐碎)”——除了我之外,没有人对文件进行过更改。

交付后,在主集成流上创建一个新基线。

真正的问题出现在开发人员 B 尝试重新设置他的流的基础上。由于开发人员 B 从未对文件进行任何更改,我希望合并是一个微不足道的合并,无需交互。但是发生的情况是,开发人员 B 被迫以图形方式解决该文件上的合并冲突,让他在集成流的基本版本、我交付给他的版本和我交付给集成流的版本之间进行选择。

当解决合并并完成 rebase 后,开发人员 B 想要向主集成流执行交付时,混乱继续存在。除了我最初交付给他的活动之外,他还被提供了一个名为 rebase_... 的活动,我从没想过会提供这个活动。

我在这里错过了什么吗?我们是否错误地使用了 ClearCase,或者这是一个已知的限制/错误?有没有人体验过这个功能?

在此先感谢您的帮助!

4

2 回答 2

7

实际上,当我查看版本树时,rebase 期间冲突的根源就很清楚了:

有冲突的版本树

当您重新阅读ClearCase 3-way merge 的工作方式时,您会发现它需要回到版本树中才能找到一个共同的祖先:

  • 来源 (Int/2)
  • 目的地 (B/1)

那个共同的祖先是 Int/1

现在,这两个版本之间可能有一条共同的线路发生了变化,因为:

  • 最后一个 rebase (Int/2) 的来源来自 A/3
  • 最后一个变基 (B/1) 的目的地来自 A/2
  • 共同祖先 (Int/1) 来自 A/1

如果在 A/2 和 A/3 中修改了公共线(从 A/1 开始)... 有理由在那里手动合并解决方案!

(我现在正在测试这个)


知道了!冲突达成!

继续我之前的实验

让我们在 Stream A 中创建一个新的 modif:

M:\vonc_test_dat_a\adev\test>ct co -nc aFile.txt
M:\vonc_test_dat_a\adev\test>echo modif by A to B>>aFile.txt
M:\vonc_test_dat_a\adev\test>ct ci -nc aFile.txt

M:\vonc_test_dat_a\adev\test>type aFile.txt
first line done on Int
Second line from Int
Addition by A to be delivered to B first
Modification by A to be delivered to Int, B does not need it
modif by A to B

直接将其交付给 B:

M:\vonc_test_dat_a\adev\test>ct deliver -to vonc_test_dat_b -target Test_DAT_B@\myPVob -cact -gmerge -force
Changes to be DELIVERED to non-default target stream in current project "Test_DeliverToAlternateTarget":
          FROM: stream "Test_DAT_A"
          TO: stream "Test_DAT_B"
Using target view: "vonc_test_dat_b".
Activities included in this operation:
        activity:test_dat_a@\myPVob   vonc        "test_dat_a"
Trivial merge: "M:\vonc_test_dat_b\adev\test\aFile.txt" is same as base "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\Test_DAT_A\2".
Copying "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\Test_DAT_A\3" to output file.
Deliver has merged

M:\vonc_test_dat_a\adev\test>ct deliver -target Test_DAT_B@\myPVob -cact -complete -force

(简单的合并)

现在让我们完全更改该文件的内容:

M:\vonc_test_dat_a\adev\test>ct co -nc aFile.txt
M:\vonc_test_dat_a\adev\test>echo change first line>aFile.txt
M:\vonc_test_dat_a\adev\test>ct ci -nc aFile.txt

M:\vonc_test_dat_a\adev\test>type aFile.txt
change first line

并交付给 Int,并在交付后立即设置新基线:

M:\vonc_test_dat_a\adev\test>ct deliver -force
M:\vonc_test_dat_a\adev\test>ct deliver -force -complete
M:\vonc_test_dat_a\adev\test>ct mkbl -comp ADV_TST@\myPVob -view vonc_test_dat_int TST_DAT1.2.0

(另一个微不足道的合并)

B 的变基怎么样?

M:\vonc_test_dat_b\adev\test>ct rebase -bas TST_DAT1.2.0
Advancing to baseline "TST_DAT1.2.0" of component "ADV_TST"
Updating rebase view's config spec...
Creating integration activity...
Setting integration activity...
Merging files...
Checked out "M:\vonc_test_dat_b\adev\test\aFile.txt" from version "\main\Test_DAT_Int\Test_DAT_B\3".
  Attached activity:
    activity:rebase.Test_DAT_B.20090707.163300@\myPVob  "rebase Test_DAT_B on 07/07/09 4:33:00 PM."
Needs Merge "M:\vonc_test_dat_b\adev\test\aFile.txt" [to \main\Test_DAT_Int\Test_DAT_B\CHECKEDOUT from \main\Test_DAT_Int\4 base \main\T
est_DAT_Int\3]
********************************
<<< file 1: M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\3
>>> file 2: M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\4
>>> file 3: M:\vonc_test_dat_b\adev\test\aFile.txt
********************************
---------[changed 1-4 file 1]----------|---------[changed to 1 file 2]---------
first line done on Int                 | change first line
Second line from Int                   |-
Addition by A to be delivered to B fir+|
Modification by A to be delivered to I+|
                                      -|
*** Automatic: Applying CHANGE from file 2 [line 1]
============
============
-----------[after 4 file 1]------------|----------[inserted 5 file 3]----------
                                      -| modif by A to B
                                       |-
Do you want the INSERTION made in file 3?  [yes] no
============
============
Output of merge is in "M:\vonc_test_dat_b\adev\test\aFile.txt".
Recorded merge of "M:\vonc_test_dat_b\adev\test\aFile.txt".
Build and test are necessary to ensure that any merges and configuration changes were completed correctly.
When build and test are confirmed, run "cleartool rebase -complete".

你有它:来自共同祖先的两个不兼容的变化之间的一个很好的冲突。

这是一张图片来说明这一点:

合并期间的冲突

.

于 2009-07-07T14:28:03.797 回答
2

我对这种冲突感到惊讶:因为 ClearCase 确实注册了从流 A 到 B 的合并,除非流 B 没有与流 A 相同的基础基线(分支的起点或初始标签)。

除了我最初交付给他的活动之外,他还被提供了一个名为 rebase_... 的活动,我从没想过会提供这个活动。

当您从 Int 变基到 B 时,您创建了一个自动“时间线”,它将所有活动链接在一起。
这意味着,在下一次交付期间,B 将不得不交付 rebase,即使不会对该变更集中存在的所有版本执行合并。


先评论几句:

  • 您可能希望避免创建附加到资源的流(开发人员“A”,开发人员“B”):如果他们正在为同一全局“开发工作”处理单独的文件集,则应该只有一个 Stream_FeatureF 代表任务手。
    然后,A 和 B 应该看到附加到该流的同一分支的相同 LATEST(无需从一个流传递到另一个流)
    如果 B 不断中断 A 的工作,那么只有这样才能为破坏性子创建一个子流-不能与主要功能“F”同时开发的功能。

  • 当合并很琐碎时,交付/rebase GUI 不会显示“是(琐碎)” (请参阅​​下面的测试)。这并不意味着合并不是微不足道的(意味着基础与源或目标相同,请参阅核心概念

  • 我下面的测试尊重您描述的合并工作流程,但仅显示微不足道的合并。
    可以解释非平凡的将是“邪恶双胞胎”(一个文件添加到一个流中,但在另一个流中从头开始重新创建,具有相同的名称)


好吧,让我们测试一下,假设一个 Vob“adev”(代表“开发架构”,我的团队在其中存储它的工具),在 \adev\test 中有一个 UCM 组件 ADV_TST。
Windows 上的 ClearCase7.0.1(虽然 Vob 实际上是在 Unix 上)

让我们从一个测试项目、一个集成流和一个空的测试组件开始:

M:\>ct mkproj -in folder:ADV_Tests@\myPVob Test_DeliverToAlternateTarget@\myPVob
M:\>ct mkstream -int -in Test_DeliverToAlternateTarget@\myPVob Test_DAT_Int@\myPVob
Created stream "Test_DAT_Int".
M:\>ct mkview -tag vonc_test_dat_int -stream Test_DAT_Int@\myPVob -stg hostname_ccstg_c_views
M:\vonc_test_dat_int\adev\test>ct rebase -bas ADV_TST0.0.0
Adding baseline "ADV_TST0.0.0" of new component "ADV_TST"
M:\vonc_test_dat_int\adev\test>ct rebase -complete

让我们使组件可写:

M:\vonc_test_dat_int\adev\test>ct chproj -amodcomp component:ADV_TST@\myPVob Test_DeliverToAlternateTarget@\myPVob
M:\vonc_test_dat_int\adev\test>ct chstream -generate Test_DAT_Int@\myPVob
M:\vonc_test_dat_int\adev\test>ct setcs -stream

A 会在 Int 上创建一个文件,添加它,修改它,然后放一个基线:

M:\vonc_test_dat_int\adev\test>ct mkact test_dat_int
M:\vonc_test_dat_int\adev\test>echo first line done on Int>aFile.txt
M:\vonc_test_dat_int\adev\test>ct co -nc .
M:\vonc_test_dat_int\adev\test>ct mkelem -nc aFile.txt
M:\vonc_test_dat_int\adev\test>ct ci -nc .
M:\vonc_test_dat_int\adev\test>ct ci -nc aFile.txt

M:\vonc_test_dat_int\adev\test>ct co -nc aFile.txt
M:\vonc_test_dat_int\adev\test>echo Second line from Int>>aFile.txt
M:\vonc_test_dat_int\adev\test>ct ci -nc aFile.txt

M:\vonc_test_dat_int\adev\test>type aFile.txt
first line done on Intct mkview vonc_
Second line from Int

M:\vonc_test_dat_int\adev\test>ct mkbl -comp ADV_TST@\myPVob TST_DAT1.0.0
Created baseline "TST_DAT1.0.0" in component "ADV_TST".

现在,让我们创建两个子流,每个开发人员一个(尽管可能被认为是“不好的做法”),两者都使用相同的基线进行初始化TST_DAT1.0.0

M:\vonc_test_dat_int\adev\test>ct mkstream -in Test_DAT_Int@\myPVob Test_DAT_A@\myPVob
M:\vonc_test_dat_int\adev\test>ct mkstream -in Test_DAT_Int@\myPVob Test_DAT_B@\myPVob
M:\vonc_test_dat_int\adev\test>ct mkview -tag vonc_test_dat_a -stream Test_DAT_A@\myPVob -stg hostname_ccstg_c_views
M:\vonc_test_dat_int\adev\test>ct mkview -tag vonc_test_dat_b -stream Test_DAT_B@\myPVob -stg hostname_ccstg_c_views
M:\vonc_test_dat_int\adev\test>ct rebase -view vonc_test_dat_a -bas TST_DAT1.0.0
M:\vonc_test_dat_int\adev\test>ct rebase -view vonc_test_dat_a -complete
M:\vonc_test_dat_int\adev\test>ct rebase -view vonc_test_dat_b -bas TST_DAT1.0.0
M:\vonc_test_dat_int\adev\test>ct rebase -view vonc_test_dat_b -complete

A 将对他的流 A 进行修改,以传递给 B:

M:\vonc_test_dat_a\adev\test>ct mkact test_dat_a
M:\vonc_test_dat_a\adev\test>ct co -nc aFile.txt
Created branch "Test_DAT_A" from "aFile.txt" version "\main\Test_DAT_Int\2".
M:\vonc_test_dat_a\adev\test>echo Addition by A to be delivered to B first>>aFile.txt
M:\vonc_test_dat_a\adev\test>ct ci -nc aFile.txt

直接从流 A 传送到 B:

M:\vonc_test_dat_a\adev\test>ct deliver -to vonc_test_dat_b -target Test_DAT_B@\myPVob -cact -gmerge
Changes to be DELIVERED to non-default target stream in current project "Test_DeliverToAlternateTarget":
          FROM: stream "Test_DAT_A"
          TO: stream "Test_DAT_B"
Using target view: "vonc_test_dat_b".
Activities included in this operation:
        activity:test_dat_a@\myPVob   vonc        "test_dat_a"
Created branch "Test_DAT_B" from "M:\vonc_test_dat_b\adev\test\aFile.txt" version "\main\Test_DAT_Int\2".
Checked out "M:\vonc_test_dat_b\adev\test\aFile.txt" from version "\main\Test_DAT_Int\Test_DAT_B\0".
  Attached activity:
    activity:deliver.Test_DAT_A.20090707.123738@\myPVob  "deliver Test_DAT_A on 07/07/09 12:37:38 PM."
Needs Merge "M:\vonc_test_dat_b\adev\test\aFile.txt" [to \main\Test_DAT_Int\Test_DAT_B\CHECKEDOUT from \main\Test_DAT_Int\Test_DAT_A\1 b
ase \main\Test_DAT_Int\2]
Trivial merge: "M:\vonc_test_dat_b\adev\test\aFile.txt" is same as base "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\
2".
Copying "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\Test_DAT_A\1" to output file.
Deliver has merged
M:\vonc_test_dat_a\adev\test>ct deliver -target Test_DAT_B@\myPVob -force -complete

我确认 GUI 没有显示Trivial,尽管同一交付的文本输出确实提到了Trivial merge......

A 继续处理 ' aFile.txt' 并将其传递给 Int:

M:\vonc_test_dat_a\adev\test>ct co -nc aFile.txt
M:\vonc_test_dat_a\adev\test>echo Modification by A to be delivered to Int, B does not need it>>aFile.txt
M:\vonc_test_dat_a\adev\test>ct ci -nc aFile.txt

M:\vonc_test_dat_a\adev\test>ct deliver
Changes to be DELIVERED to default target stream in project "Test_DeliverToAlternateTarget":
          FROM: stream "Test_DAT_A"
          TO: stream "Test_DAT_Int"
Using target view: "vonc_test_dat_int".
Activities included in this operation:
        activity:test_dat_a@\myPVob   vonc        "test_dat_a"
Do you wish to continue with this deliver operation?  [no] yes
Checked out "M:\vonc_test_dat_int\adev\test\aFile.txt" from version "\main\Test_DAT_Int\2".
  Attached activity:
    activity:deliver.Test_DAT_A.20090707.124108@\myPVob  "deliver Test_DAT_A on 07/07/09 12:41:08 PM."
Needs Merge "M:\vonc_test_dat_int\adev\test\aFile.txt" [to \main\Test_DAT_Int\CHECKEDOUT from \main\Test_DAT_Int\Test_DAT_A\2 base \main
\Test_DAT_Int\2]
Trivial merge: "M:\vonc_test_dat_int\adev\test\aFile.txt" is same as base "M:\vonc_test_dat_int\adev\test\aFile.txt@@\main\Test_DAT_
Int\2".
Copying "M:\vonc_test_dat_int\adev\test\aFile.txt@@\main\Test_DAT_Int\Test_DAT_A\2" to output file.
Deliver has merged
M:\vonc_test_dat_a\adev\test>ct deliver -force -complete

(另一个简单的合并)

让我们在 Int 上设置一个基线:

M:\vonc_test_dat_a\adev\test>ct mkbl -nc -view vonc_test_dat_int TST_DAT1.1.0
Created baseline "TST_DAT1.1.0" in component "ADV_TST".
Begin incrementally labeling baseline "TST_DAT1.1.0".
Done incrementally labeling baseline "TST_DAT1.1.0".

现在,我们切换到 B,他从他自己在另一个文件上的一点工作开始:

M:\vonc_test_dat_b\adev\test>ct mkact test_dat_b
M:\vonc_test_dat_b\adev\test>echo myFile by B>aFileByB.txt
M:\vonc_test_dat_b\adev\test>ct co -nc .
M:\vonc_test_dat_b\adev\test>ct mkelem -nc aFileByB.txt
M:\vonc_test_dat_b\adev\test>ct ci -nc aFileByB.txt
M:\vonc_test_dat_b\adev\test>ct ci -nc .

然后,突然间,他不得不使用已在 Int 中合并的内容重新调整他的工作:

M:\vonc_test_dat_b\adev\test>ct rebase -bas TST_DAT1.1.0
Advancing to baseline "TST_DAT1.1.0" of component "ADV_TST"
Updating rebase view's config spec...
Creating integration activity...
Setting integration activity...
Merging files...
Checked out "M:\vonc_test_dat_b\adev\test\aFile.txt" from version "\main\Test_DAT_Int\Test_DAT_B\1".
  Attached activity:
    activity:rebase.Test_DAT_B.20090707.125044@\myPVob  "rebase Test_DAT_B on 07/07/09 12:50:44 PM."
Needs Merge "M:\vonc_test_dat_b\adev\test\aFile.txt" [to \main\Test_DAT_Int\Test_DAT_B\CHECKEDOUT from \main\Test_DAT_Int\3 base \main\T
est_DAT_Int\Test_DAT_A\1]
Trivial merge: "M:\vonc_test_dat_b\adev\test\aFile.txt" is same as base "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\
Test_DAT_A\1".
Copying "M:\vonc_test_dat_b\adev\test\aFile.txt@@\main\Test_DAT_Int\3" to output file.
Output of merge is in "M:\vonc_test_dat_b\adev\test\aFile.txt".
Recorded merge of "M:\vonc_test_dat_b\adev\test\aFile.txt".

M:\vonc_test_dat_b\adev\test>type aFile.txt
first line done on Int
Second line from Int
Addition by A to be delivered to B first
Modification by A to be delivered to Int, B does not need it

M:\vonc_test_dat_b\adev\test>ct rebase -complete

完全没有冲突:再次简单地合并

B 继续处理他的文件:

M:\vonc_test_dat_b\adev\test>ct setact test_dat_b
M:\vonc_test_dat_b\adev\test>ct co -nc aFileByB.txt
M:\vonc_test_dat_b\adev\test>echo a modif by B to be delivered to Int>>aFileByB.txt
M:\vonc_test_dat_b\adev\test>ct ci -nc aFileByB.txt

然后他将所有工作交付给 Int:

M:\vonc_test_dat_b\adev\test>ct deliver -cact
cleartool: Error: Activity "deliver.Test_DAT_A.20090707.123738" must be added to activity list to preserve baseline order in stream.
cleartool: Error: Activity "rebase.Test_DAT_B.20090707.125044" must be added to activity list to preserve baseline order in stream.
cleartool: Error: The list of activities specified is incomplete.
cleartool: Error: Unable to deliver selected activities.
cleartool: Error: Unable to deliver stream "Test_DAT_B".

我确实确认他必须选择所有活动(不仅仅是他的):在最后一次变基期间设置的时间线已将所有活动链接在一起。
即使不会对活动“deliver.Test_DAT_A.20090707.123738”和活动“rebase.Test_DAT_B.20090707.125044”进行合并,也必须包含它们:

M:\vonc_test_dat_b\adev\test>ct deliver
Changes to be DELIVERED to default target stream in project "Test_DeliverToAlternateTarget":
          FROM: stream "Test_DAT_B"
          TO: stream "Test_DAT_Int"
Using target view: "vonc_test_dat_int".
Activities included in this operation:
        activity:deliver.Test_DAT_A.20090707.123738@\myPVob   vonc        "deliver Test_DAT_A on 07/07/09 12:37:38 PM."
        activity:test_dat_b@\myPVob   vonc        "test_dat_b"
        activity:rebase.Test_DAT_B.20090707.125044@\myPVob    vonc        "rebase Test_DAT_B on 07/07/09 12:50:44 PM."
Do you wish to continue with this deliver operation?  [no]

  Attached activity:
    activity:deliver.Test_DAT_B.20090707.131614@\myPVob  "deliver Test_DAT_B on 07/07/09 1:16:14 PM."
Needs Merge "M:\vonc_test_dat_int\adev\test" [to \main\Test_DAT_Int\CHECKEDOUT from \main\Test_DAT_Int\Test_DAT_B\1 base \main\Test_DAT_
Int\1]
********************************
<<< directory 1: M:\vonc_test_dat_int\adev\test@@\main\Test_DAT_Int\1
>>> directory 2: M:\vonc_test_dat_int\adev\test@@\main\Test_DAT_Int\Test_DAT_B\1
>>> directory 3: M:\vonc_test_dat_int\adev\test
********************************
-----------[ directory 1 ]-------------|---------[ added directory 2 ]---------
                                      -| aFileByB.txt  --07-07T12:50 vonc
*** Automatic: Applying ADDITION from directory 2
Recorded merge of "M:\vonc_test_dat_int\adev\test".
Created branch "Test_DAT_Int" from "M:\vonc_test_dat_int\adev\test\aFileByB.txt" version "\main\0".
Checked out "M:\vonc_test_dat_int\adev\test\aFileByB.txt" from version "\main\Test_DAT_Int\0".
  Attached activity:
    activity:deliver.Test_DAT_B.20090707.131614@\myPVob  "deliver Test_DAT_B on 07/07/09 1:16:14 PM."
Needs Merge "M:\vonc_test_dat_int\adev\test\aFileByB.txt" [to \main\Test_DAT_Int\CHECKEDOUT from \main\Test_DAT_B\2 base \main\0]
Trivial merge: "M:\vonc_test_dat_int\adev\test\aFileByB.txt" is same as base "M:\vonc_test_dat_int\adev\test\aFileByB.txt@@\main\0".

Copying "M:\vonc_test_dat_int\adev\test\aFileByB.txt@@\main\Test_DAT_B\2" to output file.
Deliver has merged
M:\vonc_test_dat_b\adev\test>ct deliver -complete

.

于 2009-07-07T08:43:41.580 回答