首页 > 解决方案 > 有没有办法从 GitHub 上已删除分支的 PR 中获取代码?

问题描述

在 GitHub 上,我通常克隆某人的 fork 或将其添加为远程以下载他们的更改。但是,如果分支/分叉被完全删除,这不是一个选项。

然而,如果您在 PR 中单击“文件已更改”选项卡,您仍然可以在 PR 中查看更改的文件,即使删除了 fork/branch 并关闭了 PR。

有没有办法在我的系统上本地获取具有这些更改的分支?一个想法是通过从网站上复制粘贴更改来手动重新创建所有内容,但这种方法似乎不是最理想的。

标签: gitgithubpull-request

解决方案


是的,这相对容易:

git fetch <remote-or-url> refs/pull/1234/head:refs/heads/pr1234

例如,会将他们的(GitHub 的)pull-request-#1234 提交转入您的pr1234分支。

背景

它的工作方式很简单:

  1. Git 中的所有名称1都是refsreferences。也就是说,分支名称master真的只是refs/heads/master;标签名称v1.2真的只是refs/tags/v1.2; 你的远程跟踪origin/master真的只是refs/remotes/origin/master。作为分支名称的名称以refs/heads/. Git 通常会去掉它的任何名称的前导部分,假设您会知道这master是一个分支、v1.2一个标签和origin/master一个远程跟踪名称。

  2. 当你运行 时git fetch,你的 Git 通过他们的 Git 显示给你的 Git 的 name-and-hash-ID 对来获取他们的提交(和其他对象)。然后它会复制所需的任何提交(和其他对象),以便您的 Git 可以更新您的远程跟踪名称和/或将条目写入您的 Git.git/FETCH_HEAD文件等等。最后,它做了几件事:

    • 按照指示更新您自己的裁判;和
    • .git/FETCH_HEAD


    FETCH_HEAD文件主要用于git pull代码;现在它git pull已经被用 C 重写了,有点像历史文物。

refs 的好处是,被划分为命名空间,你或任何人都可以发明你自己的。refs/heads/andrefs/tags/refs/remotes/空格被占用,andrefs/bisect/refs/replace/其他一些空格也是如此,但是 GitHub 能够使用refs/pull/Git 本身没有的 来存储他们的名字。

在这个refs/pull/空间中,GitHub 插入 PR 或问题编号(这些编号是每个存储库的,否则对于存储库是全局的),然后/head是提示提交和/merge执行无人值守的自动测试的结果git merge。如果自动合并失败,GitHub 根本不创建mergeref。因此,如果存在编号为 1234 的 PR,则refs/pull/1234/head存在;如果该 PR 成功测试合并,refs/pull/1234/merge则也存在,如果不存在,则不存在。

请注意,从他们的(GitHub 的)分支名称到您的远程跟踪名称的转换由您自己的remote.origin.fetch配置行控制,默认为:

+refs/heads/*:refs/remotes/origin/*

这是一个refspec:一对 refs,用冒号分隔,并且可选地以加号作为前缀+(总是用于这种特殊情况)。这匹配他们所有的分支名称,因为左侧或模式匹配分支名称。它会导致您的 Git 用您的远程跟踪名称替换它们的分支名称,因为右侧或目标模式替换refs/heads/refs/remotes/origin/(保持所有匹配的内容*不变)。

这意味着您可以添加:

+refs/pull/*/head:refs/heads/pr*

到您的remote.origin.fetchrefspecs,在您的, 中.git/config,这git fetch将自动并且几乎总是2创建或更新您的分支。但是,它可能会破坏您自己创建的任何您自己的个人分支,因此请注意,如果您这样做,您必须避免命名分支-something(至少是数字的东西,但要小心修剪;见脚注 2) .prnumberprnumberpr


1这里的例外是HEADMERGE_HEADCHERRY_PICK_HEAD等。虽然FETCH_HEAD有时像参考一样工作,但该FETCH_HEAD文件特别特别,因为它可以包含多行和一些额外的注释;其他仅包含(并且完全)一个哈希 ID 或一个符号引用。

2 “总是”太强了,甚至我那略显狡猾的措辞几乎总是也可能如此:任何时候你git fetch使用一些 refspec 参数运行,这将覆盖这个默认值。remote.origin.fetch仅当您没有覆盖它们时才使用您配置的设置。记住它是如何与fetch.pruneor交互的git fetch -p*目标中的现在意味着 Git 将自动删除不是由 fetch 操作写入的匹配引用。

编写pr*而不是,例如,的能力pr/*取决于您的 Git 年份。在某些较旧版本的 Git 中,refspecs 中的类 glob*模式只能以“全名组件”的方式使用,例如,refs/heads/*:refs/remotes/origin/*在所有 Git 版本中总是可以的,无论多么古老,但有时refs/heads/a*:refs/remotes/origin/a*不是。


推荐阅读