首页 > 解决方案 > 从远程获取分支后,我无法在 Git 中签出分支

问题描述

当我执行 a 时,git fetch --all 我可以看到我的分支正在从远程获取,它显示如下* [new branch] <branch name> -> origin/<branch name>,然后当我使用命令结帐时,git checkout <new branch>什么也没有发生。

所以我用命令从原点结帐,git checkout origin/<branch name>但奇怪的是它说我在不同的头上,但我仍然在 master 分支上,但头上的不同?(我在这里也很困惑)。

实际消息:

HIT-STORE on master <----- see this im still on master
gco origin/588-feature-message-project-list-view  <---- this is the branch I want to checkout
HEAD is now at 11faa7cb fixes #584: member sign up <-- instead I got this!

我以前就是这么做的。

  1. 在 gitlab 中创建一个分支
  2. 运行命令git fetch --all
  3. git checkout <new branch>

就是这样,然后我在本地有我的分支。


我也尝试过git branch --track <new branch> origin/<new branch>,它会解决它。但是下次如果我创建一个新分支,我仍然会遇到同样的问题。

我也试过点击这个链接

git config --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*

我也尝试删除和添加遥控器,但没有任何反应。


这也是我的 Git 配置:

在此处输入图像描述

我刚刚添加了这一点,ff = only因为我收到了来自 Git 的一些警告。如果删除它,我会收到有关拉动的警告。


更新

仅供参考,这与检查分支不同。我在签出分支时遇到问题。

