从分离的头创建分支后奇怪的分支名称
Strange branch name after creating branch from detached head
我的 Git 中出现分离头问题。
我对上一次提交进行了结帐。
在那之后,我们做出了承诺。
因此,在我为此提交创建分支之后。
git checkout -b detached-head-after-gitlab-crush
所以在那之后,我进行了更改并提交了更改。
但是现在,当我写 git branch
:
* (detached from a71c5ea)
detached-head-after-gitlab-crush
master
所以我想了解当前分支是什么,它是如何创建的。
怎么修改最后一个分支,而且不能把当前分支推送到原点。
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
根据您的 git 分支命令的结果,您处于提交的分离头部,并且您只创建了一个没有分离提交的新分支。
要从之前的提交创建分支,您有 3 种方法:
- 您可以通过哈希创建分支:
git 分支分支名称 sha1-of-commit
- 或者使用符号引用:
git 分支分支名称 HEAD~5
- 要在创建分支时签出分支,请使用
git checkout -b branchname sha1-of-commit 或 HEAD~3
让我们先快速回顾一下您已经知道的事情:
任何 Git 存储库中的基本存储单元是 commit。提交中有更小的单元——例如,提交包含文件,有点类似于原子如何容纳质子、中子和电子——但提交本身是你应该使用的容器。 (在这个类比中,我们想做化学,而不是核物理。)
每个提交都有自己唯一的哈希 ID。这些散列 ID 又大又丑,人类很难使用,因此 Git 有时会缩短它们以供显示:例如,您有 548af67
(它是更长的东西的缩写), be89a73
(又是 40 个字符长的缩写),依此类推。我从你的 git log --all --decorate --oneline --graph
输出中得到了这些。每个 Git 存储库都同意这些哈希 ID 是为 这些特定的 提交保留的,即使该存储库 没有 这些提交.
您可以始终使用原始哈希 ID 来引用您自己存储库中的任何提交。
提交本身包含:
data: 所有文件的快照。这与之前的提交没有区别。它是每个文件的完整副本。 (这些文件以压缩、冻结、read-only、Git-only格式存储。因为它们是read-only,它们可以是shared。例如,如果你的大多数提交都有一个 README
文件,并且在 90 次提交中只有三个 versions of README
,每 30 次提交更改一次,然后 README 的一个内部 Git-format 冻结副本服务于前 30 次提交,另一台服务器为接下来的 30 次提交服务,依此类推。)
元数据: 信息 关于 提交,例如提交人(姓名和电子邮件地址),何时提交(date-and-time 邮票),以及原因(提交日志消息)。在此元数据中,每个提交都可以列出一些先前提交的原始哈希 ID。
大多数提交只列出一个先前的提交哈希 ID。列出的提交是此提交的 parent,即紧接在此提交之前的提交。一些提交列出了不止一个以前的提交,即有多个 parent。每个 non-empty 存储库中的一次提交是该存储库中的 第一次 提交,因此列出 no parent.
只要 Git 可以访问一个提交,Git 就可以查看该提交的 parent(或 parents),因此可以倒退到前一个提交犯罪。这使 Git 可以访问 parent 提交。所以现在Git可以找到另一个parent——这个parent的parent,即parent的大parent我们刚才的提交——当然那个提交有一个 parent。因此 Git 可以找到 整个历史记录 只需从 最后一个 提交开始并向后工作即可。
分支名称找到特定的提交
但是提交哈希 ID 看起来 是随机的,并且是不可预测的。您和 Git 如何快速轻松地知道哪个提交是 最后一个 提交?这就是 分支名称 的用武之地。像 master
或 detached-head-after-gitlab-crush
这样的分支名称存储 one 提交哈希 ID。根据定义,该哈希 ID 是该分支中的 last 提交。
让我们使用大写字母代表实际的提交哈希 ID。我们会 运行 非常快,这是 Git 不使用简单大写字母的原因之一,但它对我们的绘图来说没问题。假设我们的存储库是全新的,并且其中只有三个提交。第一个是提交 A
,因为它 是 第一个,所以它没有 parent:
A
我们将调用第二个提交 B
。它会记住第一个提交的哈希 ID 作为它的 parent。所以我们会说 commit B
指向 commit A
,然后画成这样:
A <-B
当然,提交 C
包含提交 B
的哈希 ID,因此 C
向后指向 B
:
A <-B <-C
为了快速找到 C
,Git 将其哈希 ID 存储在 name master
:
A--B--C <-- master
(此时我们有点累了,开始偷懒了,将提交与提交之间的连接绘制为线,而不是箭头。请记住,它们仍然是箭头,它们来自 child 并指向 parent,永远不会从 parent 到 child。每个提交的 All 部分将一直冻结,包括从它出来的箭头,所以我们不能返回并稍后添加一个 forward-pointing 箭头:我们提交,它的 parent 有一个或两个 backwards-pointing 箭头,从那时起我们就坚持了。child人知道他们的 parent 是谁,但 parent 永远不知道他们是谁ir children are.)
现在我们有了这个,让我们为这张图片添加另一个分支名称。与其将 crash
拼写为 crush
,不如将其命名为 develop
:
A--B--C <-- master, develop
现在让我们向我们的集合添加一个新的提交。我们使用 Git 中的常规流程来做到这一点。我们将调用新的提交 D
,不管哈希 ID Git 是什么。新提交 D
将指向现有提交 C
因为我们将通过检查提交 C
开始 make D
.所以一旦 D
被制作出来,它就会看起来像这样:
A--B--C
\
D
D
将 up-and-left 指向 C
,C
指向 B
,依此类推。
这就是 HEAD
发挥作用的地方
我们现在有问题。我们有 两个 分支名称。 哪个应该记住新的提交D
?
为了告诉 Git 哪一个,我们将 附加 特殊名称 HEAD
,全部大写,到两个现有分支名称之一.假设我们在进行新提交之前将此作为安排 D
:
A--B--C <-- master (HEAD), develop
那我们之后会得到这个:
A--B--C <-- develop
\
D <-- master (HEAD)
但如果这不是我们想要的,我们应该先 git checkout develop
。那么我们将有:
A--B--C <-- master, develop (HEAD)
当我们进行新提交时 D
,我们将得到:
A--B--C <-- master
\
D <-- develop (HEAD)
无论哪种方式,我们都会得到相同的一组 commits。不同之处在于,当 Git 进行 新提交时,它将新提交的 的哈希 ID 写入 branch-name ] 名字 HEAD
是 attached-to。该分支名称然后自动指向新的提交。
事实上,新提交的parent是之前提交HEAD
的分支名称pointed-to。根据定义,这就是我们提出的 commit。我们使用 git checkout master
或 git checkout develop
,但无论哪种方式,我们都选择了现有提交 C
.
当 HEAD
没有附加到分支名称
时,会出现 分离的 HEAD
现在我们有:
A--B--C <-- master
\
D <-- develop (HEAD)
我们可以继续进行更多新的提交:
A--B--C <-- master
\
D--E--F <-- develop (HEAD)
例如。但如果我们愿意,我们可以把我们的头拿下来。 Git 有一种模式,我们可以使 HEAD
指向 直接 到任何现有的提交。比方说,出于某种原因,我们想让 HEAD
直接指向提交 E
:
A--B--C <-- master
\
D--E <-- HEAD
\
F <-- develop
我们现在可以进行 新 提交——我们称之为 G
——这将指向现有的提交 E
。 Git 会将新提交的哈希 ID(无论它是什么)写入分离的 HEAD,给我们:
A--B--C <-- master
\
D--E--G <-- HEAD
\
F <-- develop
这种模式本身没有什么错误,但它会让事情变得更难。假设我们想再次查看提交 C
。我们可能 运行 git checkout master
。这将再次将名称 HEAD
附加到名称 master
:
A--B--C <-- master (HEAD)
\
D--E--G
\
F <-- develop
您将如何找到 提交G
?我们可以轻松找到 C
:这是我们当前的提交,名称 HEAD
和 master
都可以找到它。我们可以通过返回一个从 C
中找到 B
。我们无法从C
中找到D
,但我们可以从namedevelop
中找到F
。从 F
,我们可以回到 E
,然后从那里回到 D
。但是我们不能前进。 Git 的所有箭头都指向后方。不再有简单的方法来查找提交 G
.
解决方案是在 我们从 G
切换之前添加一个新的分支名称 。这就是您之前在创建名称 detached-head-after-gitlab-crush
时所做的。如果我们知道 G
的哈希 ID(例如,如果它仍在屏幕上),我们可以用另一种方式做同样的事情:
git branch save-it <hash-of-G>
会成功的:
A--B--C <-- master (HEAD)
\
D--E--G <-- save-it
\
F <-- develop
现在我们可以使用提交 C
一段时间,甚至可以进行新的提交 H
,使 master
更改为指向 H
:
A--B--C--H <-- master (HEAD)
\
D--E--G <-- save-it
\
F <-- develop
要回到 G
,我们所要做的就是 git checkout save-it
,它将 HEAD
附加到名称 save-it
(它仍然指向 G
):
A--B--C--H <-- master
\
D--E--G <-- save-it (HEAD)
\
F <-- develop
你需要做的是找出为什么你的 HEAD 总是分离
虽然 Git 中的分离 HEAD 模式从根本上没有错,但很难使用。您必须手动创建 and/or 更新分支名称以记住您的提交。
Git 将在您告诉它时进入此分离的 HEAD 模式:
git checkout --detach master
例如说"I want to use the commit identified by master
, but I want to do that in detached HEAD mode"。
Git 将 也 分离 HEAD 每当你要求它检出(或切换到新的 Git 2.23 和更高版本 git switch
) 通过原始哈希 ID 或任何 而不是 分支名称的名称提交。这包括 remote-tracking 名称 ,如 origin/master
,以及标签名称,如 v1.2
,如果你创建了标签。
一些命令,特别是 git rebase
,将 暂时 在它们 运行 时分离 HEAD。如果他们不能完成,那么哟处于变基的中间,他们将停止并让您处于这种分离的 HEAD 模式。然后你必须选择是完成 rebase,还是用 git rebase --abort
完全终止它。 (如果你不想做其中任何一个,你就会有点卡住了:你真的必须做其中一个。)
所以:找出为什么你总是进入这种分离的 HEAD 模式。你在做什么导致它?您可以使用 git branch
或 git checkout -b
(或在 Git 2.23 及更高版本中,git switch -c
,c
代表创建)为提交创建新的分支名称当你处于分离的 HEAD 模式时修复问题,或者如果你不需要记住你现在在哪里 - 如果你正在故意查看历史提交,你可以并且可能已经找到使用 git log
例如——只需使用 git checkout
或 git switch
来 re-attach 你的 HEAD 到一个现有的分支名称。但除了那些你 do 想要分离的 HEAD(使用标记的提交或查看历史提交)的特殊情况,或者像 working-on-rebase 你处于分离状态的情况HEAD 模式直到你完成,你可能不想要 在分离的 HEAD 模式下工作。所以,不要那样做!
我的 Git 中出现分离头问题。 我对上一次提交进行了结帐。 在那之后,我们做出了承诺。 因此,在我为此提交创建分支之后。
git checkout -b detached-head-after-gitlab-crush
所以在那之后,我进行了更改并提交了更改。
但是现在,当我写 git branch
:
* (detached from a71c5ea)
detached-head-after-gitlab-crush
master
所以我想了解当前分支是什么,它是如何创建的。
怎么修改最后一个分支,而且不能把当前分支推送到原点。
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
根据您的 git 分支命令的结果,您处于提交的分离头部,并且您只创建了一个没有分离提交的新分支。
要从之前的提交创建分支,您有 3 种方法:
- 您可以通过哈希创建分支:
git 分支分支名称 sha1-of-commit
- 或者使用符号引用:
git 分支分支名称 HEAD~5
- 要在创建分支时签出分支,请使用
git checkout -b branchname sha1-of-commit 或 HEAD~3
让我们先快速回顾一下您已经知道的事情:
任何 Git 存储库中的基本存储单元是 commit。提交中有更小的单元——例如,提交包含文件,有点类似于原子如何容纳质子、中子和电子——但提交本身是你应该使用的容器。 (在这个类比中,我们想做化学,而不是核物理。)
每个提交都有自己唯一的哈希 ID。这些散列 ID 又大又丑,人类很难使用,因此 Git 有时会缩短它们以供显示:例如,您有
548af67
(它是更长的东西的缩写),be89a73
(又是 40 个字符长的缩写),依此类推。我从你的git log --all --decorate --oneline --graph
输出中得到了这些。每个 Git 存储库都同意这些哈希 ID 是为 这些特定的 提交保留的,即使该存储库 没有 这些提交.您可以始终使用原始哈希 ID 来引用您自己存储库中的任何提交。
提交本身包含:
data: 所有文件的快照。这与之前的提交没有区别。它是每个文件的完整副本。 (这些文件以压缩、冻结、read-only、Git-only格式存储。因为它们是read-only,它们可以是shared。例如,如果你的大多数提交都有一个
README
文件,并且在 90 次提交中只有三个 versions ofREADME
,每 30 次提交更改一次,然后 README 的一个内部 Git-format 冻结副本服务于前 30 次提交,另一台服务器为接下来的 30 次提交服务,依此类推。)元数据: 信息 关于 提交,例如提交人(姓名和电子邮件地址),何时提交(date-and-time 邮票),以及原因(提交日志消息)。在此元数据中,每个提交都可以列出一些先前提交的原始哈希 ID。
大多数提交只列出一个先前的提交哈希 ID。列出的提交是此提交的 parent,即紧接在此提交之前的提交。一些提交列出了不止一个以前的提交,即有多个 parent。每个 non-empty 存储库中的一次提交是该存储库中的 第一次 提交,因此列出 no parent.
只要 Git 可以访问一个提交,Git 就可以查看该提交的 parent(或 parents),因此可以倒退到前一个提交犯罪。这使 Git 可以访问 parent 提交。所以现在Git可以找到另一个parent——这个parent的parent,即parent的大parent我们刚才的提交——当然那个提交有一个 parent。因此 Git 可以找到 整个历史记录 只需从 最后一个 提交开始并向后工作即可。
分支名称找到特定的提交
但是提交哈希 ID 看起来 是随机的,并且是不可预测的。您和 Git 如何快速轻松地知道哪个提交是 最后一个 提交?这就是 分支名称 的用武之地。像 master
或 detached-head-after-gitlab-crush
这样的分支名称存储 one 提交哈希 ID。根据定义,该哈希 ID 是该分支中的 last 提交。
让我们使用大写字母代表实际的提交哈希 ID。我们会 运行 非常快,这是 Git 不使用简单大写字母的原因之一,但它对我们的绘图来说没问题。假设我们的存储库是全新的,并且其中只有三个提交。第一个是提交 A
,因为它 是 第一个,所以它没有 parent:
A
我们将调用第二个提交 B
。它会记住第一个提交的哈希 ID 作为它的 parent。所以我们会说 commit B
指向 commit A
,然后画成这样:
A <-B
当然,提交 C
包含提交 B
的哈希 ID,因此 C
向后指向 B
:
A <-B <-C
为了快速找到 C
,Git 将其哈希 ID 存储在 name master
:
A--B--C <-- master
(此时我们有点累了,开始偷懒了,将提交与提交之间的连接绘制为线,而不是箭头。请记住,它们仍然是箭头,它们来自 child 并指向 parent,永远不会从 parent 到 child。每个提交的 All 部分将一直冻结,包括从它出来的箭头,所以我们不能返回并稍后添加一个 forward-pointing 箭头:我们提交,它的 parent 有一个或两个 backwards-pointing 箭头,从那时起我们就坚持了。child人知道他们的 parent 是谁,但 parent 永远不知道他们是谁ir children are.)
现在我们有了这个,让我们为这张图片添加另一个分支名称。与其将 crash
拼写为 crush
,不如将其命名为 develop
:
A--B--C <-- master, develop
现在让我们向我们的集合添加一个新的提交。我们使用 Git 中的常规流程来做到这一点。我们将调用新的提交 D
,不管哈希 ID Git 是什么。新提交 D
将指向现有提交 C
因为我们将通过检查提交 C
开始 make D
.所以一旦 D
被制作出来,它就会看起来像这样:
A--B--C
\
D
D
将 up-and-left 指向 C
,C
指向 B
,依此类推。
这就是 HEAD
发挥作用的地方
我们现在有问题。我们有 两个 分支名称。 哪个应该记住新的提交D
?
为了告诉 Git 哪一个,我们将 附加 特殊名称 HEAD
,全部大写,到两个现有分支名称之一.假设我们在进行新提交之前将此作为安排 D
:
A--B--C <-- master (HEAD), develop
那我们之后会得到这个:
A--B--C <-- develop
\
D <-- master (HEAD)
但如果这不是我们想要的,我们应该先 git checkout develop
。那么我们将有:
A--B--C <-- master, develop (HEAD)
当我们进行新提交时 D
,我们将得到:
A--B--C <-- master
\
D <-- develop (HEAD)
无论哪种方式,我们都会得到相同的一组 commits。不同之处在于,当 Git 进行 新提交时,它将新提交的 的哈希 ID 写入 branch-name ] 名字 HEAD
是 attached-to。该分支名称然后自动指向新的提交。
事实上,新提交的parent是之前提交HEAD
的分支名称pointed-to。根据定义,这就是我们提出的 commit。我们使用 git checkout master
或 git checkout develop
,但无论哪种方式,我们都选择了现有提交 C
.
当 HEAD
没有附加到分支名称
时,会出现 分离的 HEAD
现在我们有:
A--B--C <-- master
\
D <-- develop (HEAD)
我们可以继续进行更多新的提交:
A--B--C <-- master
\
D--E--F <-- develop (HEAD)
例如。但如果我们愿意,我们可以把我们的头拿下来。 Git 有一种模式,我们可以使 HEAD
指向 直接 到任何现有的提交。比方说,出于某种原因,我们想让 HEAD
直接指向提交 E
:
A--B--C <-- master
\
D--E <-- HEAD
\
F <-- develop
我们现在可以进行 新 提交——我们称之为 G
——这将指向现有的提交 E
。 Git 会将新提交的哈希 ID(无论它是什么)写入分离的 HEAD,给我们:
A--B--C <-- master
\
D--E--G <-- HEAD
\
F <-- develop
这种模式本身没有什么错误,但它会让事情变得更难。假设我们想再次查看提交 C
。我们可能 运行 git checkout master
。这将再次将名称 HEAD
附加到名称 master
:
A--B--C <-- master (HEAD)
\
D--E--G
\
F <-- develop
您将如何找到 提交G
?我们可以轻松找到 C
:这是我们当前的提交,名称 HEAD
和 master
都可以找到它。我们可以通过返回一个从 C
中找到 B
。我们无法从C
中找到D
,但我们可以从namedevelop
中找到F
。从 F
,我们可以回到 E
,然后从那里回到 D
。但是我们不能前进。 Git 的所有箭头都指向后方。不再有简单的方法来查找提交 G
.
解决方案是在 我们从 G
切换之前添加一个新的分支名称 。这就是您之前在创建名称 detached-head-after-gitlab-crush
时所做的。如果我们知道 G
的哈希 ID(例如,如果它仍在屏幕上),我们可以用另一种方式做同样的事情:
git branch save-it <hash-of-G>
会成功的:
A--B--C <-- master (HEAD)
\
D--E--G <-- save-it
\
F <-- develop
现在我们可以使用提交 C
一段时间,甚至可以进行新的提交 H
,使 master
更改为指向 H
:
A--B--C--H <-- master (HEAD)
\
D--E--G <-- save-it
\
F <-- develop
要回到 G
,我们所要做的就是 git checkout save-it
,它将 HEAD
附加到名称 save-it
(它仍然指向 G
):
A--B--C--H <-- master
\
D--E--G <-- save-it (HEAD)
\
F <-- develop
你需要做的是找出为什么你的 HEAD 总是分离
虽然 Git 中的分离 HEAD 模式从根本上没有错,但很难使用。您必须手动创建 and/or 更新分支名称以记住您的提交。
Git 将在您告诉它时进入此分离的 HEAD 模式:
git checkout --detach master
例如说"I want to use the commit identified by master
, but I want to do that in detached HEAD mode"。
Git 将 也 分离 HEAD 每当你要求它检出(或切换到新的 Git 2.23 和更高版本 git switch
) 通过原始哈希 ID 或任何 而不是 分支名称的名称提交。这包括 remote-tracking 名称 ,如 origin/master
,以及标签名称,如 v1.2
,如果你创建了标签。
一些命令,特别是 git rebase
,将 暂时 在它们 运行 时分离 HEAD。如果他们不能完成,那么哟处于变基的中间,他们将停止并让您处于这种分离的 HEAD 模式。然后你必须选择是完成 rebase,还是用 git rebase --abort
完全终止它。 (如果你不想做其中任何一个,你就会有点卡住了:你真的必须做其中一个。)
所以:找出为什么你总是进入这种分离的 HEAD 模式。你在做什么导致它?您可以使用 git branch
或 git checkout -b
(或在 Git 2.23 及更高版本中,git switch -c
,c
代表创建)为提交创建新的分支名称当你处于分离的 HEAD 模式时修复问题,或者如果你不需要记住你现在在哪里 - 如果你正在故意查看历史提交,你可以并且可能已经找到使用 git log
例如——只需使用 git checkout
或 git switch
来 re-attach 你的 HEAD 到一个现有的分支名称。但除了那些你 do 想要分离的 HEAD(使用标记的提交或查看历史提交)的特殊情况,或者像 working-on-rebase 你处于分离状态的情况HEAD 模式直到你完成,你可能不想要 在分离的 HEAD 模式下工作。所以,不要那样做!