为什么不能 git 重置为拉取请求
Why cannot git reset to pull request
有时我登录到一个云实例,拉取一个存储库,然后想尝试一个拉取请求。我现在使用的命令是
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
有何不同? (我在这里缩短了哈希值,这样视觉上更清晰)
GitHub suggests:git fetch origin pull/ID/head:BRANCHNAME
:这样你就可以控制本地分支命名约定,而不是创建(由于 PR 的 GitHub 上的默认 refspec)
但是你有 more advance techniques here:
[alias]
copr = "!f() { git fetch -fu ${2:-origin} refs/pull//head:pr/ &&
git checkout pr/; }; f"
然后:
$ git copr 1234 # gets and switches to pr/1234 from origin
$ git copr 789 upstream # gets and switches to pr/789 from upstream
hub 也因包装 PR 导入而闻名。
每个 Git 存储库都有自己的名称副本。每个名称都映射到一个哈希 ID,例如,在您的示例中:
c31a55 refs/heads/fix-async-stdout-order
615f5a refs/pull/10/head
您建议 refs/heads/fix-async-stdout-order
映射到哈希 ID c31a55
,refs/pull/10/head
映射到哈希 ID 615f5a
。1
names 是 Git 调用 refs 或 references 的东西。 (哈希 ID 是您现在应该非常熟悉的哈希。)
在大多数情况下,当您给 Git 一个名称时,Git 会立即将其转换为底层哈希 ID。哈希 ID 才是真正重要的:提供这些名称主要是为了让我们这些普通人能够处理作为哈希 ID 的 真实 名称。哈希 ID 永远不会改变:它们总是唯一地标识特定内容——例如,一个特定的提交。提交及其哈希 ID 是永久的,而一个或多个名称可以随意创建或销毁。2
当名称标识commit时,我们可以直接使用名称来查找commit:refs/heads/fix-async-stdout-order
,例如标识commit c31a55
。但是提交也允许我们找到他们的直接 parent 提交:从 c31a55
我们可以向后工作到它的父级,并且从那个父级我们可以向后工作另一个步骤到另一个提交等等,一直回到存储库中时间的开始。所以像这样的名称不仅可以找到它存储哈希 ID 的那个提交,还可以找到其链中所有较早的提交。
当名称是 分支 名称时——就像这个一样——Git 也允许我们将它专门用于 git checkout
。 git checkout
命令将另一个特殊名称 HEAD
附加到分支名称。 Git 现在认为我们是 "on" 分支,因此如果我们进行 new 提交,Git 将 自动更改存储在该分支名称下的哈希 ID.
也就是之后:
git checkout fix-async-stdout-order
如果我们做一些工作然后进行 new 提交,名称 fix-async-stdout-order
——实际上是 refs/heads/fix-async-stdout-order
,我们只是缩短了它出于显示目的——将停止指向提交 c31a55
并开始指向我们的新提交。我们的新提交将以 c31a55
作为其父项。
属性 能够获得 "on" 分支,仅允许 branch 名称。 Git 有很多名称:分支名称、标记名称、远程跟踪名称等等。都是引用,但只有refs/heads/
开头的引用才是分支名
引用 refs/tags/v1.2
(如果存在)是名为 v1.2
.
的 标签
引用 refs/remotes/origin/master
,如果存在,则为 远程跟踪名称 origin/master
.
这些前缀中的每一个——refs/heads/
、refs/tags/
和 refs/remotes/
——代表一个 namespace。 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 垃圾收集过程的保护。因此,名称不仅允许我们在链中找到 last 提交,它们还保护该提交 and 所有其前身不被删除作为垃圾。
3过程是可编程的,通过 Git 调用的 refspecs。上面的描述仅适用于您在 运行 git clone
时获得的 default refspecs。如果您编写自己的参考规格,则可以更改此处发生的情况。请参阅 the git fetch
documentation 并注意 remote.origin.fetch
是一个 累积 设置; remote.origin.fetch
的每个实例都提供一个 refspec。
克隆时的默认设置是 Git 创建一个 remote.origin.fetch
设置,将其分支的 所有 复制到您的远程跟踪名称, 或者复制 one 它们的分支到 one 远程跟踪名称,如果你在克隆期间选择 --single-branch
。
有时我登录到一个云实例,拉取一个存储库,然后想尝试一个拉取请求。我现在使用的命令是
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
有何不同? (我在这里缩短了哈希值,这样视觉上更清晰)
GitHub suggests:git fetch origin pull/ID/head:BRANCHNAME
:这样你就可以控制本地分支命名约定,而不是创建(由于 PR 的 GitHub 上的默认 refspec)
但是你有 more advance techniques here:
[alias]
copr = "!f() { git fetch -fu ${2:-origin} refs/pull//head:pr/ &&
git checkout pr/; }; f"
然后:
$ git copr 1234 # gets and switches to pr/1234 from origin
$ git copr 789 upstream # gets and switches to pr/789 from upstream
hub 也因包装 PR 导入而闻名。
每个 Git 存储库都有自己的名称副本。每个名称都映射到一个哈希 ID,例如,在您的示例中:
c31a55 refs/heads/fix-async-stdout-order 615f5a refs/pull/10/head
您建议 refs/heads/fix-async-stdout-order
映射到哈希 ID c31a55
,refs/pull/10/head
映射到哈希 ID 615f5a
。1
names 是 Git 调用 refs 或 references 的东西。 (哈希 ID 是您现在应该非常熟悉的哈希。)
在大多数情况下,当您给 Git 一个名称时,Git 会立即将其转换为底层哈希 ID。哈希 ID 才是真正重要的:提供这些名称主要是为了让我们这些普通人能够处理作为哈希 ID 的 真实 名称。哈希 ID 永远不会改变:它们总是唯一地标识特定内容——例如,一个特定的提交。提交及其哈希 ID 是永久的,而一个或多个名称可以随意创建或销毁。2
当名称标识commit时,我们可以直接使用名称来查找commit:refs/heads/fix-async-stdout-order
,例如标识commit c31a55
。但是提交也允许我们找到他们的直接 parent 提交:从 c31a55
我们可以向后工作到它的父级,并且从那个父级我们可以向后工作另一个步骤到另一个提交等等,一直回到存储库中时间的开始。所以像这样的名称不仅可以找到它存储哈希 ID 的那个提交,还可以找到其链中所有较早的提交。
当名称是 分支 名称时——就像这个一样——Git 也允许我们将它专门用于 git checkout
。 git checkout
命令将另一个特殊名称 HEAD
附加到分支名称。 Git 现在认为我们是 "on" 分支,因此如果我们进行 new 提交,Git 将 自动更改存储在该分支名称下的哈希 ID.
也就是之后:
git checkout fix-async-stdout-order
如果我们做一些工作然后进行 new 提交,名称 fix-async-stdout-order
——实际上是 refs/heads/fix-async-stdout-order
,我们只是缩短了它出于显示目的——将停止指向提交 c31a55
并开始指向我们的新提交。我们的新提交将以 c31a55
作为其父项。
属性 能够获得 "on" 分支,仅允许 branch 名称。 Git 有很多名称:分支名称、标记名称、远程跟踪名称等等。都是引用,但只有refs/heads/
开头的引用才是分支名
引用 refs/tags/v1.2
(如果存在)是名为 v1.2
.
引用 refs/remotes/origin/master
,如果存在,则为 远程跟踪名称 origin/master
.
这些前缀中的每一个——refs/heads/
、refs/tags/
和 refs/remotes/
——代表一个 namespace。 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 垃圾收集过程的保护。因此,名称不仅允许我们在链中找到 last 提交,它们还保护该提交 and 所有其前身不被删除作为垃圾。
3过程是可编程的,通过 Git 调用的 refspecs。上面的描述仅适用于您在 运行 git clone
时获得的 default refspecs。如果您编写自己的参考规格,则可以更改此处发生的情况。请参阅 the git fetch
documentation 并注意 remote.origin.fetch
是一个 累积 设置; remote.origin.fetch
的每个实例都提供一个 refspec。
克隆时的默认设置是 Git 创建一个 remote.origin.fetch
设置,将其分支的 所有 复制到您的远程跟踪名称, 或者复制 one 它们的分支到 one 远程跟踪名称,如果你在克隆期间选择 --single-branch
。