Skip to content

发起 Pull Requests

L edited this page May 2, 2020 · 2 revisions

此页面适用于提交者, 如果不确定自己是否是提交者, 则不是.

Metasploit 由社区通过 GitHub Pull Request 增量构建. 开发环境设置 文档中已经讨论了提交的 Pull Request (或 PRs). 重要的是要意识到 PR 是 GitHub 的功能, 而不是 git, 因此本文档将着眼于如何让 git 环境合理地处理它们.

短篇说明

  • 说明 配置 git 环境.

  • 添加 fetch = +refs/pull/*/head:refs/remotes/upstream/pr/* 到你的 .git/config.

  • 添加你的签名密钥: git config --global user.signingkey

    • 使用 gpg --list-keys 显示你可用的 key. 注意一些操作系统你可能需要替换 gpggpg2. 示例输出如下:

      pub   rsa4096 2020-04-07 [SC]
        3198961E148FF5E527E31A5FD35E05C0F2B81E83
      uid           [ultimate] Grant Willcox <[email protected]>
      sub   rsa4096 2020-04-07 [E]
      
    • Set the GPG key as your signing key. To set the key shown above as the signing key for all repositories, one would execute:

    • 设置 GPG Key 用于签名. 设置上面显示的 GPG Key 为所有存储库的签名密钥, 执行:

      git config --global user.signingkey 3198961E148FF5E527E31A5FD35E05C0F2B81E83
      
  • 合并请求合并代码时, 总是 merge -S --no-ff --edit, 并写上有意义的 50/72 commit 信息将引用原始 PR 为 "#1234" (而不是 RP1234, PR#1234, 1234). 以下面为例:

    Land #1234, a whizbang bug fix
    
    Adds a whiz to the existing bang. It appears that without this,
    bad things can occasionally happen. Thanks @mcfakepants!
    
    Fixes #1024, also see #999.
    
    • -S 参数表示你将使用 PGP/GPG Key 对合并进行签名, 这很好的确保是你本人.
    • --no-ff 参数表示你无论如何都要创建合并. 这样可以确保所有更改都有关联的提交
    • --edit 参数将进入默认的文本编辑器 (通常为 vim), 并允许您编辑提交消息, 使其符合 Metasploit 标准, 而不使用 git 预先生成的提交消息.
  • 请注意,--no-ff 参数应用于返回贡献者分支的 PR 以及落在 Metasploit master 分支中的 PR.

  • If you're making changes (often the case), merge to a landing branch, then merge that branch to upstream/master with the -S --no-ff --edit options.

  • 如果要进行更改 (通常是这种情况), 请合并到登陆分支, 然后使用 -S --no-ff --edit 参数将分支合并到 upstream/master 服务器

便利的 Git 别名

查看这个 gist 可以自动化 (大多) 的 pull request 和签名合并提交, 并且同时保持与其它提交者同步.

Fork 和 clone

首先根据 指示 fork 和 clone 这个 rapid7/metasploit-framework 库. 我喜欢将 ssh 和 ~/.ssh/config 别名一起使用, 但是 https 方法也是可以的.

完成此操作后,您将拥有一个名为 "origin" 的远程存储库, 该存储库指向 GitHub 上的 fork 存储库. 即使您拥有 Rapid7 fork 库,您也将在自己的 Metasploit fork 中完成大部分工作. 现在,我们将添加一个 "upstream" 存储库以与 Rapid7 存储库对接.

此外, 我们将在配置文件中添加一行内容, 使得可以查看 Rapid7 库 (打开和关闭) 的所有 pull requests. 注意这可能需要一分钟, 因为会向 fork 引用添加数百兆数据.

因此, 使用你的文本编辑器打开编辑 metasploit-framework/.git/config 文件, 添加远程的 upstream 和 pull request 的引用. 如下:

[remote "upstream"]
  fetch = +refs/heads/*:refs/remotes/upstream/*
  fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
  url = https://github.com/rapid7/metasploit-framework

现在应该类似如下:

[remote "upstream"]
  fetch = +refs/heads/*:refs/remotes/upstream/*
  fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
  url = [email protected]:rapid7/metasploit-framework.git
[remote "origin"]
  fetch = +refs/heads/*:refs/remotes/origin/*
  fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
  url = https://github.com/YOURNAME/metasploit-framework

现在, 你可以通过 git 拉取远程的 PRs. 这个操作需要点时间, 因为有几十兆的 pull request 数据拉取.

$ git fetch --all
Fetching todb-r7
remote: Counting objects: 13, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 7 (delta 6), reused 7 (delta 6)
Unpacking objects: 100% (7/7), done.
From https://github.com/todb-r7/metasploit-framework
 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
Fetching upstream
remote: Counting objects: 91, done.
remote: Compressing objects: 100% (29/29), done.
remote: Total 59 (delta 47), reused 42 (delta 30)
Unpacking objects: 100% (59/59), done.
From https://github.com/rapid7/metasploit-framework
 [... bunches of tags and PRs ...]
 * [new ref]         refs/pull/1701/head -> upstream/pr/1701
 * [new ref]         refs/pull/1702/head -> upstream/pr/1702

你随时可通过 git fetch 获取所有分支最新的 pull request.

PRs 的分支

单独对合并请求合并前测试是好的 PR 管理策略. 例如, 要处理 PR#1217, 我们将:

$ git checkout upstream/pr/1217
Note: checking out 'upstream/pr/1217'.

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 9e499e5... Make BindTCP test more robust
((no branch)) todb@mazikeen:~/git/rapid7/metasploit-framework
```
```
$ git checkout -b landing-1217

现在, 我们与原始拉取请求相同的本地分支上, 并且可以从那继续. 我们可以进行修改, 不影响 master 分支, 并且可将修改发送到贡献者的分支, 我们可以合并它 (如果你有 Rapid7 的提交者权利, 你可以直接将分支合并到 upstream 中)

在 RP#1217 中, 我想将一些修改返回给贡献者.

强调: 如果贡献者的 PR 所基于的代码库严重过时(例如从旧的 master 分支出来的), 则不应如上所述单独测试其 PR. 而是应该创建一个与最新代码相同的测试分支, 将贡献者的 PR 合并到该测试分支中, 然后开始测试.

这是 #6954 的示例(您的工作流程可能有所不同):

$ git checkout upstream/master 
Note: checking out 'upstream/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 afbeb2b... Land #7023, fixes for swagger exploit
$ git merge --no-ff --no-edit upstream/pr/6954
Merge made by the 'recursive' strategy.
 modules/exploits/windows/local/payload_inject.rb | 5 +++++
 1 file changed, 5 insertions(+)
[*] Running msftidy.rb in .git/hooks/post-merge mode
--- Checking new and changed module syntax with tools/dev/msftidy.rb ---
modules/exploits/windows/local/payload_inject.rb - msftidy check passed
------------------------------------------------------------------------

这样可以确保使用最新的代码库而不是过时的代码库对贡献者的 PR 进行测试. 如果您不这样做,那么当您获得 PR 时, 可能会破坏 Metasploit.

请注意,上面的示例将使您处于分离的HEAD状态。 如果您只想测试有问题的模块,这很好,但是,如果要进行任何更改,请不要忘记创建一个新分支。 对于上面的示例,可以通过运行以下命令来完成

git checkout -b land-6594

在一个远程 fork 库中获取分支到自己的 fork 库

按照上述步骤设置 .git/config 后, 就可以成功运行 git fetch --all, 需要两步在一个远程 fork 库中获取分支到自己的 fork 库.

您需要将他 fork 库添加一次作为远程对象: git remote add OTHER_USER git://github.com/OTHER_USER/metasploit-framework.git. 然后可以从他那获取最新的数据: git fetch OTHER_USER. 现在, 你可以像往常一样切换到 OTHER_USER 的分支, 如 git checkout bug/foo.

进行修改

$ gvim .gitignore
[... make some changes and some commits ...]
(landing-1217) todb@mazikeen:~/git/rapid7/metasploit-framework
$ git checkout -b pr1217-fix-gitignore-conflict
Switched to a new branch 'pr1217-fix-gitignore-conflict'
(pr1217-fix-gitignore-conflict) todb@mazikeen:~/git/rapid7/metasploit-framework
$ git push origin pr1271-fix-gitignore-conflict
(pr1217-fix-gitignore-conflict) todb@mazikeen:~/git/rapid7/metasploit-framework
$ git pr-url schierlm javapayload-maven
Created new window in existing browser session.

This sequence does a few things after editing .gitconfig. It creates another copy of landing-1217 (which is itself a copy of upstream/pr/1217)). Next, I push those changes to my branch (todb-r7, aka "origin"). Finally, I have a mighty .gitconfig alias here to open a browser window to send a pull request to the original contributor's branch (you will want to edit yours to reflect your real GitHub username, of course). 编辑 .gitconfig 之后, 会执行一些操作. 它会创建 landing-1217 的一个副本 (它本身是 upstream/pr/1217 的副本). 接下来, 将这些更改推送到我的分支 (todb-r7,即 "origin" ). 最后, 我这里有一个强大的 .gitconfig 别名, 用浏览器访问, 向原贡献者的分支发送 pull request (当然, 您将需要对其进行编辑以反映您的真实 GitHub 用户名).

pr-url = !"echo https://github.com/YOURNAME/metasploit-framework/pull/new/HISNAME:HISBRANCH...YOURBRANCH"

填补空白 (由 GitHub 的原始 PR 信息提供) 使我得到:

https://github.com/todb-r7/metasploit-framework/pull/new/schierlm:javapayload-maven...pr1217-fix-gitignore-conflict

我在浏览器中将其打开, 最后得到 https://github.com/schierlm/metasploit-framework/pull/1 . 一旦 @schierlm 将它放到他的分支上 (再次使用 git merge --no-ff 和一个简短的信息合并提交消息), 我 (或任何人) 要做的就是 git fetch 以反映更改. 在 upstream/pr/1217 上继续整合 PR.

贡献者之间的合作

注意重要部分: 您不需要 Rapid7 的提交权限即可创建 pull request 分支. 如果 Alice 知道 Juan 指出 Bob 的请求的解决方案, 那么 Alice 通过遵循上述过程来提供该解决方案是 很容易 的. git blame 仍然可以正常工作, 提交历史都将是准确的, 在 pull request 中每个人都将收到有关 Alice 的更改操作通知, 而 Juan 不必等 Bob 弄清楚如何使用 send_request_cgi() 或任何问题. 最难的部分是记住如何构造对 Bob 的 pull request -- 幸运的是此 .git/config 别名 使该部分变得非常完美.

提交到 upstream

返回到 RP#1217. 事实证明, 我的修改足以完成最初的工作. 因此其他人 (@jlee-r7) 可以执行以下操作:

$ git fetch upstream
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 7 (delta 5), reused 7 (delta 5)
Unpacking objects: 100% (7/7), done.
From https://github.com/rapid7/metasploit-framework
   9e499e5..263e967  refs/pull/1651/head -> upstream/pr/1651

一切看起来都很不错,因此他可以使用以下命令将其提交到 Rapid7 库中:

$ git checkout -b upstream-master --track upstream/master
$ git merge -S --no-ff --edit landing-1217
$ git push upstream upstream-master:master

或者, 他已经有 upstream-master 分支:

$ git checkout upstream-master
$ git rebase upstream/master
$ git merge -S --no-ff --edit landing-1217
$ git push upstream upstream-master:master

如果我们在 $HOME/.gitconfig 正确编辑了编辑器则 --edit 参数是可选的. 这里的重点是我们总是想要合并提交, 而不希望使用 (通常没用的) 默认合并提交消息. 对 #1217 提交信息更改为:

Land #1217, java payload build system refactor

请注意, 您应该 在登陆之前 rebase, 否则您的合并提交将在 rebase 中丢失.

最后, -S 参数表示我们将使用 GPG 密钥对合并进行签名. 这是证明实际合并提交是本人的好办法. 有关合并签名的更多信息, 请参考 Git 恐怖事件: 带签名提交的存储库完整性

要设置你自己的签名, 你的 .gitconfig (或 metasploit-framework/.git/config) 文件应该会有下面的内容:

[user]
name = Your Name
email = [email protected]
signingkey = DEADBEEF # Must match exactly with your key for "Your Name <[email protected]>"
[alias]
c = commit -S --edit
m = merge -S --no-ff --edit

拥有 rapid7/metasploit-framework 提交权的人, 密钥列表

合并后

合并 pull request 后, 应以注释形式将发行说明添加到 pull request 中. 这些发行说明将在创建新版本时自动提取并用作文档记录在 metasploit 发布记录.

发行说明示例:

如果合并 pull request 后没有发布说明, 必须添加上 rn-no-release-notes 标签.

交叉链接 PR、 Bug 和提交

TODO: Update in this new post-Redmine, GitHub issues world

合并冲突

下面的操作好处是, 可立即测试合并冲突, 依序如下操作:

git checkout upstream/pr/1234
git checkout -b landing-1234
git checkout master
git checkout -b master-temp
git merge landing-1234 master-temp

如果可行, 那很好, 您知道您现在没有任何合并冲突.

问题与更正

Metasploit Slack 上的 #contributors 或发送到 [email protected] 邮箱.

Clone this wiki locally