Git 提取拉取请求:解锁熟练程度

如今,对项目应用修复就像创建克隆一样简单,它会提供项目的完整远程副本供您修改,具体方法是选择您要变更的文件,然后按下编辑并提交修复。

如果您在拉取请求(下文缩写为 PR)的接收端会怎样?使用精美的 Web 用户界面很棒,通常这正是您所需要的。点击按钮进行批准,点击按钮合并,然后就完成了。

但情况并非总是如此!通常需要在本地下载拉取请求 (PR) 中包含的变更,运行一些测试,看看它们在您 IDE 中的样子才能理解所做的事情。

您的同事或贡献者的拉取请求的下载步骤(更明确地说是 fetchcheckout)在概念上很简单,但是如果您知道一些重要的细节和提示,它们就会变得更容易。

我来帮助您更好地理解 git 为您提供的命令行功能,让您能轻松处理来自命令行的拉取请求。

在我们开始之前:用分支名称和状态丰富您的 shell 提示符

我总是感到惊讶,有很多人只有一个裸命令提示符,该提示符没有显示他们所在的 git 分支,或者工作目录中是否有修改/未提交的文件。如果您觉得您就是这样,不妨让我来帮助您,结果肯定会让您大吃一惊!

安装 liquid prompt 这样的提示,它将为您的 git 工作目录的状态提供很好的注释(也支持任何其他 VCS):

(在上面的屏幕截图中,您会看到我的提示提醒我,我在 newbranch 分支上,在跟踪的工作目录文件中添加了 5 行,并且已经删除了 0 行)

每个人都在同一个存储库中工作

如果您和您的团队在同一个存储库上工作,那么签出拉取请求的流程非常简单:只需 fetchcheckout 创建拉取请求的分支即可:

  • 获取在共享存储库上发布的所有分支:

git fetch origin
  • 创建一个本地分支来跟踪您感兴趣的远程分支:

git checkout -b PRJ-1234 origin/PRJ-1234
  • 现在您可以用这个比对合并、测试您的核心了:

git diff main ./run-tests.sh
  • 如果您满意,只需回到 Web 用户界面并提供反馈或直接批准变更即可。

贡献者负责自己的克隆

部分贡献者在不同的克隆中工作时,流程会有变更。在这种情况下,您可以 fetch 提交贡献或功能的远程分支:

  • 先添加贡献者的远程存储库:

git remote add jsmith http://bitbucket.org/jsmith/coolproject.git
  • 先从您的主存储库 origin 收集所有最新更新:

git checkout main git fetch origin git merge main
  • 获取贡献者克隆上发布的所有分支:

git fetch jsmith
  • 创建一个本地分支来跟踪您感兴趣的远程分支:

git checkout -b jsmith-PRJ-1234 jsmith/PRJ-1234
  • 现在您可以用这个比对合并、测试您的核心了:

git diff main ./run-tests.sh

使用拉取请求引用减少工作量

以上方法可行,但有几件事可能会给您带来困扰:

  • 如果您有很多合作者,每个人都有自己的克隆该怎么办?添加他们所有的克隆并单独处理是不切实际的。

  • 如果您连一些克隆都无法访问并且无法查看源分支该怎么办?

解决上述两个问题的办法是使用某些 git 服务器提供的拉取请求引用。我将要展示的程序由某些 git 服务器支持,但会因您使用的服务器而略有不同。在下文中,我将介绍如何在 Stash(现在称为 Bitbucket Data Center)和 Github 上 fetch 所有拉取请求。

别害怕 Refspec

第一个先决条件是熟悉 Refspec。Refspec 很赞,不用害怕。它们是从远程分支到本地引用的简单映射,换句话说,告诉 git“这个远程分支(或这组远程分支)的直接方法应该在本地这个命名空间中映射到这些名称。”

例如,像这样的命令:

git fetch +refs/heads/main:refs/remotes/origin/main

会将您的 origin 远程上的远程分支 main 映射到本地 origin/main,这样您就可以输入:

git checkout origin/main

