灵活vs静态分支(Git vs Clearcase / Accurev)

我的问题是关于Git处理分支的方式:每当你从一个提交分支,这个分支将永远不会收到来自父分支的变化,除非你强制合并。

但在Clearcase或Accurev等其他系统中,您可以指定分支如何填充某种inheritance机制 :我的意思是,使用Clearcase,使用config_spec,可以说“获取在branch / main / issue001上修改的所有文件,然后继续进行/主要或这个特定的基线“。

在Accurev中,你也有一个类似的机制让我们的stream接收来自上层分支的变化(stream如何调用它们)而不合并或在分支上创build新的提交。

使用Git的时候不要错过这个东西? 你能枚举这种inheritance是必须的场景吗?

谢谢

更新请阅读下面的VonC答案,以真正关注我的问题。 一旦我们同意“线性存储”和基于DAG的SCM有不同的能力,我的问题是: 哪些是真正的生活场景(特别是对于比OSS更多的公司)线性可以做DAG不可能的事情? 他们值得吗?

要理解为什么Git不提供某种你所指的“inheritance机制”(不涉及提交),你必须首先理解那些SCM的核心概念之一(例如Git vs. ClearCase)

  • ClearCase使用线性版本存储 :元素(文件或目录)的每个版本与相同元素的先前版本以直接线性关系链接。

  • Git使用DAG 指导的无环图 :文件的每个“版本”实际上是树中全局变化的一部分,树本身就是提交的一部分。 以前的版本必须在以前的提交中find,可以通过单个有向非循环图path访问。

在一个线性系统中,configuration规范可以指定几个规则来实现你所看到的“inheritance”(对于一个给定的文件,首先select一个特定的版本,如果不存在,则select另一个版本,如果不存在,则select一个第三等等)。

分支是给定select规则的给定版本的线性历史logging中的分支(所有其他select规则在该规则之前仍然适用,因此是“inheritance”效应)

在一个DAG中,一个提交代表了所有你将获得的“inheritance” 没有“累积”版本的select。 在这个图中只有一个path来select你将在这个确切点上看到的所有文件(提交)。
分支只是这个图中的一条新path。

要在Git中应用其他一些版本,您必须:

  • 合并到你的分支一些其他的提交(如在STSQUAD的回答中提到的git pull)或者
  • 重新分配你的分支( 格雷格提到 )

但是由于Git是一个基于DAG的SCM,它总是会导致一个新的提交。

你用Git“输”的是某种“组合”(当你select具有不同的连续select规则的不同版本时),但在D VCS中(如“分布式”)则不实用:当你使用Git做分支,你需要这样做,一个起点和一个内容明确定义,并容易复制到其他存储库。

在纯粹的中央VCS中,您可以使用您想要的任何规则来定义您的工作空间(在ClearCase中,您的“视图”,快照或dynamic)。


未知谷歌添加在评论(和在他的问题上面):

所以,一旦我们看到两个模型可以实现不同的事情(线性和DAG),我的问题是:哪些是真正的生活场景(特别是对于公司而不是OSS)线性可以做DAG不可能的事情? 他们值得吗?

就select规则而言,当谈到“现实生活场景”时,在线性模型中你可以做的是对同一组文件几个select规则。

考虑这个“configuration规范”(即“ClearCaseselect规则的configuration规范”):

element /aPath/... aLabel3 -mkbranch myNewBranch element /aPath/... aLabel2 -mkbranch myNewBranch 

它select标签为“ aLabel2 ”(以及从那里分支)的所有文件,除了那些标记为“ aLabel3 ”的文件以及从那里分支的文件(因为该规则在提及“ aLabel2 ”的那个之前)。

这值得么?

没有。

事实上,ClearCase的UCM风格(ClearCase产品包含的“ 统一configurationpipe理 ”方法,代表从基本ClearCase的使用中推导出的所有“最佳实践”)不允许出于简化的原因。 一组文件被称为一个“组件”,如果你想分支一个给定的标签(称为“基线”),那么将会像下面的configuration规范那样翻译:

 element /aPath/... .../myNewBranch element /aPath/... aLabel3 -mkbranch myNewBranch element /aPath/... /main/0 -mkbranch myNewBranch 

你必须select一个起点(这里是' aLabel3 '),然后从那里出发。 如果您还想从“ aLabel2 ”中find文件,则将从“ aLabel2 ”文件合并到“ aLabel2 ”文件中。

这是一个“简化”,你不必使用DAG,图中的每个节点代表一个分支的唯一的“起点”,无论涉及的是哪一组文件。

合并和重新定义足以将该起点与给定文件集合的其他版本结合起来,以便实现所需的“组合”,同时在分支中保持该特定的历史logging。

总体目标是在“适用于相关组件的连贯版本控制操作”中进行推理。 一个“连贯的”文件集是一个明确的连贯的状态:

  • 如果贴了标签, 所有的文件都被标记
  • 如果分支, 所有文件将从相同的唯一起点分支

这很容易在DAG系统中完成。 在线性系统中(特别是“configuration规范”可能会非常棘手的“BaseCaseCase”),可能会更困难,但是它是通过同一个线性工具的UCM方法实施的。

不是通过“私人select规则技巧”(使用ClearCase,某些select规则顺序)来实现这个“组合”,而只是通过VCS操作(重新绑定或合并)来实现,这留下了一个清晰的跟踪供大家遵循到开发者私有的configuration规范,或者在一些开发者中共享的configuration规范)。 同样,它强化了一致性的感觉, 而不是“dynamic的灵活性”,以后可能很难再生成

这使得您可以离开VCS(版本控制系统)的领域,进入SCM(软件configurationpipe理)领域 ,主要关注“可重复性 ”。 而且(SCMfunction)可以通过基于线性或基于DAG的VCS实现。

这听起来像你正在寻找可能是git rebase 。 从概念上重新分支一个分支从原来的分支点分离,并在其他点重新附加它。 (实际上,通过将每个分支的每个分支顺序应用到新的分支点,创build一组新的分支来实现rebase。)在您的示例中,您可以将分支重新绑定到上部分支的当前尖端,将基本上“inheritance”对其他分支所做的所有更改。

我不完全清楚你的要求,但听起来像git的跟踪语义是你想要的。 当你从原产地分支时,你可以做如下的事情:

git -t -b my_branch origin / master

然后未来的“git pull”会自动将origin / master合并到你的工作分支中。 然后你可以使用“git cherry -v origin / master”来看看有什么不同。 你可以使用“git rebase”在发布你的修改来清理历史logging之前,但是一旦你的历史logging被公开(也就是其他人关注这个分支),你就不应该使用rebase。

