繁体   English   中英

本地存储库中的“ remotes / origin / dev”和“ origin / dev”之间有区别吗?

[英]Is there a difference between “remotes/origin/dev” and “origin/dev” in your local repo?

本地存储库中的“ remotes / origin / dev”和“ origin / dev”之间有区别吗?

我似乎见证了一些差异,但尚未向我证明这一点。

通常, remotes/origin/devorigin/dev是表达同一事物的两种方法。 但这不一定是事实! 该问题类似于如果您创建一个名为X分支和一个名为X标签时发生的情况。 在这种情况下,简单地写X是模棱两可的,并且在不同的情况下,您可能不得不写一些不同的东西。

整个故事相当长,但是必须了解正在发生或可能发生的情况。

Git引用具有全名

所有这些名称(分支名称(如master ,标签名称(如v1.2 )和远程跟踪名称(如origin/master都存在于计算机科学/信息学中的单独命名空间命名空间中 如果存在歧义问题,我们在派对上所做的就是我们在同一场派对上所做的相同的事情,所有男人都被命名为布鲁斯,所有女人都被命名为希拉:我们使用不同的名称和/或更长的名称。 在编程语言中,我们倾向于称这些合格的名称 ,它们看起来像std::map 在Git中,我们仅将它们称为参考名称,它们以refs/开头,然后继续确定我们指的是哪个名称空间

Git现有的标准化参考名称空间是按字母顺序排列的,在我写这篇文章时,它是: 1

  • refs/heads/ :分支名称
  • refs/namespaces/ :一个保留的递归空间( git upload-packgit receive-pack特殊技巧,实际上是这些,而不是普通用途)
  • refs/notes/ :由git notes
  • refs/remotes/ :远程跟踪名称
  • refs/replace/ :由git replace
  • refs/stash (无尾斜杠,其中不能包含名称):由git stash
  • refs/tags/ :标签名称

这意味着,如果您同时创建了refs/heads/X (这是一个名为X的分支)和refs/tags/X (这是一个名为X的标签),则可以显式地拼写 refs/heads/X来表示分支Xrefs/tags/X表示标签X。 标准规则有烦人的例外,但首先让我们看一下这些规则。


1名称空间随着时间的推移而增长。


通常的规则

通常,当Git向您显示参考时,它会根据一些简单的规则将其缩短。 而且,如果您使用的不合格的引用(我的意思是名字不是以refs/开头),那么Git会通过六个步骤来弄清楚您的意思。 gitrevisions文档中描述了此六步过程:

当模棱两可时,通过遵循以下规则中的第一个匹配项来消除< refname >的歧义:

  1. 如果$ GIT_DIR / <refname>存在,那就是您的意思(通常仅对HEADFETCH_HEADORIG_HEADMERGE_HEADCHERRY_PICK_HEAD );

  2. 否则, refs / <refname>(如果存在);

  3. 否则,使用refs / tags / <refname>(如果存在);

  4. 否则, refs / heads / <refname>(如果存在);

  5. 否则, 引用/远程/ <refname>(如果存在);

  6. 否则, 引用/远程/ <refname> / HEAD(如果存在)。

因此,如果您编写master ,并且refs/heads/master存在,则通常会获得名为master分支 (从第4步开始)。 因此,如果Git要打印refs/heads/master ,则可能只打印master 同样,如果您编写origin/dev ,并且refs/remotes/origin/dev存在,那么通常会得到(从第5步开始),因此,如果Git要打印refs/remotes/origin/dev ,则它可能只打印origin/dev

有很多例外

如果您运行git branch -r ,那么Git会refs/remotes/

$ git branch -r
  origin/HEAD -> origin/master
  origin/maint
  origin/master
  origin/next
  origin/pu
  origin/todo

这就告诉我们, refs/remotes/origin/HEAD中存在refs/remotes/等。 这些将在上面的步骤5中匹配。

但是,如果您运行git branch -a ,则Git仅从远程跟踪名称中refs/

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/maint
  remotes/origin/master
  remotes/origin/next
  remotes/origin/pu
  remotes/origin/todo

当前的分支master ,实际上是refs/heads/master ,已经剥离了两个组件: refs/heads/ 但是,以前删除了两个组件的远程跟踪名称,现在只删除了一个:例如, remotes/origin/master 这些仍将起作用,实际上,它们将在步骤2中更早地匹配。但是为什么它们不一致? 唯一的答案似乎是: 这很传统。

现在,假设您不小心创建了一个名为master标签 ,即完全限定名称refs/tags/master 根据六个步骤的清单,如果您编写名称master ,那么Git应该首先找到该标记 ,因为这是步骤3。让我们找出它是否确实存在。 首先,让我们看看什么是哈希ID master名称,然后选择一个不同的(早期提交)哈希ID:

$ git rev-parse master
b7bd9486b055c3f967a870311e704e3bb0654e4f
$ git rev-parse master~3
18f2717578853edfdaed5fb7361b5f992a68a79e

现在,让我们创建具有哈希ID 18f2717578853edfdaed5fb7361b5f992a68a79e标记 master 18f2717578853edfdaed5fb7361b5f992a68a79e ,以便第3步将找到此18f27...东西,而不是第4步将找到b7bd9...东西:

$ git tag master 18f2717578853edfdaed5fb7361b5f992a68a79e
$ git rev-parse master
warning: refname 'master' is ambiguous.
18f2717578853edfdaed5fb7361b5f992a68a79e

啊哈:我们收到警告 ,实际上Git确实找到了标签而不是分支。 因此,如果我们运行git checkout master ,我们将检出标签 ,对吗? 错误!

$ git checkout master
warning: refname 'master' is ambiguous.
Already on 'master'
Your branch is up-to-date with 'origin/master'.
$ git rev-parse HEAD
b7bd9486b055c3f967a870311e704e3bb0654e4f

git checkout命令首先尝试将该名称作为分支名称,然后找到commit b7bd9486b055c3f967a870311e704e3bb0654e4f 它仍然给我们警告,但使用了分支名称。 如果我们想要标签名称,则必须完全将其拼写出来,或者使用tags/master来完成步骤2。我更喜欢自己使用完整的拼写:

$ git checkout refs/tags/master
Note: checking out 'refs/tags/master'.

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 performing another checkout.

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

  git checkout -b <new-branch-name>

HEAD is now at 18f2717578... Merge branch 'ms/core-icase-doc'

删除多余的master并恢复理智是一个好主意:

$ git tag -d master
Deleted tag 'master' (was 18f2717578)
$ git checkout master
Previous HEAD position was 18f2717578... Merge branch 'ms/core-icase-doc'
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Git充满了这种奇怪的极端情况,而找出每个命令的实际行为的唯一方法就是进行实验(或避免模棱两可的情况)。

这对于原始问题意味着什么

例如,可以创建一个名为origin/dev分支 (其全名因此为refs/heads/origin/dev或一个远程跟踪名称,其全名为refs/remotes/remotes/origin/dev 如果我们从这个姓氏中剥离两个名称组件,我们将看到remotes/origin/dev ,它看起来像是从git branch -a获得的那种名称,而它只剥离了一个组件。 如果您使用各种颜色选项,则远程跟踪名称默认情况下为红色,而分支名称默认情况下为绿色或黑色,因此其中一些会突出。 但是绝对有可能使自己陷入困境。

要查看所有具有全名的引用,请使用git for-each-ref 请注意,在具有许多标签或分支的存储库中,这会产生大量输出,因此我从Git存储库中剥离了Git的输出:

b7bd9486b055c3f967a870311e704e3bb0654e4f commit refs/heads/master
b7bd9486b055c3f967a870311e704e3bb0654e4f commit refs/remotes/origin/HEAD
53f9a3e157dbbc901a02ac2c73346d375e24978c commit refs/remotes/origin/maint
b7bd9486b055c3f967a870311e704e3bb0654e4f commit refs/remotes/origin/master
5c9ce644c390ec4ef3ba4adc94e7f4af17ade36b commit refs/remotes/origin/next
1aaaa8cf15ba4eb62d485c5c8b64d6a75b9e7c3f commit refs/remotes/origin/pu
f59de5ad04b18866024fb298ddb276cb51d91673 commit refs/remotes/origin/todo
d5aef6e4d58cfe1549adef5b436f3ace984e8c86 tag    refs/tags/gitgui-0.10.0
33682a5e98adfd8ba4ce0e21363c443bd273eb77 tag    refs/tags/gitgui-0.10.1
ca9b793bda20c7d011c96895e9407fac2df9648b tag    refs/tags/gitgui-0.10.2
[mass snippage]
f883596e997fe5bcbc5e89bee01b869721326109 tag    refs/tags/v2.9.3
8d091e9ed473c372a5b89d1258d1c3ad01daa04c tag    refs/tags/v2.9.4
dcba104ffdcf2f27bc5058d8321e7a6c2fe8f27e tag    refs/tags/v2.9.5

这里的名称(在第三列中)是完全限定的,因此您可以查看是否发生任何奇怪的情况。 您还可以仅检查名称空间的特定部分,并使用--format指令来限制输出:

$ git for-each-ref --format='%(refname)' refs/remotes/origin
refs/remotes/origin/HEAD
refs/remotes/origin/maint
refs/remotes/origin/master
refs/remotes/origin/next
refs/remotes/origin/pu
refs/remotes/origin/todo

如果您认为自己处境不好,特别是如果Git警告您名称不明确,则可以使用git for-each-ref分析您的实际情况,并使用该计划来计划恢复。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM