git - 为什么 git reset 不能拉取请求
问题描述
有时我登录到一个云实例,拉一个 repo,然后想尝试一个拉请求。我现在使用的命令是
git fetch origin pull/<ID>/head && git checkout FETCH_HEAD
这很长。我也尝试过更短的方法
git reset --hard origin/pull/<ID>
git reset --hard origin/pull/<ID>/head
git reset --hard origin/pull/<ID>/HEAD
给出以下错误
$ git reset --hard origin/pull/27
fatal: ambiguous argument 'origin/pull/27': unknown revision
or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
为什么git reset --hard origin/<some-branch>
工作但拉取请求分支不工作?
我注意到在输出中
$ git ls-remote origin
常规分支和拉取请求分支之间存在差异。例如
c31a55 refs/heads/fix-async-stdout-order
615f5a refs/pull/10/head
与有何heads
不同?pull
(我在这里缩短了哈希,所以它看起来更干净)
解决方案
每个 Git 存储库都有自己的名称副本。每个名称都映射到一个哈希 ID,例如,在您的示例中:
c31a55 refs/heads/fix-async-stdout-order 615f5a refs/pull/10/head
您建议refs/heads/fix-async-stdout-order
映射到 hash ID c31a55
,并refs/pull/10/head
映射到 hash ID 615f5a
。1
名称是 Git 称为refs或references的东西。(散列 ID 是您现在应该非常熟悉的散列。)
在大多数情况下,当您为 Git 命名时,Git 会立即将其转换为底层哈希 ID。哈希 ID 才是真正重要的:提供这些名称主要是为了让我们这些普通人能够处理作为哈希 ID 的真实姓名。哈希 ID 永远不会改变:它们总是唯一地标识特定的内容——例如,一个特定的提交。提交及其哈希 ID 是永久的,而一个或多个名称可以随意创建或销毁。2
当一个名称标识一个提交时,我们可以直接使用该名称来查找该提交:refs/heads/fix-async-stdout-order
例如,标识 commit c31a55
。但是提交也允许我们找到它们的直接父提交:从c31a55
我们可以向后工作到它的父提交,并且从那个父提交我们可以向后工作另一个步骤到另一个提交,依此类推,一直回到时间的开始在存储库中。因此,这样的名称不仅用于查找它存储其哈希 ID 的一个提交,而且还用于查找其链中所有较早的提交。
当名称是分支名称时(就像这个名称一样),Git 还允许我们专门将它与git checkout
. 该git checkout
命令将另一个特殊名称 , 附加HEAD
到分支名称。Git 现在认为我们“在”分支上,因此如果我们进行新的提交,Git 将自动更改存储在该分支名称下的哈希 ID。
也就是说,之后:
git checkout fix-async-stdout-order
如果我们做一些工作然后进行新的提交,名称fix-async-stdout-order
——实际上是refs/heads/fix-async-stdout-order
,我们只是为了显示目的而将其缩短了——将停止指向提交c31a55
并开始,而是指向我们的新提交。我们的新提交将c31a55
作为其父级。
能够“进入”一个分支的这个属性只允许用于分支名称。Git 有很多名称:分支名称、标签名称、远程跟踪名称等。它们都是引用,但只有拼写开头的引用refs/heads/
才是分支名称。
引用refs/tags/v1.2
(如果存在)是名为的标记v1.2
。
引用refs/remotes/origin/master
(如果存在)是远程跟踪名称 origin/master
。
这些前缀中的每一个——<code>refs/heads/ refs/tags/
、 和refs/remotes/
——代表一个命名空间。refs/heads/
命名空间中的引用是分支名称。
除了允许git checkout
以上述方式使用它们方面的特殊性之外,分支名称的另一个特殊功能发生在客户端 Git(例如您自己的 Git)连接到服务器 Git 时。服务器 Git 为客户端显示其所有名称,包括分支名称,以及这些名称所代表的哈希 ID。客户端Git 会复制服务器的分支名称,但同时更改它们,以便服务器调用什么refs/heads/master
,客户端调用什么refs/remotes/origin/master
。
这个过程是你的Git 首先拥有远程跟踪名称的方式。服务器 Git 有它的分支,你的 Git 会出现——当你运行时git fetch
——看到并记住它们的分支作为你的远程跟踪origin/*
名称。这些存在于您的 Git 中,在refs/remotes/
命名空间中。
此过程仅发生在分支名称上!3 由于refs/pull/10/head
不以 开头refs/heads/
,因此不是分支名称。该过程不适用于refs/pull/10/head
. 这就是为什么以及如何heads
不同于pull
.
1这些都是缩写的哈希 ID;实际的哈希 ID 目前总是 40 个字符长。
2这里需要注意的是,如果没有允许您查找提交或其他 Git 对象的名称,则该提交或其他对象现在不受Git 垃圾收集过程的保护。因此,名称不仅可以让我们找到链中的最后一个提交,还可以保护该提交及其所有前辈不被当作垃圾丢弃。
3这个过程是可编程的,通过 Git 所说的refspecs。上面的描述仅适用于您在运行时获得的默认git clone
refspecs 。如果您编写自己的 refspec,则可以更改此处发生的情况。请参阅文档并注意这是git fetch
remote.origin.fetch
一个累积设置;每个实例都remote.origin.fetch
提供一个 refspec。
克隆时的默认设置是 Git 创建一个remote.origin.fetch
设置,将其所有分支复制到您的远程跟踪名称,或者如果您在克隆期间选择,则将其分支之一复制到一个远程--single-branch
跟踪名称。
推荐阅读
- django - 名字、姓氏和图像未显示
- angular - Angular 中的纯管道
- javascript - JavaScript 更新并依赖于选择输入
- python - 如何单独浏览子文件夹?
- three.js - THREE.js:响应鼠标事件而变形的球体
- sql - 按男性和女性 SQL 分组 -
- iterm2 - iterm2 shell 提示现在显示“(base)”
- google-apps-script - UrlFetchApp.Fetch 返回状态 200 但 Google 脚本 Web 应用程序不起作用
- python - Pandas 代码将大于 0.5 的值舍入为 1
- powershell - 加密 Excel 电子表格 epplus powershell