至于accurev使用的inheritancescheme:GIT用户在看git-flow时可能会“得到”整个事情(参见: http : //github.com/nvie/gitflow和http://jeffkreeftmeijer.com/ 2010 / why-are-you-using-git-flow / )

这个GIT分支模型或多或less地(手动/借助于git-flow工具)自动进行开箱即用,并且具有良好的 GUI支持。

所以看来 GIT可以做什么accurev。 因为我从来没有真正使用过git / git-flow,所以我不能真正说出它是如何工作的,但它看上去很有前景。 (减去适当的GUI支持:-)

我会尽力回答你的问题。 (我必须在这里说,我没有使用GIT只读了它,所以如果我下面提到的是错误的,请纠正我)

“你能列举这种inheritance是必须的吗?

我不会说这是必须的,因为你可以用你拥有的工具解决问题,并且可能是你的环境的有效解决scheme。 我想这比工具本身更重要。 确保你的过程是连贯的,也让你回到过去的时间重现任何中间步骤/状态是目标,而且这个工具让你运行你的过程和南华早报尽可能无痛苦

我可以看到的一个场景是拥有这个“inheritance”行为,并且使用configuration规范的强大function,当你想将你的一组变化“ 孤立 ”映射到一个任务(devtask,CR,SR或者其他的定义您的变更集的目的/范围)

使用这个组合可以让你的开发分支变得干净,并且仍然使用其他代码的不同组合(使用组合),而且在任务整个生命周期中,仍然只有分支中孤立任务的相关内容,直到整合阶段。

纯粹主义者为了拥有一个“定义的起点”而不得不提交/合并/重新定义,我想它会“ 污染 ”你的分支,最终你的更改+其他分支/更改集中的更改。

何时/何地这种隔离有用? 下面的要点可能只适用于追求CMM和一些ISOauthentication的公司的背景,对于其他types的公司或OSS可能没有兴趣

  • 如果您真的很挑剔,那么您可能需要精确地统计与单个开发人员相对应的变更集的代码行(添加/修改/删除),稍后将其用作代码和工作量估算的一个input。

  • 在不同的阶段查看代码会比较容易,只需将代码放在一个分支中(不要与其他更改绑定)

在有几个团队和+500开发人员的大型项目中,他们同时在相同的基本代码上同时工作(graphics化单个元素版本树看起来像一个凌乱的networking,有多个装载线,每个大客户一个,或者每个技术一个)使用深度为几度的构图的规格使得这个量的人们无缝地工作以使相同的产品/系统(基本代码)适应不同的目的。 使用这个configuration规范,dynamic地给每个团队或子团队,不同的视图,他们需要什么,他们需要从哪里分支,(在多个案例级联),而不需要创build中间整合分支,或不断地合并和重新绑定你需要开始的位。 来自同一任务/目的的代码是分支不同的标签,但是有意义的。 (你可以在这里将'已知基线'作为SCM的一个原则来讨论,但是在一个书面的SCM计划中考虑的简单标签做了这项工作)必须有可能用GIT解决这个问题(我猜测是以一种非dynamic的方式)如果没有这种“inheritance”行为,真的很难想象。 我想VonC提到的“如果分支,所有的文件将从同一个独特的起点”分支的点被打破在这里,但除了它在南华早报有很好的logging,我记得有这么做的强大的商业理由。

是的,构build上面提到的configuration规范并不是免费的,一开始在SCM后面有4-5个收入丰厚的人,但后来被自动脚本降低了,并且在标签/分支/function方面问你想要什么为你写CS。

这里的可重复性是通过将configuration规范与任务一起保存在devTask系统中来实现的,所以每个上行任务映射到需求,下行映射到configuration规范,一组更改(代码文件,devise文档,testing文档等等)

所以在这里可以得出一个结论,只有当你的项目足够复杂时(你可以在项目的整个生命周期中支付SC经理)),那么你只会开始思考,如果你需要“inheritance”的行为或真的是多才多艺的工具,否则你会直接去一个免费的工具,并已经照顾你的SCM一致性…但SCM工具上可能有其他因素,可能会使你坚持一个或另一个..阅读

一些方面的说明,这可能是脱离主题,但我想在一些像我的情况需要考虑。

我必须在这里补充一点,我们使用“好-OL CC”而不是UCM。 完全同意VonC 一个好的方法论可以“引导”灵活性,以获得更一致的configuration 。 好的是,CC是非常灵活的,你可以find(不是没有一些努力)一个很好的方式,让其他的SCM,而你可能是免费的。 但是,例如在C / C ++项目中(和我一起工作的其他地方),我们不能承受没有winkin特性(重用Derive对象)的代价,这会减less几十倍的编译时间。 可以认为,拥有更好的devise,更多的解耦代码以及优化Makefiles可以减less编译整个事情的需要,但是有些情况下,您需要每天多次编译整个野兽,共享DO save时间/金钱堆。 现在,我们尽量使用尽可能多的免费工具,而且我认为如果我们能够find一个实现winkinfunction的更便宜或免费的工具,我们将摆脱CC。

