将git回购的分支推送到新的远程(github),隐藏其历史记录

将git回购的分支推送到新的远程(github),隐藏其历史记录,git,github,git-branch,remote-branch,Git,Github,Git Branch,Remote Branch,我的组织正准备使用github发布我们软件的开源版本,但我不确定实现这一点的最佳方法: 我们有两个分支master和release,master包含一些我们决定不发布的专有组件,release包含我们想要发布的清理版本。问题是,如果我们只是将发行版分支推到github,那么可以通过查看修订历史来检索专有组件 我正在考虑创建一个单独的存储库,将relase的头部复制到其中,执行git init,并将该存储库推送到github。但是,我们希望保留在将来将某些补丁从master挑选到release的能

我的组织正准备使用github发布我们软件的开源版本,但我不确定实现这一点的最佳方法:

我们有两个分支masterreleasemaster包含一些我们决定不发布的专有组件,release包含我们想要发布的清理版本。问题是,如果我们只是将发行版分支推到github,那么可以通过查看修订历史来检索专有组件

我正在考虑创建一个单独的存储库,将relase的头部复制到其中,执行
git init
,并将该存储库推送到github。但是,我们希望保留在将来将某些补丁从master挑选到release的能力,并将这些更改推送到github

有没有一种方法可以在不维护两个单独的存储库的情况下做到这一点

谢谢

更新:

更具体地说,我们的提交历史目前是这样的:

--- o - o - o - o - f - o - o - f - master
             \
              c - c - c - c - c - c - c - REL - f - f

其中,“o”是主文件中的提交,专有分支,“c”是删除不应发布的内容的提交(通常不删除整个文件,但修改现有文件以不依赖专有组件),而“f”是主文件中的修复程序,也适用于发布,樱桃也是如此。REL是我们认为可以安全发布的代码的一个标记版本,没有任何历史记录(甚至是发布分支的早期版本,因为在REL标记之前并没有删除所有专有材料)。

提交的SHA基于提交blob,其中包括父SHA、提交文本和文件树的SHA。这棵树包含树上每个斑点的SHA。因此,任何给定的提交都依赖于该修订中的所有内容,并且每个父修订都返回到一个空的存储库。如果您有一个从包含您不想发布的文件的版本(无论多么间接)派生的提交,那么您就不想发布该分支

git filter branch
的第一个示例谈到从存储库中删除机密文件。它通过创建备用历史记录(重写所有树和提交)来实现这一点。如果你理解我答案的第一部分,你就会明白为什么这一定是真的


您应该能够运行过滤器分支命令,从“干净”提交创建新的提交。历史记录会有些奇怪(旧版本可能无法构建,因为它们现在不完整或已损坏)。这不会破坏存储库中的任何现有分支或blob。它将创建所有新的(并行的)共享文件blob而不是树或提交的文件。您应该能够安全地推送该分支,而不暴露它未引用的任何对象(推送分支时,只推送该分支命名的SHA及其依赖项)。但是,这会有一定的风险,因为一个
git合并到“clean”分支中,最终可能拖入“private”分支和对象。您可能希望使用钩子(提交或推送触发器)来双重检查私有文件是否未转义。

本·杰克逊的回答已经涵盖了一般思路,但我想在这里补充一些关于最终目标的注释(比评论更重要)

您可以很容易地拥有两个分支,一个具有完全干净的(无私有文件)历史记录,另一个具有完整的(私有文件)历史记录,并适当地共享内容。关键是要注意合并的方式。过于简单化的历史可能是这样的:

o - o - o - o - o - o - o (public)
 \       \           \   \
  x ----- x ----x---- x - x (private)
o - o - o - o - o - o - o - o - o - o (public)
      \              \               \
  x -- x -- x -- x -- x -- x -- x --- x (private)
git checkout public
git reset --soft <root SHA1>
git commit
o
提交是“干净”提交,
x
是包含一些私人信息的提交。只要您将公共内容合并到私有内容,它们都可以拥有所需的所有共享内容,而不会泄露任何内容。正如本所说,你确实需要注意这一点——你永远不能以另一种方式合并。尽管如此,还是有可能避免——而且你不必把自己局限于采摘樱桃。您可以使用所需的正常合并工作流

当然,在现实中,您的工作流程可能会变得更加复杂。您可以在自己的分支上开发一个主题(特性/错误修复),然后将其合并到公共和私有版本中。你甚至可以时不时地摘樱桃。真的,任何事情都会发生,除了将私有合并到公共之外

滤波支路 所以,您现在的问题只是让您的存储库处于这种状态。不幸的是,这可能相当棘手。假设存在一些涉及私有和公共文件的提交,我认为最简单的方法是使用
过滤器分支
创建公共(干净)版本:

然后创建一个仅包含私有内容的临时私有分支:

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)
注意:这里有两个单独的根提交。这有点奇怪;如果要避免这种情况,可以使用
git-rebase--root--on
将整个私有临时分支移植到公共分支的某个祖先上

如果您想拥有一些中间完整版本,您可以执行完全相同的操作,只需在此处或此处停止合并并重新设置基础:

git checkout -b private <private-SHA1>  # use the SHA1 of the first ancestor of private-temp
                                        # you want to merge something from public into
git merge <public-SHA1>           # 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 <private-SHA1>          # use the next SHA1 on private-temp you want to merge into
                                  # this is a fast-forward merge
git merge <public-SHA1>           # merge something from public
git rebase private private-temp   # and so on and so on...
同样,如果您希望它们有一个共同的祖先,您可以开始使用初始的
git-rebase--root--to…

注意:如果您的历史记录中已经有合并,您需要在任何回退上使用
-p
选项来保留合并

假装 编辑:如果对his进行返工
git checkout public
git reset --soft <root SHA1>
git commit
o - A' (public)
 \
  o - x - o - x - X - A (public@{1}, the previous position of public)
               \
                x - x (private)
git checkout private
git merge -s ours public