我最近在开发一个API库,它将一个相对较大的外部API的一部分包装到一个更惯用的结构中。当我在编写原型代码时进行API探索时,我最终实现了三个具有不同功能程度的可用子API。或者更简单地说,我有一个结构上看起来像
的项目dir:root
└ dir:feature-a
└ dir:feature-b
└ dir:feature-c
└ dir:common
└ file:build.gradle
└ file:build.py
其中每个功能都与其中一个子API匹配。值得一提的是这些目录并不平坦,为了简单起见,我只是省略了子目录。
我的主要问题是,虽然我实际上只提供了一个半正式的版本历史,但它只在一个分支中,并且只有一个子API可以发布。理想情况下,我想找到最便捷的方式
我之前使用git filter-branch
用于类似目的,但这里的一个主要曲线球是存储库根目录实际上是另一个存储库 - 在元级别上,存储库有两个父母,当然这是 funky 并且对于使构建脚本保持最新非常有用但是如果我尝试用filter-branch
做我想要的东西,项目根目录下的构建脚本将被删除,这绝对不是我想要的。
最后,common
目录有点特别 - 我不介意削减其版本历史记录,只要其内容在那里。
答案 0 :(得分:4)
<强>摘要强>
如果您想保留某些公共资源(build.*
)的历史记录并在将来轻松合并这些资源,和您想要重写/过滤/删除子资源使用feature-a
在存储库(common
,git filter-branch
)中设置其他树的集合,您应该首先按顺序重写现有的提交:
build.*
,包括本地更改和上游Cradle的合并。feature-*
和common
。然后,您可以在项目特定的开发线上安全地运行git filter-branch
,而无需重写任何上游资源历史记录。如果你不这样做,你可能会最终重写涉及构建脚本的提交,包括来自上游Cradle的merge-commit,这将禁止历史可追溯性和未来的合并。
<强>详细强>
听起来你有一个黄金项目模板,称之为T
,每次你开始一个新项目时,你都会分叉这个回购(无论是在传统的GitHub意义上,还是只是创建将会是什么一个不同的克隆)称之为Pn
。因此Pn
和T
以相同的历史记录和常见提交开头(称为分支点Pn-0
)。
当Pn
开发其代码库时,其他项目可能会识别对基础项目模板基础结构的改进,并对F
中的文件T
进行更改。任何项目Pn
(可能在模板前面提交数百次提交)仍然可以合并T
中常见文件的更改。
现在,您想要在Pn
中重写历史记录。从Pn-0
开始,您已经进行了许多项目特定的提交,然后是T
的合并,然后是更多项目特定的提交。如果您必须将P
重新设置回Pn-0
以便filter-branch
,则T
的合并历史记录将丢失,因为历史记录已经分歧,未来将从{{}}合并{1}}变得地狱般的。
这是否描述了您的问题?
我认为您正在看到,当您希望完全自由地重写历史记录以重新组织项目回购时,使用项目克隆从模板方法有其局限性。如果您在T
合并提交之前和之后都有历史记录,那么您将不得不进行一些奇特的重组以保留共同的历史记录。那个解决方案是:
T
成为Tx
的最新提交,您已完全合并到T
。Pn
提取到T
回购中,并在Pn
中创建一个以提交Pn
开头的分支。Tx
历史记录重新定位到该分支上,将其从Pn
(常见提交Pn-0
)移至T
,最新的常见提交{ {1}}。此方法将在Tx
中重播您的整个历史记录,就像它以T
而不是Pn
开头一样,因此提交Tx
有一个新的父Pn-0
。当然,每个提交都将被重写,因此Pn-1
的任何现有克隆都会立即成为孤立状态。
完成此操作后,您可以从重写的提交Tx
开始运行Pn
,并删除任何不完整模块的历史记录。
现在 - 这是一个相当大的麻烦,并以棘手的方式重写历史,但历史将保留。你不想每天都在做这个过程。
您可能想要考虑的一件事是,是否有任何方式可以在没有源共享的情况下生成和使用您的摇篮。它可能不像Git-merge一样方便,但如果您的模板项目是版本控制的并且您organize your build logic并且可能使用shared scripts,那么您可以模块化您的模板项目,这样您就不再依赖于孩子 - 项目维护共同的源历史以便合并 - 他们只会使用最新的模板二进制文件。取决于构建逻辑以外的模板中的内容。