我会用Paul提到的一些东西来完成, 不同的工具更适合不同的目的,但是我会补充一点,你可以通过一个连贯的过程来避免某些工具的局限性,而且不会影响再现性,关键点在于SCM In最后我猜这个答案是值得的? 取决于你的“问题”,你正在运行的SDLC,你的SCM进程,以及是否有任何额外的function(如winkin)在你的环境中可能是有用的。

我的2美分

除了理论之外,从我的angular度来看,在商业生产环境中使用AccuRev已有很多年了,这里有一个明显的实践:inheritance模型运行良好,只要子stream与祖先没有太大的分歧仍在发展中。 当inheritancestream太不同了,它就会崩溃。

inheritance(更新版本作为较早版本的子版本)允许祖先stream中的变化在子stream中处于活动状态,而不需要任何人做任何事情(除非需要合并,在这种情况下,它显示为深度重叠,这是很好的能够看到)。

这听起来不错,实际上,当涉及到的所有stream都比较相似时。 我们将该模型用于指定生产版本下的修补程序和服务包级别stream。 (这实际上比我们更复杂一些,但这是一般的想法。)

生产版本是并行的,没有inheritance,在每个版本下面有这些修补程序和Service Pack子项。 开始一个新版本意味着创build一个新的版本级别的stream,并手动将最新版本的维护stream中的所有内容都推送到其中。 之后,更早版本适用于以后版本的更改必须手动推送到每个版本中,需要更多的工作,但允许更多的控制。

我们最初在所有版本中使用了inheritance模型,后来的版本是早期版本的子版本。 这一段时间运行良好,但随着时间的推移变得难以pipe理。 各版本之间的主要架构差异不可避免地inheritance了一个糟糕的想法。 是的,你可以在它们之间放置一个快照来阻止inheritance,但是所有的修改都必须手动推送,父快照子和并行非inheritancestream之间的唯一真正区别是整个graphicsstream视图不断地下压和右边,这是一个PITA。

AccuRev的一个非常好的事情就是你总是有这个select。 这不是SCM程序架构的固有限制。

你有没有注意到你也可以使用GIT检出特定的文件版本?

只需使用这个:

 git checkout [< tree-ish >] [--] < paths > 

像每个configuration规范一样,文件(path)的任何现有版本都可以加载到工作树中。 从git-checkout文档引用:

以下序列检出主分支,将Makefile恢复为两个版本,错误地删除hello.c ,并从索引中取回:

 $ git checkout master $ git checkout master~2 Makefile $ rm -f hello.c $ git checkout hello.c 

没有MultiSite的ClearCase是一个存储库,但是Git是分布式的。 ClearCase在文件级别提交,但Git在存储库级别提交。 (这个最后的区别意味着原来的问题是基于一个误解,正如在这里的其他职位所指出的那样。)

如果这些是我们正在讨论的差异,那么我认为“线性”与“DAG”是区分这些SCM系统的一种令人困惑的方式。 在ClearCase中,文件的所有版本都被称为文件的版本“树”,但实际上它是一个有向的非循环图! Git的真正区别在于ClearCase的DAG存在于每个文件中。 所以我认为将ClearCase作为非DAG和Git称为DAG是误导性的。

(顺便说一下,ClearCase以类似于文件的方式对其目录进行了版本化 – 但这是另外一回事。)

我不确定你是否问任何问题,但是你正在certificateAccurevstream是不同于Git(或SVN)分支的工具。 (我不知道Clearcase。)

例如,在Accurev中,如您所说,您被迫使用某些工作stream程,这会给您提供Git中不支持的可更改的可审计历史logging。 Accurev的inheritance使得某些工作stream程更有效率,而其他工作stream程则不可能。

使用Git,您可以在本地回购站或特色分支中分离探索性编码,这不会得到Accurev的支持。

不同的工具适用于不同的目的; 询问每个人的优点是很有用的