ard*_*kar 1 git git-branch git-detached-head
我的 Git 中出现了一个分离头的问题。我对之前的提交进行了检查。之后,我们做出了承诺。所以在我为此提交创建分支之后。
git checkout -b detached-head-after-gitlab-crush
所以在那之后,我做出了改变并承诺了改变。
但现在,当我写下git branch:
* (detached from a71c5ea)
detached-head-after-gitlab-crush
master
Run Code Online (Sandbox Code Playgroud)
所以我想了解当前分支是什么以及它是如何创建的。
我如何对最后一个分支进行更改,而且我无法将当前分支推送到原点。
git log --all --decorate --oneline --graph
显示以下结果:
* 548af67 (HEAD) Images were changed, and issue with Printing Gate entry records
* be89a73 (origin/detached-head-after-gitlab-crush, detached-head-after-gitlab-c
* 6979cba Files before solving HEAD detached problem
* fb89a62 Rules added, made some changes which I don't remember
| * d4183f3 (origin/master, origin/HEAD, master) Merged files
| |\
|/ /
| * 3c3cadc Merge branch 'master' of http://gitlab.sdu.edu.kz/sdu/portal
Run Code Online (Sandbox Code Playgroud)
让我们首先快速回顾一下您已经知道的事情:
\n\n任何 Git 存储库中的基本存储单位都是提交。commits\xe2\x80\x94 中有更小的单元,例如,commits 包含文件,有点类似于原子保存质子、中子和电子的方式 \xe2\x80\x94,但 commit 本身就是你应该存放的容器使用。(在这个类比中,我们想要研究化学,而不是核物理。)
每个提交都有自己唯一的哈希 ID。这些哈希 ID 又大又难看,而且人类很难使用,因此 Git 有时会缩短它们以供显示:例如,548af67(它是更长的东西的缩写),be89a73(同样是 40 个字符长的东西的缩写) , 等等。我从你的git log --all --decorate --oneline --graph输出中得到了这些。每个 Git 存储库都同意这些哈希 ID 是为这些特定提交保留的,即使该存储库没有这些提交。
您始终可以使用原始哈希 ID 来引用您自己的存储库中的任何提交。
提交本身包含:
\n\n数据:所有文件的快照。这与之前的提交没有区别。它是每个文件的完整副本。(这些文件以压缩、冻结、只读、Git-only 格式存储。因为它们是只读的,所以可以共享。例如,如果您的大多数提交都有一个README文件,并且只有三个版本在README90 次提交中,每 30 次提交进行一次更改,然后一个内部 Git 格式的 README 冻结副本服务于前 30 次提交,另一个服务于接下来的 30 次提交,依此类推。)
元数据:有关提交的信息,例如谁进行了提交(姓名和电子邮件地址)、时间(日期和时间戳)以及原因(提交日志消息)。在此元数据中,每个提交都可以列出一些先前提交的原始哈希 ID。
大多数提交恰好列出了一个先前的提交哈希 ID。列出的提交是此提交的父提交,即在此提交之前的提交。一些提交列出了多个先前提交,即具有多个父提交。每个非空存储库中的一次提交是该存储库中的第一次提交,因此不会列出父级。
每当 Git 有权访问一个提交时,Git 就可以查看该提交的父级(或多个父级),从而向后工作到上一个提交。这使 Git 可以访问父提交。所以现在 Git 可以找到另一个父级\xe2\x80\x94,这个父级的父级,即我们刚才的提交的祖父\xe2\x80\x94,当然这个提交有一个父级。因此,Git只需从最后一次提交开始并向后查找即可找到整个历史记录。
\n\n但提交哈希 ID看起来是随机的,并且是不可预测的。你\xe2\x80\x94和Git\xe2\x80\x94如何快速、轻松地知道哪个提交是最后一个?这就是分支名称的master用武之地。类似或 的分支名称detached-head-after-gitlab-crush存储一个提交哈希 ID。根据定义,该哈希 ID 是该分支中的最后一次提交。
让我们使用大写字母来代表实际的提交哈希 ID。我们很快就会用完,这是 Git 不使用简单大写字母的原因之一,但对于我们的绘图来说是没问题的。假设我们的存储库确实是新的,并且只有三个提交。第一个是 commit A,因为它是第一个,所以它没有父级:
A\nRun Code Online (Sandbox Code Playgroud)\n\n我们将调用第二次提交B。它会记住第一次提交的哈希 ID 作为其父提交。所以我们会说 commitB 指向commit A,并像这样绘制:
A <-B\nRun Code Online (Sandbox Code Playgroud)\n\n当然, commitC包含 commit 的哈希 ID B,因此C向后指向B:
A <-B <-C\nRun Code Online (Sandbox Code Playgroud)\n\n为了C快速查找,Git 将其哈希 ID 存储在名称 master中:
A--B--C <-- master\nRun Code Online (Sandbox Code Playgroud)\n\n(此时我们有点累了,变得懒惰了,将提交与提交之间的连接绘制为线条,而不是箭头。只要记住它们仍然是箭头,它们从子项中出来并指向父级,永远不会从父级到子级。 每次提交的所有部分都将一直冻结,包括从中出来的箭头,因此我们无法返回并稍后添加向前指向的箭头:我们进行提交,它有一个或两个向后指向其父母的箭头,从那时起我们就坚持这一点。孩子们知道他们的父母是谁,但父母永远不知道他们的孩子是谁。)
\n\n现在我们有了这个,让我们向这张图片添加另一个分支名称。而不是像crash我crush这样称呼这个develop:
A--B--C <-- master, develop\nRun Code Online (Sandbox Code Playgroud)\n\n现在让我们向我们的集合添加一个新的提交。我们使用 Git 中的常规流程来完成此操作。我们将调用新的提交D,无论 Git 提供什么哈希 ID。新的提交D将指向现有的提交C,因为我们将开始通过检查提交来进行制作 。所以一旦制作完成,它将看起来像这样:DCD
A--B--C\n \\\n D\nRun Code Online (Sandbox Code Playgroud)\n\nD向上和向左指向、C向后C指向B,等等。
HEAD进来的地方我们现在有问题。我们有两个分支名称。 哪一个应该记住新的提交D?
为了告诉 Git 是哪一个,我们将把所有大写字母的特殊名称附加HEAD到两个现有分支名称之一。假设我们在进行新提交之前有这样的安排D:
A--B--C <-- master (HEAD), develop\nRun Code Online (Sandbox Code Playgroud)\n\n然后我们会得到这个:
\n\nA--B--C <-- develop\n \\\n D <-- master (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n\n但如果这不是我们想要的,我们应该git checkout develop首先这样做。然后我们将有:
A--B--C <-- master, develop (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n\n当我们进行新的提交时D,我们将得到:
A--B--C <-- master\n \\\n D <-- develop (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n\n无论哪种方式,我们都会得到相同的提交集。不同之处在于,当 Git进行新提交时,它将新提交的HEAD哈希 ID 写入该名称所附加的任何分支名称。然后该分支名称会自动指向新的提交。
事实上,新提交的父级HEAD是之前指向的提交的分支名称。根据定义,这就是我们做出的承诺。我们使用了git checkout masteror git checkout develop,但无论哪种方式,我们都选择了现有的提交C。
HEAD现在我们有:
\n\nA--B--C <-- master\n \\\n D <-- develop (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n\n我们可以继续进行更多新的提交:
\n\nA--B--C <-- master\n \\\n D--E--F <-- develop (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n\n例如。但如果我们愿意,我们可以把头拿下来。Git 有一种模式,我们可以直接HEAD指向任何现有的提交。比方说,由于某种原因,我们想直接提交我们的观点:HEADE
A--B--C <-- master\n \\\n D--E <-- HEAD\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n我们现在可以创建一个新的提交\xe2\x80\x94,我们将其称为G\xe2\x80\x94,它将指向现有的提交E。Git 会将新提交的哈希 ID(无论它是什么)写入分离的 HEAD 中,从而为我们提供:
A--B--C <-- master\n \\\n D--E--G <-- HEAD\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n这种模式本质上并没有什么问题,但它会让以后的事情变得更加困难。假设我们想C再次查看提交。我们可能会跑git checkout master。这会将名称再次附加HEAD到名称上master:
A--B--C <-- master (HEAD)\n \\\n D--E--G\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n你将如何找到提交G?我们可以轻松找到C:这是我们当前的提交和名称HEAD,并且master都可以找到它。我们可以通过返回一个来B找到。C我们无法D从 中找到C,但可以F从名称 develop中找到。从F,我们可以退回到E,并从那里到D。但我们无法向前迈出一步。Git 的所有箭头都指向向后。不再有一种简单的方法可以找到 commit G。
解决方案是在我们切换到G. 这就是您之前创建名称时所做的事情detached-head-after-gitlab-crush。如果我们知道哈希 ID G(例如,如果它仍然在屏幕上),我们可以用另一种方式做同样的事情:
git branch save-it <hash-of-G>\nRun Code Online (Sandbox Code Playgroud)\n\n会成功的:
\n\nA--B--C <-- master (HEAD)\n \\\n D--E--G <-- save-it\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n现在我们可以使用 commitC一段时间,甚至可能进行一个新的提交H,使master更改指向H:
A--B--C--H <-- master (HEAD)\n \\\n D--E--G <-- save-it\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n要返回到 ,我们所要做的G就是git checkout save-it,它附加HEAD到名称save-it(仍然指向G):
A--B--C--H <-- master\n \\\n D--E--G <-- save-it (HEAD)\n \\\n F <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n虽然 Git 中的分离 HEAD 模式没有什么根本性的错误,但它很难使用。您必须手动创建和/或更新分支名称才能记住您的提交。
\n\n每当你告诉 Git 时,它都会进入这种分离的 HEAD 模式:
\n\ngit checkout --detach master\nRun Code Online (Sandbox Code Playgroud)\n\n例如,“我想使用由 标识的提交master,但我想在分离的 HEAD 模式下执行此操作”。
每当您要求 Git通过原始哈希 ID 或任何非分支名称签出(或切换到新的 Git 2.23 及更高版本)提交时, Git也会分离 HEAD。这包括远程跟踪名称(如 )和标签名称(如 )(如果您已创建标签)。git switchorigin/masterv1.2
某些命令(包括专门的命令git rebase)将在运行时暂时分离 HEAD。如果他们无法完成,那么您正处于变基过程中,他们将停止并让您处于这种分离的 HEAD 模式。然后,您必须选择是完成变基,还是使用 完全终止它git rebase --abort。(如果你不想做其中任何一个,那么你就有点陷入困境:你确实必须做其中一个。)
所以:找出为什么你总是进入这种分离的 HEAD 模式。你在做什么导致它发生?git branch您可以使用, 或 with git checkout -b(或者在 Git 2.23 及更高版本中,git switch -c,代表创建)为提交创建新的分支名称,c以在处于分离 HEAD 模式时或者不需要记住位置时修复问题你现在是\xe2\x80\x94如果你故意查看历史提交,你可以并且可能确实发现使用git log例如\xe2\x80\x94只需使用git checkout或git switch将你的HEAD重新附加到现有的分支名称。但是,除了那些您确实需要分离 HEAD 的特殊情况(以使用标记提交或查看历史提交),或者像在 rebase 上工作这样在完成之前处于分离 HEAD 模式的情况,您可能不\不想在分离的 HEAD 模式下工作。所以,不要这样做!
| 归档时间: |
|
| 查看次数: |
648 次 |
| 最近记录: |