Git 发送 tarball 并要求为子项目发回补丁的替代方法?

Git alternative to sending out tarballs and asking patches be sent back for a sub-project?

我有一个很大的项目,其中有一个子目录,它本身就是一个项目。

为了简单起见,我想在共享相同分支、标签等的较大项目中管理此子目录。大型项目的完整性以及将其作为整体 git 存储库进行跟踪的能力对我来说非常重要。

但我也想在较小的项目(子目录)中发布和接受来自贡献者的拉取请求,而不将他们暴露给我的较大项目。子项目需要其父项目中的一些辅助文件(如 Eclipse .project)才能完全独立。

我研究了子模块、子树合并和稀疏检查,但不知道如何执行此操作。作为权宜之计,我只是发送了一个子目录的压缩包,并在 return 中请求补丁。

关于如何通过以 git 为中心的工作流程改进这一点有什么想法吗?

好的,这不是一个完美的设置,但应该足够好了。

想法是建立一个分支,其中除该子目录和公共文件之外的所有内容都被删除(我的意思是:根本不存在),并接受该分支的拉取请求(您可以创建一个新的存储库仅包含该分支)。

它有点扭曲,所以我将通过一个例子来展示它。比方说,您的项目是用这样的逗号创建的:

mkdir bigproj
cd bigproj
git init
echo "common file" >common
mkdir subproj
echo "subproj content" >subproj/content
mkdir other
echo "other content" >other/content
git add common subproj other
git commit -m 'Initial commit'
git commit --allow-empty -m 'Some history'

里面有一个common文件,一个subproj子目录有一些内容,other子目录有一些内容。树:

.
├── common
├── other
│   └── content
└── subproj
    └── content

现在让我们创建一个只包含 commonsubproj 没有历史记录的分支:

git checkout --orphan subproj-branch
git rm -rf .  # clear the index
git checkout master -- common subproj  # put `common` and `subproj` back to index
git commit -m 'Initial commit for subproj-branch'

结果树:

.
├── common
└── subproj
    └── content

将此分支合并回 master 以避免可能的虚假冲突:

git checkout master
git merge subproj-branch  # obviously no conflicts

现在我们可以在一些专用存储库中发布 subproj-branch

git remote add subproj-repo <some url>
git push subproj-repo subproj-branch:master --set-upstream  # -f may be needed.
# And remote branch doesn't have to be named master, of course.

存储库已发布,我们得到了一些补丁。现在我们可以合并它们了:

git checkout subproj-branch
git pull
git checkout master
git merge subproj-branch

这是基本流程,它允许在子项目仓库中进行更改并将它们合并到主仓库中。现在,把它反过来有点问题,但有可能。有以下可能性:

  1. 仅更改触摸 subproj/common。我们可以带他们 "as they are":

    git checkout subproj-branch
    git cherry-pick master  # replace master with anything you actually need
    git checkout master
    git merge subproj-branch
    git push subproj-repo subproj-branch:master
    
  2. 更改涉及 subproj/common 和其他文件。您可以手动将每个更改的文件检出到 subproj-branch,然后提交并合并回 master(以避免将来发生虚假冲突)。这并不完美,您可能想以某种方式更改该步骤。

    git checkout subproj-branch
    git checkout master -- common subproj
    git commit -m 'Some changes'
    git checkout master
    git merge subproj-branch
    git push subproj-repo subproj-branch:master
    

这里的重要部分是将更改合并回 master。 这可能看起来很荒谬,但可能会阻止一些冲突的发生。

哇哦,好长的答案。我希望它会有所帮助 :P

这不是一个完整的答案,但是根据@Frax 的回答我 运行 有一些我不理解的东西,或者没有像我预期的那样工作,我需要修改它如下:

  • 首先,我使用 filter-b运行ch 创建了一个新的 b运行ch,它只包含具有历史记录的公共子目录的内容。 (* 我避免将其作为单独的回购协议,因为我在 GitHub * 处对私人回购协议的数​​量有限制)。这将简化所有剩余的操作,因为大多数 git 命令在 b运行ch 范围内自然工作,但在尝试在子树范围内执行操作时我总是感到困惑。
  • 即使这个过滤后的历史也非常臃肿,所以我继续使用 Frax 建议的 --orphan 选项创建一个没有历史的 b运行ch。很好的建议。
  • 做一个git merge回到完整的b运行ch(而不是孤立的b运行ch)很重要,这个合并方向在Frax的回答中似乎是倒退的,或者我只是不明白我在做什么。结果是可以在历史 b运行ch.
  • 中看到来自新 b运行ch 的提交哈希
  • 最后,使用 submodule add –b branch 将这个新的 b运行ch 合并到原始项目和子项目中。
  • 尝试使用它几分钟后,我已经 运行 陷入了 Eclipse 子模块处理的局限性。看起来下一个替代方案是拆分回购协议。

更多注意事项

  • 这个问题看起来非常相似:How can I keep a subfolder of a git repo in sync with a subfolder of another git repo - 我刚刚为这个问题提供了 100 点赏金
  • 使用稀疏签出从一个存储库中获取一个子目录并提交到另一个存储库 "almost works",除了我的整个 500MB 存储库在幕后被复制,即使我的稀疏签出仅涵盖少数文本文件。
  • 使用 --depth=1 是有希望的,除了尝试提交我得到的第二个回购 ! [remote rejected] master -> master (shallow update not allowed)
  • 另一个类似的问题(未回答):Child git repository as subset of a main repository
  • 如果我在第二个遥控器上推送到一个全新的 b运行ch,下面@Frax 的回答就可以正常工作。但我希望它与远程主机集成,以便 运行 独立模式下的子项目所需的额外支持文件可以在同一个 b运行ch.

我在 How do I merge a sub directory in git?

找到了隐藏的答案

git 魔法的关键位是使用以下同步两个公共子目录:

git read-tree --prefix=MyHugeProprietaryWebApp/public_html/ -u contrib/master:MyOpenSubproject/public_html/

在哪里

  • MyHugeProprietaryWebApp 是项目在存储库根目录下的顶级目录(即这是 Eclipse 中的项目根文件夹)
  • public_html 是包含我想与贡献者合作的代码的子目录(在我的特定情况下,这是一些 PHP 布局代码)。它在命令中出现两次,因为子目录在两个存储库中的名称相同。
  • contrib 是 github 上的存储库(与贡献者共享),我之前按照 Frax 的建议使用 git checkout --orphangit push 创建了该存储库;我没有测试可能的替代方案,例如 --depth=1.
  • MyOpenSubproject 是较小项目的根文件夹,包含 Eclipse .project 和其他使子项目独立的辅助文件。这些辅助文件不与较大的项目共享,包括额外的文档、测试等,这些文件仅与外部贡献者相关,与从事较大项目的内部人员无关。

我对这种方法的体验仅限于一些干燥的 运行 测试,但我对目前所见感到满意。我还没有尝试过 pull -s subtree -X path,我可能在某些时候需要它。