我的仓库中有一个分支:开发。代码已经提交并推送到那里。
\n\n存储库中没有主分支。
\n\n我想创建一个主分支,以便我可以向其中提出拉取请求。
\n\n我已经尝试过两种方法:\n1. 从开发创建主分支:
\n\ngit checkout develop\ngit checkout -b master develop\nRun Code Online (Sandbox Code Playgroud)\n\n这里的问题是没有什么可以比较的:master 和development 已经是一样的了。
\n\ngit checkout --orphan master\ngit reset --hard\nRun Code Online (Sandbox Code Playgroud)\n\n这里的问题是分支有不同的历史记录,我得到:\n“没有\xe2\x80\x99t任何东西可以比较。(分支)是完全不同的提交历史记录”
\n\ngit 版本 2.17.2 (Apple Git-113)
\n\n如何创建一个空的 master 以便我可以从现有的开发中提出 Pull 请求?
\n只需创建一个分支名称即可。真的,这就是全部。选择一些现有的提交并使分支名称master标识该提交。那现在是你的master分支机构。
不过,已经存在一个问题了,因为Git 中“分支”这个词是不明确的。(请参阅“分支”到底是什么意思?)当我们说“分支”时,有时我们指的是名称,例如master或develop,有时我们指的是其他东西。
Git 真正存储的是一系列提交。每个提交都有一个分配给它的唯一编号:哈希 ID,8dca754b1e874719a732bc9ab7b0e14b21b1bc10例如看起来像这样。您可以在git log输出中看到这些。
每次提交都保存项目的完整快照,作为一组文件(不是文件夹,只是文件:文件夹(如果有)将在运行时根据需要创建以保存git checkout文件)。并且,每个提交都有一些元数据:有关提交的信息,例如谁、何时、为何(其日志消息),以及\xe2\x80\x94至关重要的\xe2\x80\x94前一个的原始哈希ID犯罪。
正是这些原始哈希 ID 构成了向后查找的提交链。如果我们使用单个大写字母来伪造哈希 ID\xe2\x80\x94,这对人类来说更有用,但显然不适用于数千个提交\xe2\x80\x94,我们可以绘制一个简单的三提交存储库像这样:
\n\nA <-B <-C\nRun Code Online (Sandbox Code Playgroud)\n\n这里的commitC是最新的commit。它记录了 commitB是较早的提交,所以我们说C 指向 B. 另一种说法是 that Bis C\'s Parent。同时 commitB说 commitA出现在 之前B。提交A是任何人所做的第一个提交,因此没有父级。这可以让操作停止:历史记录开始\xe2\x80\x94或结束,如果你像Git那样向后工作\xe2\x80\x94here。
有时,当我们说分支时,我们指的是整个提交系列。这个提交链A-B-C,从末尾开始并向后工作,是一个分支。您指示 Git 查找最后一次提交 ,C然后该提交指向较早的提交B,该提交又再次指向。无论有多少次提交,只要我们知道哪个提交是最后一次提交,我们总是可以让 Git 从最后开始,一直回到开头。但是我们如何找到最后一次提交呢?
在这个例子中,很简单:只有三个提交,我们让它们使用连续的字母名称,所以显然C是最后一个。但在真实的存储库中,可能有数千次提交:
$ git rev-list --all --count\n58314\nRun Code Online (Sandbox Code Playgroud)\n\n它们的哈希 ID 看起来完全是随机的。我们如何知道哪个提交是最后一个一个提交?此外,如果我们有一系列提交,例如:
\n\n I--J\n /\n...--F--G--H\n \\\n K--L\nRun Code Online (Sandbox Code Playgroud)\n\n哪里有两个“最后”提交?
\n\n分支名称,如master或,仅保存最后develop一个分支的实际哈希 ID,仅保存我们想要称为“分支的一部分”
I--J <-- master\n /\n...--F--G--H\n \\\n K--L <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n通过使名称master指向 commit J,我们声明这J是该分支的最后一次master提交。通过使名称develop指向 commit L,我们声明这L是分支的最后一次提交develop提交。
请注意,提交H、和G、以及F以及之前出现的任何其他内容都在两个分支上。这是 Git 的一个独特功能:通常,大多数提交都是在每个分支上。它只是最后几个\xe2\x80\x94或几百个,或任何\xe2\x80\x94,仅在一个或两个或十个分支上。
对于存在的分支名称,它必须指向某个现有的提交。您可以在不使用分支名称 \xe2\x80\x94 的情况下进行提交,这有点棘手:它使用 Git 所谓的分离 HEAD模式 \xe2\x80\x94 但您不能拥有分支名称,除非它指向某个实际提交。通过指向该提交,该分支名称声明该提交是该分支中的最后一次提交。
\n\n即使名称指向其他人链中间的提交也是如此。假设你没有大师,但有:
\n\n...--F--G--H--K--L <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n现在,您可以告诉 Git:创建名称masterH,通过查找 H 的实际哈希并运行来指向提交:
git branch master <hash-of-H>\nRun Code Online (Sandbox Code Playgroud)\n\n或者:
\n\ngit checkout -b master <hash-of-H>\nRun Code Online (Sandbox Code Playgroud)\n\n现在你有:
\n\n...--F--G--H <-- master\n \\\n K--L <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,提交根本没有改变。您刚刚添加了标签master\xe2\x80\x94a 分支名称\xe2\x80\x94 以记住 commit 的哈希 ID H。
master现在您有了标识 commit 的名称H,您可以:
git checkout master\nRun Code Online (Sandbox Code Playgroud)\n\n然后做一些工作并进行新的提交。当您进行新的提交时,Git 会打包项目的新快照并将其写出。Git 将您的姓名添加为此新提交的作者和提交者,设置其日期和时间戳,并使用您的日志消息作为此提交现在存在的原因。Git 将现有提交的原始哈希 ID 添加H为新提交的父提交。然后,Git 将新提交保存到“所有现有提交”的数据库中,该数据库为新提交分配新的唯一哈希 ID。我们将这个新的哈希 ID 称为I:
I <-- ???\n /\n...--F--G--H <-- ???\n \\\n K--L <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n现在有一个棘手的部分:创建 commit 后I,Git会移动当前分支名称,使其指向新的提交。由于当前分支名称为master,Git 会进行更改master,使其指向新的提交I:
I <-- master (HEAD)\n /\n...--F--G--H\n \\\n K--L <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n你现在应该问自己两个问题:
\n\nmaster而不是develop应该移动?H?这里问题 1 的答案如图:我已将特殊名称附加HEAD到 name 上master。当您使用git checkout选择分支时,Git 会将此名称 附加HEAD到该分支。这不仅告诉 Git 你现在签出了哪个提交,还告诉 Git 哪个名称当您进行新提交时需要更新
Q2 的答案并不那么明显,直到您发现 Git 的一般原则,即:一旦进行提交,该提交将永远冻结。 任何现有提交中的任何内容都不能由您或 Git 更改\xe2\x80\x94。原因是提交的实际哈希 ID 是提交内数据的校验和。更改任何数据,即使是单个位,并且更改校验和\xe2\x80\x94,你会得到一个新的、不同的提交,而不是原始提交。原始提交保持不变。
\n\n提交内的文件全部被冻结、只读并永久保存。它们也被压缩,并采用特殊的 Git-only 格式。这有助于防止 Git 存储库立即变得巨大:如果每次提交都保存每个文件\xe2\x80\x94(确实如此)\xe2\x80\x94,存储库的大小如何不会完全失控?Git 使用的技巧之一是,如果您保存文件的相同版本,它只会重新使用现有的冻结副本。它可以做到这一点,因为冻结的副本无法更改。
\n\n(我喜欢将这些冻结的、仅限 Git 的文件副本称为“冻干”。在 Git 存储库中,冻干的文件实际上没有名称:它们具有哈希 ID 号。请注意,它们必须解冻并“重新水化”为普通文件以供您使用\xe2\x80\x94冻结的副本对于完成任何新工作是无用的。这就是为什么git checkout要创建一个工作树,您可以在其中完成您的工作。提交中的冻干文件成为工作树中的普通文件,Git 首先使用与提交一起存储的冻干名称创建保存它们所需的任何文件夹。)
通常,我们用来git clone创建存储库,然后将我们的工作发送回我们稍后开始使用的存储库git push。该git clone过程从原始存储库复制提交。但它并没有完全复制分支名称。相反,它采用它们的分支名称\xe2\x80\x94及其存储库的master等等develop\xe2\x80\x94并重命名它们,调用它们origin/master等等origin/develop。
刚刚克隆了他们的 Git,我们的Git根本没有分支名称!它有他们所有的分支名称,重命名为我们的origin/* 远程跟踪名称。1 但是我们的 Git 通常希望我们有一个分支\xe2\x80\x94 master,但如果他们甚至没有master,我们的 Git 现在会选择一些其他名称,例如develop. 作为最后一步git clone,我们的 Git 必须:
origin/namegit checkout按该分支名称提交。第一步选择的名称是:
\n\n-b如果您说 ,则为您在论证中提供的名称,或者git clone -b namemaster。最后一个master是特殊情况,用作最后的手段。2
因此,如果您克隆一个只有 的存储库develop,您将获得自己的origin/develop名称\xe2\x80\x94a 远程跟踪名称,而不是真正的分支\xe2\x80\x94,指向其develop. 但是,作为 的最后一步git clone,您的 Git 将创建您自己的develop,指向同一个提交,然后git checkout develop您就可以使用您的一个分支名称 ,develop并签出此提交。
master如果您现在在存储库中创建新名称,您将得到以下结果:
...--o--o <-- develop, master, origin/develop\nRun Code Online (Sandbox Code Playgroud)\n\n(HEAD附加到develop或master,具体取决于您创建名称的方式master:您使用了git branch, 或 吗git checkout -b?)。
您现在可以运行git push origin master告诉他们的Git:创建一个分支名称master,指向与您的develop. 所做git push的就是向他们的 Git 发送您拥有的任何提交,他们不会发送您所做的任何提交,他们将需要创建或更新某些分支名称部分 \xe2\x80\x94,然后礼貌地要求他们创建或更新一些分支名称以匹配您的一些分支名称:
git push origin branch1 branch2 branch3\nRun Code Online (Sandbox Code Playgroud)\n\n让您的 Git 在origin您的名字 \xe2\x80\x94 下存储的 URL 处调用origin位于 \xe2\x80\x94 的 Git,并向他们发送所需的任何提交,然后要求他们设置名为、 、 的分支,并指向相同的提交你的名字、、 和指向。由于他们只有在拥有这些提交的情况下才能执行此操作,因此如果他们没有这些提交,您的 Git 将首先向他们发送提交。您的 Git 不仅会向他们发送这些提示提交(对于三个分支),还会发送任何历史记录\xe2\x80\x94 任何早期提交\xe2\x80\x94 需要将这些提示提交连接到其存储库中的其余提交。branch1branch2branch3branch1branch2branch3
1 Git 文档将这些远程跟踪分支名称称为。但从技术上讲,它们并不是分支名称。特别是,如果你git checkout origin/master,你最终会得到一个分离的头。所以我更喜欢直接称它们为远程跟踪名称,完全放弃“分支”这个词。
2如果您克隆一个完全空的存储库,没有提交,则其 Git 没有分支名称,因为它没有提交,而分支名称需要提交。所以在这种情况下他们不推荐任何东西。然后,您的 Git 必须用作master您的分支名称。当然,您也没有任何提交。因此,现在您会遇到与创建新的空存储库时相同的特殊状态git init:您位于分支上master,但分支master不存在!您位于一个不存在的分支上。Git 的其他部分将此称为孤儿分支。这是一种奇怪的状态,您的下一次提交会创建您所在的分支,以便您可以正确地使用它。在此之前,您只需记录要创建的HEAD分支的名称。
以下是您已学到的内容(以及需要了解的内容):
\n\ngit log命令将显示哈希 ID。宇宙中的每个 Git 都必须就哈希 ID 达成一致。3git clone和git fetch来说最重要git push。名称也很重要,因为它们是每个 Git 查找其提交的方式,但名称对于每个 Git 来说都是本地的:它们不一定是通用的,就像哈希 ID 一样。特别是,随着时间的推移,分支名称预计会发生变化。master在其他Git 中看到的 ? 或者他们的意思是我的Git中看到的远程跟踪名称?origin/master 这些是不同的名称,并且可能指向不同的提交!从现在到您下次查看时,其他 Git 中的分支名称可能会发生变化。谁有权访问其他 Git 存储库,他们现在正在对其执行什么操作?3 Git\xe2\x80\x94 未来将出现复杂情况,没有人确切知道什么时候,\xe2\x80\x94 中的哈希 ID 将被重新编号,从 SHA-1 变为 SHA-256。具体如何处理尚未确定。
\n