Ben Jackson 的回答已经涵盖了总体思路,但我想在这里添加一些关于最终目标的注释(不仅仅是评论的价值)。
您可以很容易地拥有两个分支,一个具有完全干净的(无私有文件)历史记录,一个具有完整的(具有私有文件),并适当地共享内容。关键是要小心你如何合并。过于简单的历史可能看起来像这样:
o - o - o - o - o - o - o (public)
\ \ \ \
x ----- x ----x---- x - x (private)
o
提交是“干净”的提交,x
是包含一些私人信息的提交。只要您从公共合并到私有,它们都可以拥有所有所需的共享内容,而不会泄露任何内容。正如本所说,你确实需要小心这一点 - 你永远不能以其他方式合并。尽管如此,还是有可能避免的——而且你不必限制自己去采摘樱桃。您可以使用正常所需的合并工作流程。
当然,实际上,您的工作流程最终可能会稍微复杂一些。您可以在自己的分支上开发一个主题(功能/错误修复),然后将其合并到公共和私人版本中。你甚至可以时不时地挑选樱桃。真的,任何事情都会发生,除了将私人合并到公共之外。
过滤器分支
所以,你现在的问题只是让你的存储库进入这个状态。不幸的是,这可能非常棘手。假设存在一些涉及私有和公共文件的提交,我相信最简单的方法是使用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)
注意:这里有两个单独的根提交。这有点奇怪;如果你想避免它,你可以使用git rebase --root --onto <SHA1>
将整个私有临时分支移植到公共分支的某个祖先上。
如果你想要一些中间的完整版本,你可以做同样的事情,只是在这里和那里停下来合并和变基:
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...
这会给你一个类似这样的历史:
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
在任何变基上使用该选项来保留合并。
假装
编辑:如果修改历史真的很难处理,你总是可以完全捏造它:将整个历史压缩到一个提交,在你已经拥有的同一个根提交之上。像这样的东西:
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)
whereA
和A'
包含完全相同的内容,并且X
是您从公共分支中删除所有私有内容的提交。
此时,您可以将公共合并为私有,然后按照我在答案顶部描述的工作流程进行操作:
git checkout private
git merge -s ours public
-s ours
告诉 git 使用“我们的”合并策略。这意味着它将所有内容完全保留在私有分支中,并简单地记录一个合并提交,显示您将公共分支合并到其中。这可以防止 git 将那些“删除私有”更改从提交应用X
到私有分支。
如果根提交中包含私有信息,那么您可能想要创建一个新的根提交,而不是在当前提交之上提交一次。