还要引用那个远程分支。定义中的加号 (+) 表示我们希望 git 更新引用,即使它不是快进。

我们使用它来下载所有拉取请求的方法是映射远程存储库存储 PR HEAD 的方式,并将它们映射到本地命名空间以便于引用。

因此,假设您定义了 origin(或 upstream)远程存储库,以下是要做的事情。

注意:正如几位 Stash(现在称为 Bitbucket Data Center)开发人员所合理指出的那样,我在下面演示的引用被认为是未公开私有的内容,可能随时会更改。

下载所有拉取请求:Stash

  • 克隆存储库。

  • 在本地克隆您的克隆:

git clone git@stash.atlassian.com:durdn/tis.git
  • 上游原始存储库添加为 upstream 存储库。

git remote add upstream git@stash.atlassian.com:tpettersen/tis.git
  • 从 'upstream' 维护者那里获取最新的 HEAD

git fetch upstream
  • 添加 refspec,它将远程拉取请求 head 映射到本地 pr 命名空间。您可以用一个 config 命令来完成:

git config --add remote.origin.fetch '+refs/pull-requests/*/from:refs/remotes/origin/pr/*'
  • 如果您看一下 .git/config,会发现 fetch 条目变成:

[remote "upstream"]
    url = git@stash.atlassian.com:docker/libswarm.git
    fetch = +refs/heads/*:refs/remotes/upstream/*
    fetch = +refs/pull-requests/*/from:refs/remotes/upstream/pr/*
  • 现在您可以轻松 fetch 所有拉取请求分支了:

$ git fetch upstream

remote: Counting objects: 417, done.
remote: Compressing objects: 100% (274/274), done.
remote: Total 417 (delta 226), reused 277 (delta 128)
Receiving objects: 100% (417/417), 105.28 KiB | 0 bytes/s, done.
Resolving deltas: 100% (226/226), done.

From stash.atlassian.com:docker/libswarm
 * [new ref]         refs/pull-requests/10/from-> upstream/pr/10
 [...]
 * [new ref]         refs/pull-requests/100/from -> upstream/pr/100
 * [new ref]         refs/pull-requests/101/from -> upstream/pr/101
 [...]
 * [new ref]         refs/pull-requests/109/from -> upstream/pr/109
 * [new ref]         refs/pull-requests/110/from -> upstream/pr/110
 [...]
  • 现在要切换到特定的拉取请求,您只需:

git checkout pr/102

下载所有拉取请求:Github

如果克隆或上游在 Github 上,则其工作原理与上面完全相同,但 config 命令变更为:

git config --add remote.origin.fetch '+refs/pull//head:refs/remotes/origin/pr/'

还有 .git/config 中的远程存储库将变更为包含额外的 fetch 配置,用于将 PR head 映射到名为 pr 的本地命名空间:

[remote "upstream"] url = git@github.com:docker/libswarm.git fetch = +refs/heads/*:refs/remotes/upstream/* fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*

使用 refs 获取单个拉取请求

如果您不想在 .git/config 中设置 fetch 条目,只想快速得到一个拉取请求,只需一个命令就可以:

  • Stash 中查看单个 PR:

git fetch refs/pull-requests/your-pr-number/from:local-branch-name
  • 在 Github 上查看单个 PR:

git fetch refs/pull/your-pr-number/head:local-branch-name

如果您发现自己经常使用上述方法,您可以通过创建 git 别名来简化流程:

# For Stash
git config alias.spr '!sh -c "git fetch origin pull-requests/${1}/from:pr/${1}" -'

# For Github
git config alias.gpr '!sh -c "git fetch origin pull/${1}/head:pr/${1}" -'

配置好这个别名后,我们可以用一个简单的(谢谢 inuit)来获取拉取请求:

总结

最后,只要您创建几个简单的别名或在 .git/config 中添加正确的 refspec,就可以轻松关注同行或贡献者的工作。

为您推荐

Bitbucket 博客

DevOps 学习路径

了解有关 Git 的更多信息

在此中心查找更多 Git 指南和资源。