代码之家  ›  专栏  ›  技术社区  ›  David Claridge

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

  •  19
  • David Claridge  · 技术社区  · 15 年前

    我们有两个分支 主人 释放 , 包含一些我们决定不发布的专有组件,以及 释放 释放 分支到github,可以通过查看修订历史来检索专有组件。

    我在考虑创建一个单独的存储库,复制 放松 git init ,并将存储库推送到github。但是,我们希望保留从 主人 释放 在未来,将这些更改推送到github。

    谢谢!

    更新:

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

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

    主人 ,property branch,'c'是删除不应发布的内容的提交(通常不删除整个文件,但重写现有文件以不依赖于专有组件),而'f'是在 主人 适用于 释放 同样,也被樱桃采摘。REL是我们认为可以安全发布的代码的标记版本,没有任何历史记录(甚至是发布分支的以前版本,因为并不是所有的专有资料都在REL标记之前被删除)。

    2 回复  |  直到 15 年前
        1
  •  17
  •   Cascabel    15 年前

    本·杰克逊的回答已经涵盖了这个基本概念,但是我想在这里补充一些关于最终目标的注释(不仅仅是一个评论的价值)。

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

    o - o - o - o - o - o - o (public)
     \       \           \   \
      x ----- x ----x---- x - x (private)
    

    这个 o x 是包含一些私人信息的。只要您从公共合并到私有,它们都可以拥有所需的所有共享内容,而不会泄漏任何内容。正如本所说,你确实需要小心这一点-你永远不能以其他方式合并。尽管如此,还是有可能避免——而且你不必局限于采摘樱桃。您可以使用正常的所需合并工作流。

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

    过滤支管

    所以,您现在的问题只是让您的存储库进入这种状态。不幸的是,这可能相当棘手。假设存在一些涉及私有和公共文件的提交,我相信最简单的方法是 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)
    

    哪里 A A' X 是从公共分支中删除所有私有内容的提交。

    此时,您可以将public合并为private,从那时起,按照我在回答顶部描述的工作流进行操作:

    git checkout private
    git merge -s ours public
    

    这个 -s ours 告诉git使用“ours”合并策略。这意味着它将所有内容完全保留在私有分支中,并简单地记录一个合并提交,显示您将公共分支合并到其中。这将防止git从commit中应用那些“remove private”更改 去私人分行。

        2
  •  5
  •   Ben Jackson    15 年前

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

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

    您应该能够运行filter branch命令,从“clean”提交创建新的提交。历史会有些奇怪(旧版本可能无法构建,因为它们现在不完整或已损坏)。这不会销毁存储库中的任何现有分支或blob。它将创建所有新的(并行的)共享文件blob但不共享树或提交的文件blob。您应该能够安全地推送该分支,而不公开它不引用的任何对象(推送分支时,只推送由该分支命名的SHA及其依赖项)。然而,这有点冒险,因为 git merge 进入“clean”分支,你可能会拖入“private”分支和对象。您可能需要使用钩子(提交或推送触发器)来双重检查私有文件是否没有转义。

    推荐文章