有什么方法可以不忽略子文件夹中的.git吗?

时间:2019-07-18 03:55:01

标签: git monorepo

我有一个类似这样的项目:

+ MonoRepo
  - .git
  + PublicUtil
    - .git
    - PublicFile.js
  + PrivateStuff
    - internalUseOfPublicUtil.js

使用此结构,我们可以将更新推送到PublicUtil,这些更新是版本控制的,并且对公众可见。然后,同时在开发方面,我们只对所有提交使用MonoRepo,然后有一个脚本,如有必要,该脚本将推送到subgits。

我们需要这个,因为(实际上)该项目更大。想象30个PublicUtil仓库。我们不能使用子模块,因为这将导致内部开发人员不得不将多个存储库推送到一个更新中(通常,多个存储库需要同时修改),然后再更新MonoRepo。这意味着浪费大量时间将不同PR之间的点连接起来,并且当一个子模块在没有其他子模块的情况下被拉出或某些东西尚未被推入时,偶尔会损坏。

无论如何,既然我已经解释了为什么我试图实现这一奇怪的目标,这就是问题/问题:

据我所知,git不允许用户从子文件夹中推送.git。但是,我可能错了。所以,我不妨问一下:

有什么办法可以忽略子文件夹中的.git?

我可以很好地设置项目,但是如果我按MonoRepo然后将其拉到另一台计算机上,它将没有任何子文件夹git,因此我将无法执行任何操作看中了公开发布私人git内容的部分。

P.S。当前,我对如何解决此问题的最佳猜测是制作一个用于重命名git文件夹的提交前和提交后钩子,仅由MonoRepo使用。我也需要一个克隆后的数据库...它可以工作,但是我宁愿不要那么费力。

2 个答案:

答案 0 :(得分:0)

除了删除.git子文件夹之外,为了提交真正的monorepo,您​​还可以随时在其自己的Git存储库中记录一个子文件夹(例如PublicUtil)。

您需要拥有的.git存储在其他位置,外部主要monorepo结构中,并执行

 git --git-dir=/path/to/monorepo§publicUtils \
     --work-tree=/path/to/PublicUtils/.git add .

 git --git-dir=/path/to/monorepo§publicUtils \
     --work-tree=/path/to/PublicUtils/.git commit -m "record PublicUtils"

这使您可以维护两组历史记录:

  • 您的monorepo中有一个全球性的
  • 一个特定于子文件夹的项目。

所有这些都可以通过挂钩自动执行,该挂钩将检测新提交涉及哪些子文件夹(项目),并进行额外的git --git-dir=... --work-tree=...调用。

答案 1 :(得分:0)

我已经设计出一种解决方案,该解决方案适用于具有node.js的项目。如果我擅长bash,那我会把它设为bash脚本。如果您可以通过bash做到这一点,我将认为它是该问题的真实答案。无论如何,这是我的设置脚本:

const fs = require("fs");
const path = require("path");
const { exec } = require('child_process');

function createRenamer(forCommit) {
  const from = forCommit ? ".xgit" : ".git";
  const to = forCommit ? ".git" : ".xgit";
  return [
    `for x in $(find */ -name ${from}); do`,
    `  mv ${forCommit ? "-n" : ""} $x $(echo "$x" | sed 's/${from.replace(".", "\\.")}$/${to}/')`,
    `done`,
    forCommit ? `&& git add */.xgit` : ""
  ].join("\n");
}

const hooksPath = path.join(__dirname, "./.git/hooks");

const preCommitFilename = hooksPath + "/pre-commit";
fs.writeFileSync(preCommitFilename, createRenamer(true));
fs.chmodSync(preCommitFilename, 0o755); 

const postCommitFilename = hooksPath + "/post-commit";
fs.writeFileSync(postCommitFilename, createRenamer(false));
fs.chmodSync(postCommitFilename, 0o755); 

exec(postCommitFilename);

它必须在任何时候运行一次,并且它将初始化所有子存储库。它的作用是:

  • 创建一个预克隆的bash脚本,该脚本
    • 将每个**/.git更新为**/.xgit
    • 然后git添加所有.xgit文件。这实际上只需要执行一次,但是它使新的子存储库更加自动
  • 然后,它创建一个克隆后的bash脚本,该脚本将每个**/.xgit更新为**/.git,以便再次使用
  • 然后运行后克隆以初始化子存储库

CAVEAT :这仍然是不完整的解决方案。如果有人拉回购协议,则在运行重命名脚本之前不会更新.gits。此外,mv的工作方式是愚蠢的,似乎无法重命名目录,而无意间将其复制到您要命名的文件夹中。这让我大吃一惊,当然我一定是错的...(How can I rename a directory in bash, without overwriting or moving inside a pre-existing target?

弄清楚这些纠结之后,我会进行更新。