我的组织正准备使用github发布我们软件的开源版本,但是我不确定解决这个问题的最佳方法:
我们有两个分支master和release,master包含一些我们决定不发布的专有组件,release包含我们想要分发的清理版本.问题是,如果我们只是将发布分支推送到github,可以通过查看修订历史来检索专有组件.
我正在考虑创建一个单独的存储库,将HEAD of relase复制到其中,执行a git init
,并将该存储库推送到github.但是,我们希望保留能够在将来从主服务器中挑选某些补丁到发布的能力,并将这些更改推送到github.
有没有办法在不维护两个separte存储库的情况下执行此操作?
谢谢!
更新:
更具体一点,这就是我们的提交历史目前的样子:
--- o - o - o - o - f - o - o - f - master \ c - c - c - c - c - c - c - REL - f - f
'o'是master,专有分支中的提交,'c'是提交,删除不应发布的内容(通常不会删除整个文件,但重新处理现有文件不依赖于专有组件),'f'是修复了适用于发布的大师,因此被挑选出来.REL是我们认为可以安全发布的代码的标记版本,没有任何历史记录(甚至是发布分支的早期版本,因为并非所有专有材料都在REL标记之前被删除).
本杰克逊的答案已经涵盖了一般的想法,但我想在这里添加一些关于最终目标的笔记(不仅仅是评论的价值).
您可以很容易地拥有两个分支,一个具有完全干净(无私有文件)历史记录,一个完整(具有私有文件),并且可以适当地共享内容.关键是你要如何合并.过度简化的历史记录可能如下所示:
o - o - o - o - o - o - o (public) \ \ \ \ x ----- x ----x---- x - x (private)
o
提交是"干净的",x
包含一些私人信息的提交.只要您从公共合并到私有,它们都可以拥有所有所需的共享内容,而不会泄漏任何内容.正如Ben所说,你需要小心这一点 - 你不可能以其他方式合并.尽管如此,它仍然可以避免 - 而且你不必限制自己采摘樱桃.您可以使用正常的所需合并工作流程.
实际上,当然,您的工作流程最终会变得复杂一些.您可以在自己的分支上开发主题(feature/bugfix),然后将其合并到公共版本和私有版本中.你甚至可以偶尔选择樱桃.真的,任何事情都有,除了将私人合并到公众之外的关键例外.
过滤分支所以,你现在的问题只是让你的存储库进入这种状态.不幸的是,这可能非常棘手.假设存在一些涉及私有和公共文件的提交,我相信最简单的方法是使用filter-branch
创建公共(干净)版本:
git branch public master # create the public branch from current master git filter-branch --tree-filter ... -- public # filter it (remove private files with a tree filter)
然后创建一个临时的仅限私有分支,仅包含私有内容:
git branch private-temp master git filter-branch --tree-filter ... -- private-temp # remove public files
最后,创建私有分支.如果您只有一个完整版本,那么您可以简单地合并一次:
git branch private private-temp git merge public
那将只给你一个只有一个合并的历史:
o - o - o - o - o - o - o - o - o - o (public) \ x -- x -- x -- x -- x -- x -- x --- x (private)
注意:这里有两个单独的root提交.这有点奇怪; 如果你想避免它,你可以使用git rebase --root --onto
将整个私有临时分支移植到公共分支的某个祖先.
如果您想要一些中间完整版本,您可以做同样的事情,只需在此处停止合并和变基:
git checkout -b private# use the SHA1 of the first ancestor of private-temp # you want to merge something from public into git merge # merge a corresponding commit of the public branch git rebase private private-temp # rebase private-temp to include the merge git checkout private git merge # use the next SHA1 on private-temp you want to merge into # this is a fast-forward merge git merge # merge something from public git rebase private private-temp # and so on and so on...
这会给你一个像这样的历史:
o - o - o - o - o - o - o - o - o - o (public) \ \ \ x -- x -- x -- x -- x -- x -- x --- x (private)
同样,如果你想让他们拥有一个共同的祖先,你可以做一个初始的git rebase --root --onto ...
开始.
注意:如果您已在历史记录中进行合并,则需要-p
在任何rebase上使用该选项来保留合并.
编辑:如果重新编写历史记录真的是难以处理的话,你总是可以完全捏造它:将整个历史记录压缩到一个提交,在你已经拥有的相同根提交之上.像这样的东西:
git checkout public git reset --softgit commit
所以你最终会得到这个:
o - A' (public) \ o - x - o - x - X - A (public@{1}, the previous position of public) \ x - x (private)
where A
和A'
包含完全相同的内容,并且X
是从公共分支中删除所有私有内容的提交.
此时,您可以将公共单独合并为私有,从那时起,按照我在答案顶部描述的工作流程:
git checkout private git merge -s ours public
该-s ours
告诉混帐使用"我们"合并策略.这意味着它将所有内容保留在私有分支中,并简单地记录合并提交,显示您将公共分支合并到其中.这可以防止git将这些"删除私有"更改从提交应用X
到私有分支.
如果根提交中包含私有信息,那么您可能希望创建一个新的根提交,而不是在当前提交之前提交一次.
提交的SHA基于提交blob,其中包括父SHA,提交文本和文件树的SHA.树包含树中每个blob的SHA.因此,任何给定的提交都依赖于该修订中的所有内容以及每个父修订版返回到空的存储库.如果您从包含您不想发布的文件的版本(无论多么间接)派生提交,那么您不希望发布该分支.
git filter-branch
关于从存储库中删除机密文件的第一个例子.它通过创建备用历史记录(重写所有树和提交)来完成此操作.如果你理解我的答案的第一部分,你就会明白为什么这一定是真的.
您应该能够运行filter-branch命令以从"干净"提交创建新提交.历史将有点奇怪(旧版本可能无法构建,因为它们现在不完整或以其他方式破坏).这不会破坏存储库中的任何现有分支或blob.它将创建所有共享文件blob但不共享树或提交的新(并行)文件.您应该能够安全地推送该分支而不暴露任何它不引用的对象(当您推送分支时,只有该分支命名的SHA及其依赖项被推送).但是,这有点冒险,因为一个git merge
进入"干净"分支,你可能最终拖入"私人"分支和对象.您可能希望使用钩子(提交或推送触发器)来仔细检查私有文件是否未转义.