如何编辑外部子模块并将其推送到我自己的存储库?

EBD*_*IJK 4 git git-push git-submodules git-fork

我正在写我的论文,我在那里扩展了另一篇论文。本文已在存储库 X 中公开了他们的所有代码,同时还使用了自己的子模块:我们将其称为 Y。

对于我自己的项目,我创建了一个自己的存储库 Z,其中包含 X 作为子模块,因此 Y 作为嵌套子模块。但是,我想对 X 和 Y 中的代码进行更改,并且还能够将其推送到我自己的存储库,以便我可以在多个位置使用它。我没有 X 和 Y 的推送权限,因为它是别人的仓库。解决这个问题的最佳方法是什么?预先感谢,我迷路了:D

我尝试将我自己的存储库推送到其主目录中,但它不包含我在子模块中更改的代码。当我进入子模块并在那里提交更改的代码时,我首先发出了分离头的警告。当我通过签出新分支来修复此问题时,它现在给我:

git push --set-upstream origin new_branch
ERROR: Permission to \[repo X\] denied to \[myusername\].
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Run Code Online (Sandbox Code Playgroud)

我现在分叉了存储库 X 并更改了 .gitmodules 中的 url。子模块 Y 现在发生了什么?

tor*_*rek 9

让我们从子模块的背景开始

\n

子模块很简单,但结果很复杂。一个“子模块”由两部分组成:一个.gitmodules文件和两个 Git 存储库。一个存储库称为超级项目,一个称为子模块超级项目在一个或多个提交中包含要在子模块中签出的提交的原始哈希 ID 。无论如何,这就是整个图片\xe2\x80\x94,直到我们开始实际工作为止。

\n

假设您首先克隆超级项目

\n

假设你运行:

\n
git clone --no-recurse-submodules <url> super\ncd super\n
Run Code Online (Sandbox Code Playgroud)\n

现在,您在超级项目存储库中签出了一个提交,并附有一条指令,指示此超级项目中运行的 Git 应签出子模块中的提交。但没有任何子模块。您只克隆了一个存储库,而不是两个。

\n

--no-recurse-submodules选项确保 Git 不会继续克隆子模块。无论如何,这都是默认设置,但我们故意在这里明确说明,以使其显而易见,以防万一您更改了个人设置以打开递归。

\n

如果您希望克隆子模块并签出提交,您现在必须指示 Git完成签出。(如果您根本不想理会子模块,则可以将其保留在这种状态:即使超级项目需要子模块,您也不会拥有子模块。实际的克隆和签出步骤是可选的,前提是无论你在做什么都不需要子模块。例如,Git 的 Git 存储库包含对检查 SHA-1 冲突的程序的子模块引用,但它是特别可选的,你不需要费心它.)

\n

要完成结帐,您现在运行:

\n
git submodule update --init\n
Run Code Online (Sandbox Code Playgroud)\n

--recurse-submodules(如果您在克隆中使用,该命令会在步骤 步骤 6 1git clone之后为您运行此命令)。git checkout

\n

这里有一个问题:它git submodule update --init必须运行git clone。该git clone命令需要一个URL。网址从哪里来?这个问题的解决办法就是.gitmodules文件,该文件必须存在于第6步签出的提交;该文件必须列出此时必须克隆的任何子模块的 URL。

\n

克隆这些子模块后,git submodule update您现在可以在不使用标志 \xe2\x80\x94 的情况下使用命令--init\xe2\x80\x94,它会通过哈希 ID 选择一个提交,该提交应该git checkout 超级项目列出的每个子模块中。超级项目 Git 命令在git submodule update子模块存储库中签出的哈希 ID是存储在签出的提交中的哈希 ID(再次在步骤 6 中)\xe2\x80\x94,或更准确地说,是现在在 Git索引中的哈希 ID (但它通过步骤 6) 中的结帐进入 Git 的索引。

\n

现在通过 克隆的任何子模块本身都git submodule update --init可以通过列出提交哈希 ID 并在其中包含一个文件来成为超级项目。如果您使用选项 to ,它将进入每个子模块并使其轮流作为子模块命令的超级项目。这就是获取子模块的子模块的子模块的所有子模块的过程(无论嵌套有多深)。.gitmodules--recursivegit submodule updategit clone --recurse-submodules

\n
\n

1git clone命令基本上是运行六七个命令的简写,除了其中一个之外,所有命令都是 Git 命令:

