从现有仓库创建孤立分支?

6
我有一个git存储库,我对其进行了一些测试,并希望将其包含在主存储库中。我想将其添加为孤立分支,因为我想保留它,但不想用我的测试项目使主分支变得臃肿。如何将git存储库导入为孤立分支?我想保留我的提交记录。编辑以显示它不是重复的:实际上我并不关心它是否被孤立或其他任何事情,我只是想有一种方法来合并两个存储库。给出的答案是正确的,解决了我的问题。

我不太确定你的意思:你是想将你的测试推送到远程代码库吗?还是想从远程机器获取主要代码到你本地的代码库? - Asenar
它们是不同的代码库,两者都是本地的。 - vrwim
仍然不理解...使用git checkout -b --orphan test/somefeature && git add . && git commit 'my tests things'创建一个分支有什么问题吗? - Asenar
1
请参见 https://dev59.com/RXM_5IYBdhLWcg3waiiJ。 - Edward R. Mazurek
我想将我在测试仓库中的所有提交复制到一个新的孤立分支上。 - vrwim
1个回答

7
我认为你的观点是错误的。事实上,这个问题的存在意味着某些并不真实的东西。我认为你想要更准确地称之为“不相交的子图”。
为了达到这个目的,请跟我完成下面的练习。如果你只想要答案,请直接向下滚动。:-)
练习:哪个分支是孤立的?
假设你有一个存储库,在这个存储库中有两个名为X和Y的分支(没有主分支,只有X和Y)。分支X指向提交a123456,分支Y指向提交b987654。这些提交像往常一样指向它们的父提交,但如果我们绘制整个提交图(存储库很小,因此适合在此SO答案中),我们会得到:
o--o--o--o    <-- X

o--o--o---o   <-- Y
    \    /
     o--o

有两个不同的根提交。分支X指向a123456,它是根为a000000的四次提交链的尖端。分支Y指向b987654,它是根为b000000的六次提交结构的尖端合并提交。
哪些分支(如果有的话)是孤儿分支?
(这是一个思考这个问题的好地方。)
如果你选择了X,那么你为什么选择它?如果你选择了Y,那么你为什么选择它?如果你选择了两个,我认为你可以证明这个选择;但是如果你回答“都不是”,那么我认为这是正确的,并注意到你现在已经同意Git的看法。
(如果你选择了X和Y,你称这些为“孤立分支”的理由是什么?我认为你可以将其作为一个正确答案进行辩护,并通过说它们都没有连接到主分支来证明它的正确性。如果我们接着添加一个名为master的分支,并使其指向X上的任何四次提交之一,那么你将会认为分支Y是孤立的而X不是。如果你让master指向Y的六个提交之一,那么你将会说X是孤儿,而Y不再是孤儿。可能有更多的决定方式,取决于你如何定义“孤儿”的复杂程度。但是这不是Git的意思,实际上有更好的术语,它不会与Git产生分歧,并且在长期内为你提供更好的服务)。
不相交的子图:
在我们的练习示例存储库中,X和Y都不是孤立分支,因为它们都有提交记录。在图论中——Git存储库是基于图论构建的——两个分支名称X和Y指向整体图的不相交子图。
旁注:Git对“孤儿分支”的理解
在Git中,使用git checkout --orphan newbranch创建的“孤儿分支”处于一种特殊状态,“尚未诞生”。该状态持续到分支上有提交,在此之后,该分支就不再是“孤儿分支”了。现在它只是一个普通的分支,像其他任何分支一样。
Git实际上是以一种非常糟糕的方式实现孤立分支状态,导致抽象泄漏。具体来说,它将新的分支名称写入“HEAD”,但没有在其他地方写入。由于“HEAD”包含当前分支的名称,如果您检出任何其他分支,则这将覆盖“HEAD”文件,并且孤立分支本身将完全消失。换句话说,只有一个单一的分支可以处于“孤立”状态,并且通过在“HEAD”中存储其名称且仅在“HEAD”中存储其名称来到达该状态。由于“HEAD”存储当前分支的名称,因此只有当前分支可以成为孤立分支。
最后,我认为你真正想问的问题的答案如下:假设有两个不相关的存储库R1和R2,你想创建一个联合存储库(可能是一个新的存储库R3,也可能只是修改其中一个原始存储库),其提交图是由R1和R2中的提交图的并集得到的"不相交"图。
让我们将其作为第三个新存储库。 (甚至可以通过省略其中一些步骤将R1粘在R2中或反之亦然,因此让我们从完整的练习开始,如果需要,您可以将其缩小。)
要构建新存储库R3,首先创建一个空存储库:
$ mkdir r3 && cd r3 && git init

现在从 R1 中获取所有内容并存储到 R3 中。如果您将 R2 添加到 R1 中,那么添加 R1 作为命名远程库是最好的选择(尽管这时我们是在 R1 中添加 R2,而不是在 R3 中添加 R1)。您可以运行 git fetch 并给它一个 URL,使用它放入 FETCH_HEAD 的分支信息,但让我们添加两个远程库。这里的 <url> 可以是路径(../../otherrepo.git/path/to/otherrepo.git),也可以是 ssh://...git://...https://... 等常见格式。

然后,从 R2 中获取所有内容并存储到 R3 中。我们使用完全相同的步骤,只需使用不同的远程库名称和 URL:

$ git remote add r1 <url for r1>
$ git remote add r2 <url for r2>
$ git fetch r1; git fetch r2

此时您基本上已经完成了:您在新存储库中拥有联合作为提交图。唯一剩下的事情是创建本地分支名称,使其指向某些或所有远程跟踪分支所指向的提交。
由于我们将存储库R1命名为r1,因此它的所有分支都在refs/remotes/r1/branch-name中。同样,由于我们将R2命名为r2,因此它的所有分支都在refs/remotes/r2/branch-name中。您可以通过它们的缩写版本r1/whatever和r2/whatever来引用这些内容。假设r1具有master和A分支,而r2具有master和B分支。
由于只有一个A,因此您可以执行以下操作:
$ git checkout A

现在你有一个名为A的分支,它指向与r1/A相同的提交。此外,您的本地A已设置为跟踪r1/A:也就是说,它的上游是r1/A

B同样适用。

您可以在r3中创建新的master,但它只能指向另外两个存储库中的一个存储库的相同提交,并且您不能使用此快捷方式。假设您希望r3masterr2/master匹配:

$ git checkout -b master r2/master

将创建它并设置跟踪r2/master

如果您不想要这个上游的--track设置,可以使用--no-track创建分支。

这就是全部内容:创建这两个不相关的子图确实很容易。您只需要知道这就是您要做的事情,如果您想要有机地增长一个新的不相关的子图,而不是从现有存储库中获取它,则需要使用--orphan


1
是的,这正是我在寻找的!我能添加一个远程仓库,但它实际上只存在于我的本地计算机上吗?还是我需要将其推送到GitHub并重新获取才能实现这一点? - vrwim
任何远程的<url>部分都可以是一个普通的文件路径(或者是一个file:// URL,但为什么要麻烦呢? :-))。 - torek

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