如何将一个git仓库中的目录镜像到另一个git仓库?

16

我在 RepoA 中有一个目录 /amp,并且有一个 RepoB(最初填充了 /amp 的内容)。我想将对 RepoA 中的 /amp 的任何更改都反映到 RepoB 中。

这是可能的吗?

P.S:RepoA 包含许多其他目录。 我只想镜像 /amp 目录。而 RepoB 只会包含 /amp 内容而不是其他任何内容。


将/amp中的配置内容作为子模块,并将该子模块添加到RepoA和RepoB中。 - gnuanu
5个回答

12

你可以使用Git子模块来实现此目的,第一步是从你的/amp目录创建一个仓库,然后将其作为子模块在其他仓库中使用。

要将/amp变成一个仓库,你可以执行以下操作:

$ cd /path/to/amp
$ git init
$ git add .
$ git commit -m "First commit"

现在假设您将使用Github,您可以通过以下方式发布您的存储库:

$ git remote add origin git@github.com:<your-user>/amp.git
$ git push -u origin master

现在在repoArepoB中,您需要将新的amp存储库作为子模块添加,可以通过执行以下操作完成:

$ cd /path/to/repoA
$ git submodule add -b master git@github.com:<you-user>/amp ampMirror

对于仓库repoB同样适用

$ cd /path/to/repoB
$ git submodule add -b master git@github.com:<you-user>/amp ampMirror
$ git commit -m "added appMirror submodule"

注意,我在repoArepoB中给目录取的名字是ampMirror,但实际上你可以使用任何名称,事实上,只需使用以下命令即可使用相同的名称:

git submodule add -b master git@github.com:<you-user>/amp 

目录结构将会长成这个样子:

repo(A/B)
├── .git/
├── .gitmodules   <-- created after adding the submodule
├── foo
└── ampMirror
    ├── .git/     <-- repo to keep/track changes for app (need to git pull)
    └── foo

现在,每当您对amp存储库进行更改时,您需要更新“pull”您的存储库中的更改,例如:

$ cd /path/to/repoB
$ cd appMirror
$ git pull
$ cd ..    <--- get back to your project root
$ git commit -am "update submodule" 

如果有多个子模块,则另一种实现方式是:

$ cd /path/to/repo(A/B)
$ git submodule foreach git pull origin master
$ git commit -am "updated submodules"

希望这能帮助您更好地理解。


一个使用案例是拥有一个 Monorepo 并将其中一个文件夹发布为独立的 repo。例如,我创建了一个包库并想要发布一些启动器。目前我有一个用于启动器应用程序的 repo 和一个用于库的 repo,您的解决方案将适用。但它感觉“反向”,在某些架构中,您希望将 monorepo 作为真相的来源,而将隔离的 repos 作为镜像。 - Eric Burel

5

nbari的回答是正确的,子模块是为了解决这个问题而设计的。

子模块的一个潜在缺点是它们对用户不完全透明。如果你想让一些人能够使用 RepoA RepoB 而不需要知道任何关于子模块的东西,一个替代方案是 git subtree。你需要使用的主要命令是:

  • git subtree split可以将RepoA的子目录amp提取出来,创建一个独立的仓库RepoAMP(你也可以使用git subtree push将结果推送到新的仓库)。

  • git subtree merge可以将RepoAMP合并到RepoB的目录/amp中(你也可以使用git subtree pull一次性下载和合并)。

最终,RepoARepoB都是“普通”的代码仓库。镜像不会自动完成,但是git subtree可以帮助您正确地进行操作。


听起来更适合使用单一代码库设置,这样您就可以将树的一部分发布为只读存储库。 - Eric Burel
1
两种用例都能够实现:在单一代码库上进行开发并提取并发布某些子目录,或者将另一个代码库中开发的依赖项作为仓库的子目录包含进来。为了回答这个问题,我们实际上需要两种方法,将一个仓库中的一个目录提取出来并合并到另一个仓库中。 - Matthieu Moy
谢谢!顺便说一句,我想你曾经是我工程学院时的“Unix入门课”老师,我仍在从你那里学习。哈哈 - Eric Burel
哈哈,确实看起来像我 :-) - Matthieu Moy

2

将git仓库的目录镜像到另一个git仓库有一种简单的方法:

git clone --mirror git@example.com/mirror-repository.git

cd mirror-repository.git

使用以下命令将更改推送到新仓库

git push --mirror git@example.com/new-mirror.git

这将获取镜像仓库中可用的所有分支和标签,并将其复制到新位置。

请勿在没有使用--mirror克隆的仓库中使用git push --mirror。它会用您的本地引用(和本地分支)覆盖远程仓库。git clone --mirror优于git clone --bare,因为前者还克隆了git notes和其他一些属性。


0

如果RepoB只会有/amp内容,那么从中创建一个库更加准确。将此库作为依赖项放入RepoA的项目中。如何操作取决于您使用的语言(包管理器)。

对于开发环境,您可以在RepoA中创建符号链接,指向RepoB。


但是 git 怎么会识别符号链接呢?当我提交时,符号链接被提交了,而不是它所指向的文件(或目录)。 - mukilane
你应该只在RepoB(lib)里提交更改。它们因某些原因是不同的仓库。也许以后RepoC也会使用RepoB。如果你在项目中更改lib,可能会破坏其他使用它的项目。 - Raz
我确实在RepoB中提交了,但是我已经找到了我的解决方法。我只是将RepoB嵌套到A中。在amp文件夹中初始化RepoB。现在它按照我预期的工作了。 - mukilane

0
如果子模块不符合您的喜好,另一种方法是在 repoA 的 .gitattributes 中使用内容过滤驱动程序,用于所有位于/amp/中的文件。
请参阅Pro Book

https://git-scm.com/book/en/v2/images/clean.png

更具体地说,"clean" 过滤器将在 git commit 时自动调用(仅针对 /amp/** 文件),然后可以执行必要的命令以便在 repoB 中复制更改。
该清理合并驱动程序脚本将是:
#!/bin/sh
git --work-tree=/path/to/repoA/amp --git-dir=/path/to/repoB/.git add .
git --git-dir=/path/to/repoB/.git commit -m "import from repoA/amp"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接