\n
    \n
  1. mkdir,或者您的系统用于创建新文件夹/目录的任何命令。其余命令在新文件夹中运行。
  2. \n
  3. git init:这会创建一个新的、完全空的存储库。
  4. \n
  5. git remote add:这会添加您可以选择其名称的遥控器,但每个人都使用默认名称origin,以及您提供的 URL git clone
  6. \n
  7. 您指定的任何git config命令(默认无)。
  8. \n
  9. git fetch origin:这会复制Git 软件中响应您提供的 URL 的所有提交。它不复制任何分支:它们的分支将成为您的远程跟踪名称。
  10. \n
  11. git checkout:这会在您的新存储库中创建一个分支,并签出提交。此步骤是可选的,因为它被 抑制--no-checkout
  12. \n
  13. git submodule update --init,如果您要求这样做,并且在步骤 6 中签出的提交中是否列出了子模块。此步骤是可选的,不是默认步骤。
  14. \n
\n
\n

假设你这样开始

\n

想象一下,不仅仅是克隆超级项目:

\n
git clone --no-recurse-submodules <url> super\ncd super\n
Run Code Online (Sandbox Code Playgroud)\n

您首先亲自克隆超级项目本身,然后您也继续亲自克隆子模块:

\n
git clone --no-recurse-submodules <url1> super\ncd super\nmkdir -p super/sub\ngit clone --no-recurse-submodules <url2> super/sub\n
Run Code Online (Sandbox Code Playgroud)\n

现在您可以运行git checkoutor git switchin super(您现在所在的位置),然后git submodule update运行 ​​in super,并且 Git不必克隆新的存储库。Git 仅使用您在超级项目中创建的现有子模块克隆。2

\n

使用此方法时,.gitmodules文件的内容将被忽略。 因此,通过使用此方法,您无需修复.gitmodules任何超级项目中的任何文件即可使用不同的子模块 URL。

\n
\n

2您可能还希望git submodule absorbgitdirs在这两个git clone命令之后运行,以便从子模块存储的旧 Git 1.x 模型切换到新的 Git 2.x 模型。这不是必需的,这只是一个好主意,因为有些混乱“子模块可能来来去去,然后又回来”。当子模块确实消失时\xe2\x80\x94,例如,通过提取历史提交\xe2\x80\x94,结果目前相当难看:子模块有很多用户体验缺陷,导致许多人仍然称它们“呜咽” -模块,尽管自 Git 早期以来它们已经有了重大改进。

\n
\n

后果

\n

这是什么意思呢?好吧,假设有一些现有的超级项目您不需要触及,但是您有一个子模块或子模块子模块,您确实需要触及,因此,您希望人们克隆您的子模块,或您的子子模块,当它们克隆超级项目时。

\n

真正 需要做的就是让您自己的 Git 存储库可供访问。那些“知情者”可以仔细克隆您的子模块并将其放置在现有超级项目提供的上层结构中。但是,如果您希望其他人(仅)方便地克隆超级项目,并让该超级项目git submodule update --init克隆您的子模块,则必须更新.gitmodules充当子模块超级项目的任何 Git 存储库中的文件。

\n

假设您最初有这样的结构:

\n
super                <-- their superproject\nsuper/sub1           <-- their submodule\nsuper/sub1/sub2      <-- their sub-submodule\n
Run Code Online (Sandbox Code Playgroud)\n

有两个.gitmodules文件,其中一个super/sub1/.gitmodules列出了可以从中克隆的 URL sub2,另一个文件中super/.gitmodules列出了可以从中克隆的 URL sub1

\n

因为您已经创建了一个用于替换的 新存储库sub2,所以您现在必须创建一个用于替换的 sub1新存储库,其中的文件.gitmodules列出了替换的新 URL 。但是为了让超级项目列出替换的新 URL ,您现在必须创建一个替换的新存储库,其中的文件列出了替换的新 URL 。 sub1sub2supersub1 super.gitmodules supersub1

\n

换句话说,接触.gitmodules文件的需求从最低的子模块“冒泡”,通过每个中间子模块,并最终到达最顶层的超级项目。如果你想让别人方便地克隆你的底层子模块,这是不可避免的。

\n

但这是一个如果。子模块已经很糟糕了;这里还有什么可怕的程度呢?您可以.gitmodules提供一条指令,在执行递归克隆后update --init,那些想要使用您的子子模块的人应该删除一个克隆并将其替换为您的克隆,而不是复制其他存储库只是为了更新每个存储库中的一个文件。

\n

这是你的选择:让你不方便,让别人方便,或者让别人不方便,让你更方便。

\n