因此,当我在 Gitlab 上创建分支时,我必须先执行以下步骤:

  1. git fetch --all
  2. 然后 git 将更新我的远程源以拥有新分支
  3. 然后我必须像以前一样使用命令 `git checkout <the_new_brach> 简单地检查一个分支
  4. 我可以在那个分支上工作。

这就是问题。我在 Gitlab 上创建了一个分支。

  1. git fetch --all
  2. 然后 git 将更新我的远程源以拥有新分支
  3. 这是我执行 git checkout 时的问题部分git checkout new_branch。我会得到这个错误。error: pathspec 'new_branch' did not match any file(s) known to git. 所以我说好。也许我需要从原点结帐。所以我运行命令。git checkout origin/new_branch然后我得到这个 HEAD 错误/警告:
Note: switching to 'origin/new_branch'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 8a55a856 Merge branch 'hotfix-branch-base1'

在我运行时收到该错误/警告后,cat .git/HEAD我得到一个 SHA:

$ cat .git/HEAD                                    
8a55a856dd9a9756533158bf28a98bab81b0d0c6

我以前从未遇到过。现在要解决这个问题,我必须运行命令。git branch --track new_branch origin/new_branch每次我结帐一个分支。每次我结帐分支时,这都很烦人。

标签: gitversion-control

解决方案


我不清楚您的问题(在编辑之前或之后)究竟是什么导致了问题,但这里有一些背景和我自己的猜测:

  1. Git 有多种名称:分支名称、标签名称、远程跟踪名称等。这些名称存在于名称空间中,分支名称在技术上是以 . 开头的名称refs/heads/。您总是可以完全拼出这些名称之一:refs/heads/X表示分支 Xrefs/tags/X表示标记 X,即使您有一个共享缩短名称的分支和标记。该名称X将表示它匹配的任何一个:如果您只有一个名为 X 的分支,则为分支 X,或者如果您只有一个名为 X 的标签,则为标签 X。

    一般来说,人类喜欢缩短他们的名字。我们看到像 Robert 变成 Bob、Christine 变成 Chris 等等这样的名字,所以这不是 Git 或计算机特有的,甚至。但是如果它是模棱两可的——比如在一个每个人都叫布鲁斯的聚会上——我们总是可以使用一些更长的、明确的名字,比如布鲁斯布鲁森。

  2. git checkout(并且,从 Git 2.23 开始,git switch)在某些情况下会创建一个的分支名称。这种创建在内部被称为“DWIM 模式”,DWIM 代表 Do What I Mean(与我所说的相反)。有一个--no-guess选项可以禁用git checkout禁用DWIM 模式,尽管目前它只是正确记录在案。即将到来的 Git 更新将改进文档并添加配置设置以默认启用或禁用猜测。git switchgit switch

第2 项的某些情况部分可能是事情出错的地方。 在 Git 2.23 版本之前,你必须非常注意这部分,因为它会破坏你所做的工作。这在 Git 版本 2.23 中得到修复,Git 检测到其中一种模棱两可的情况并警告您使用更具体的命令。

(如果可能的话,我建议升级。破坏工作的情况非常罕见,原因有很多,但当它发生时也很讨厌。让 Git 停止并让你消除你的意图是一件非常好的事情。)

情况

假设您运行:

git checkout abcd

该字符串abcd可以用四种不同的方式解释:

  • 它可能是一个简短版本的分支名称,特别是如果你有一个refs/heads/abcd,根据定义,它是一个以 . 开头的分支名称refs/heads

  • 它可能是一个缩短的哈希 ID。哈希 ID 是任何 Git 提交或任何内部 Git 对象的真实名称。哈希 ID 当前为1,表示为 40 个字符的十六进制字符串,例如e1cfff676549cdcd702cbac105468723ef2722f4. 它们可以缩短到前四个字符,只要这是明确的(如果不明确,您只需使用更多字符)。请注意,具有不在[0-9a-fA-F] 集中的任何字符的分支名称不能以这种方式被误解:名称beef可能是缩短的散列,但beer绝对不是缩短的散列。

  • 如果不存在refs/heads/abcd且不是缩短的哈希 ID,则可能是使用猜测 DWIM 模式创建的请求。 abcd

  • 最后,它可能是您希望提取 的文件或目录的名称,或更正式地说,是路径规范。在我看来,这是一个危险的案例。 这是被复制到两个单独命令中的原因之一,并且在 Git 版本 2.23 中:永远不会解释为最后一种情况;只会这样解释。git checkoutgit checkoutgit switchgit restoregit switchabcdgit restore

在 DWIM 情况下(并且仅在这种情况下),Git 将搜索您的远程跟踪名称2 这些是以 开头的名称refs/remotes/。您的 Git 将一些其他 Git 的分支名称复制到您自己的远程跟踪名称中,这样如果它们有masterand develop,您就会得到origin/masterand origin/develop,前提是您调用了另一个 Git origin3 如果您的 Git 准确找到了一个合适的远程跟踪名称,您的 Git 会假装您写道:

git checkout -b <branch> --track <remote>/<branch>

从而做到了你的意思,而不是你所说的:DWIM!


1 Git 正朝着使用 SHA-256 而不是 SHA-1 的方向发展,然后哈希 ID 将是 64 个字符而不是 40,以便保存 256 位数字而不是 160 位数字。

2 Git 调用这些远程跟踪分支名称。它们是分支名称复制的,但它们不充当分支名称,而且我发现从名称中删除单词分支更容易混淆。

3因为当只有另一个 Git 并且大多数人使用另一个 Git 时,它是“另一个 Git”origin默认origin/*名称,所以这通常是唯一的远程,因此也是唯一的一组远程跟踪名称: .


当他们不适用时

在以下情况下,您的 Git不会使用 DWIM 模式:

  • 没有匹配的远程跟踪名称。根本没有候选人,所以这不可能发生。

  • 有两个或多个匹配的远程跟踪名称。仅当您有两个或多个遥控器时才会发生这种情况,例如两者originupstream

    假设您没有名为的分支beer并且您运行git checkout beer. 您的 Git 无法将其解释为分支名称,因为您没有分支名称beer;您的 Git 无法将其解释为缩短的哈希 ID,因为r它不是有效的十六进制字符。但是你有一个origin/beer. 这是创建您自己的beer. 但是如果你有一个upstream/beer,那么,现在你有两个候选人。这太多了,DWIM 将不适用。

  • 其他情况之一首先匹配。

我认为最后一个就是在这里咬你的情况。假设您正在跑步git checkout dev。您显然没有名为 的现有分支dev,因为如果您这样做了,您会收到有关切换到它的消息,并且您将不再在master. 所以不是这样的。该字母v不是有效的十六进制字符,并且三个字母——<code>dev——太短了,Git 无法将其用作缩短的哈希名称,因此可能也不是这种情况。

但是,如果您有一个名为 的文件或目录dev怎么办?然后:

git checkout dev

被解释为:

git checkout -- dev

这意味着将(或,如果是目录)的工作树内容替换为devdev/*devGit 索引中的内容。此功能不存在,git switch因为它被放入git restore,以避免意外破坏未git add编辑的工作。

我认为是这种情况的原因是,如果您没有要签出的分支并且没有其他匹配项以便 Git 尝试执行 DWIM 技巧并且由于任何原因而失败,那么在 DWIM 失败后,您会得到一个错误信息。您没有收到错误消息,因此结帐必须成功。

该怎么办

你有两个选择:

  • 不要使用那个名字。分支名称对 Git 实际上并不重要,因此您可以使用其他拼写。不过,您可能有某种外部 Git 约束,让您真的想使用该拼写。

  • 使命令明确。

为了使命令明确,您有多种选择:

  • 使用-b,如克里斯托夫的回答。您可以添加一个显式的,就像我文档--track中的剪切和粘贴一样,或者如果您希望新分支没有上游集。4git checkout--no-track

  • 使用git checkout --track origin/dev. 如果没有该-b选项,Git 实际上会反转 DWIM 逻辑并将远程跟踪名称 origin/dev(即,refs/remotes/origin/dev)转换为分支名称dev(即,refs/heads/dev)。

  • 使用. 告诉 Git这绝对不是路径规范。(我不是这种特殊方法的忠实粉丝,但这更多的是品味问题。)git checkout name ----

  • 用于git branch创建分支名称,然后是单独的git checkout. 这回避了所有 DWIM 的东西,因为git branch它总是知道它正在处理一个分支名称。当然,缺点是它需要额外的步骤。

  • 使用任何其他多步骤方法,例如将提交检出为分离的 HEAD,然后git checkout -b创建分支名称。


4我不知道您为什么想要它,但它可以作为一个选项使用。


为什么git checkout origin/dev会导致“分离的 HEAD”

Git 有两种正常的操作模式,Git 称之为附加 HEAD分离 HEAD。分离的 HEAD 模式实际上是用于特殊目的的操作,例如当您处于需要手动解决冲突的正在进行的 rebase 中时。您可以将其用于普通的日常工作,但这需要一定程度的受虐狂。

附加的 HEAD模式下,Git 的特殊名称——应该总是像这样5HEAD那样全大写——附加到一个分支名称。Git 使用它来启用通过该分支名称查找当前提交,并在进行新提交时自动更新该分支名称。但是因为只有分支名称应该像这样自动更新,Git 不会将特殊名称附加到任何不是分支名称的东西上。HEADHEAD

namerefs/remotes/origin/dev或任何类似的远程跟踪名称根本不是分支名称。(再次参见脚注 2。)Git 不会附加HEAD到这些名称之一。所以git checkout origin/dev,或任何类似的东西,都会导致与. 在 Git 2.23 及更高版本中,该命令要求您在执行此类操作时添加选项,以确保您知道自己在做什么,但只是愉快地假设您知道分离 HEAD 模式是关于什么的,最多,打印警告。git checkout hash-IDgit switch--detachgit checkout


5全小写或混合拼写,例如headandHeAd有时适用于某些文件系统,目前通常在 Windows 和 macOS 上,但有两个问题:Git 的未来版本可能会使它完全停止工作,有时它不会无论如何都行不通。如果您在添加的工作树中,小写拼写指的是主工作树的HEAD,而不是添加的工作树的HEAD。无论如何,这是一个坏习惯。如果您发现名称HEAD太长,请考虑使用其同义词:单个字符@。由于是后期的 Git 1.8 左右版本,因此@可以在任何地方HEAD使用。


推荐阅读