代码之家  ›  专栏  ›  技术社区  ›  anthony

使用git子树合并,同时也合并所有合并子树的所有分支

  •  8
  • anthony  · 技术社区  · 15 年前

    我想使用一个流行的开源问题跟踪器(Redmine),它提供了Git集成。不幸的是,跟踪器中的每个项目只能与一个Git回购相关联。在跟踪器中创建多个项目不是我理想的设置。

    考虑到这一点,我尝试使用Git子树合并(解释说 here here )我已经创建了一个“伞式”回购,它已经合并到我正在处理的众多其他回购中的每一个。

    不幸的是,给出的示例只拉入每个子树的主分支。因为我在每个子树的多个分支中进行开发,所以我需要学习如何让这个伞形repo反映每个子树的每个分支。

    这有可能吗?

    额外学分:如果两个子树都有一个同名的分支怎么办?

    1 回复  |  直到 15 年前
        1
  •  7
  •   Chris Johnsen    15 年前

    对于我们中不熟悉Redmine的人,请扩展您的描述以包括以下问题的答案:追踪器需要什么样的访问存储库?它需要做出自己的承诺吗?或者,它是否只需要某些类型的读访问(可能是为了验证提交哈希并扫描提交日志中的关键字)?

    如果您的跟踪器只需要读取权限,那么您可能根本不需要合并任何子树。在单个存储库中有多个初始提交(允许多个独立的历史记录)是完全可以接受的。Git项目本身就是为一些额外的项目做这个的。( 男人 , HTML , 托多 )它不与共享(提交)历史记录,但与源代码的主要分支集一起发布。( 维恩特 , 主人 , 下一个 , 聚氨基甲酸酯 )就您的目的而言,为每个子存储库设置一个远程文件,并将它们的分支提示提取到聚合存储库中就足够了。也许自动远程跟踪分支就足够了,或者您可能需要采取额外的步骤来创建(和更新)基于远程跟踪分支的本地分支。

    您描述的子树合并方案在源存储库中的分支不相关或只有半相关的一般情况下可能没有意义。但是,如果所有源存储库共享一组分支,其中每个分支都有一个在所有存储库中相同的给定用途,那么您可能会有意义地将它们合并到一种超级存储库中。

    但有趣的问题不是如果两个存储库有同名的分支怎么办?__,但是_如何处理存储库缺少共享的__全局_集分支的情况?艾斯。

    如果所有子存储库都有相同的分支集,那么您只需执行您所做的操作。 主人 ,但每个分支一次。当存储库中缺少某个特定分支时,就会出现问题。你可以用它代替 主人 但这并不总是正确的答案。这取决于为什么您首先要将存储库聚合在一起,以及您希望在超级存储库分支的子树中看到什么。

    如果子存储库是 密切相关,那么我真的对这种子树方法的合理性有怀疑。对于不相关的存储库来说,这样的方法似乎与谷物相反。这可能仍然是可能的,但我怀疑是否有任何工具可以帮助您,您需要花费一些时间来计划解决这些棘手的问题。

    如果您最终坚持使用子树合并,那么您可能会看到第三方 git subtree 命令。它可能有助于保持无数存储库的同步。


    收集分支,不合并

    如果Redmine指定 --mirror 克隆,这意味着它需要本地分支,可能无法直接读取__远程跟踪分支,因此您可能需要创建和更新一些本地分支。

    本地分支更新自_远程跟踪分支_
    • 初始设置

      mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
      git init
      git remote add alpha <url/path-to-alpha-repo>
      git remote add bravo <url/path-to-bravo-repo>
      git remote add charlie <url/path-to-charlie-repo>
      for r in $(git remote); do
          git config --add remote.$r.fetch \
            "$(git config remote.$r.fetch | sed -e 's.heads.tags.;s.remotes.tags/all.')"
          git config remote.$r.tagopt --no-tags
      done
      
    • 周期性更新

      git remote update
      git for-each-ref --shell --format \
        'git branch --force --track -l all/%(refname:short) %(refname:short)' refs/remotes \
        | sh
      
    直接接收提取的分支提示的本地分支
    • 初始设置

      mkdir $COLLECTION_REPO && cd $COLLECTION_REPO &&
      git init
      git remote add alpha <url/path-to-alpha-repo>
      git remote add bravo <url/path-to-bravo-repo>
      git remote add charlie <url/path-to-charlie-repo>
      for r in $(git remote); do
          git config remote.$r.fetch \
            "$(git config remote.$r.fetch | sed -e 's.remotes.heads/all.')"
          git config --add remote.$r.fetch \
            "$(git config remote.$r.fetch | sed -e 's.heads.tags.g')"
          git config remote.$r.tagopt --no-tags
      done
      
    • 定期更新

      git remote update
      

    两种方法最终都将分支收集到 refs/heads/all/<remote-name>/<branch-name-on-remote> ,但第一个也有一组重复的refs refs/remotes/<remote-name>/<branch-name-on-remote> .第一个函数使用普通的fetch refspec并使用 git branch 复制_远程跟踪分支_( refs/remotes/… )变成正常的本地分支( refs/heads/all/… )第二个使用自定义refspec将提取的refs直接存储到目标引用层次结构中。

    由于更新是盲目地获取到这个组合存储库中的,所以任何人都不应该试图直接使用它:没有直接在其分支上进行的提交,没有来自外部的推送。如果有人在本地进行提交或推送到其中一个分支上,那么在下一次更新完成时,这些提交将被清除。

    如果Redmine可以处理一个空存储库,我建议使用一个。使用 git init --bare 以及以.git结尾的回购名称。阿尔索 git config core.logAllRefUpdates true 可能是个好主意(因为在一个裸露的存储库中,这个默认值为false)。

    除此之外 all/ 名称空间中的前缀,此方法与完整的 镜子 克隆是指外部引用 refs/heads refs/tags 不会被收集。大多数其他常见的引用被认为是存储库的本地引用(这就是为什么它们不被普通克隆复制的原因)。其他一些参考是_远程跟踪分支_( refs/remotes )一些平分记录( refs/bisect ) git filter-branch _( refs/original 等等。可能这些其他的事情对Redmine来说都不重要。如果是,它们也可以包含在其他参考规范中。

    创建额外的初始提交

    要使用新的初始提交来安排分支,请参见 GitTips page 在下面 How to create a new branch that has no ancestor . 其中两个配方涉及另一个存储库,在完成通常的init/add/commit步骤后,您可以从中推送或获取分支(这正是上述配方以自动方式所做的)。