ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 5.2 向一个项目贡献 **影响因素** 影响描述项目贡献有许多因素: * 活跃贡献者数量 * 项目所使用的工作流程 * 提交权限 ### 5.2.1 提交准则 有一个好的创建提交的准则并坚持使用会让与 Git 工作和其他人协作更容易。 Git 项目提供了一个文档,其中列举了关于创建提交到提交补丁的若干好的提示(可以在 Git 源代码中的 `Documentation/SubmittingPatches` 文件中阅读)。 **空白错误** 行尾的空格、Tab制表符,行首空格后跟 Tab 制表符的行为。 检查方法为在提交前执行 `git diff --check` 。 **独立变更集** 尝试让每一个提交成为一个逻辑上的独立变更集,并且为每一个提交附带一个有用的信息。除了平时提交时注意,还可以通过重写历史,让工作被发送给其他人前生成一个干净易懂的历史。 **提交信息** 一般情况下,信息应当小于 50 个字符(25个汉字)的单行开始且简要地描述变更,接着是一个空白行,在接着更详细的解释。 ### 5.2.2 私有小型团队 假设团队中有两名开发者 John 和 Jessica。 John 克隆了仓库,做了改动,然后本地提交: ``` $ git clone john@githost:simplegit.git ... $ git commit -am"738ee" ``` 同时 Jessica 也做了相同的操作: ``` $ git clone jessica@githost:simplegit.git ... $ git commit -am"fbff5" ``` 然后 Jessica 先将修改提交到远程库上: ``` $ git push origin master ``` 接着 John 也尝试推送他的修改,然而操作被禁止,因为 Jessica 已经提交了她的修改,John 必须抓取 Jessica 的改动并合并它: ``` $ git fetch origin ``` 此时 John 的本地库为: ![](https://img.kancloud.cn/3f/88/3f8854cfde0d96284c4814b546a7f301_800x484.png) John 有一个引用指向 Jessica 推送上去的改动,但是他必须将它们合并入自己的工作中之后才能被允许推送: ``` $ git merge origin/master ``` 合并后 John 的本地库为: ![](https://img.kancloud.cn/b0/33/b033f62ac0cdeffa3d65bde963cce868_800x358.png) 现在,John 可以测试代码,确保它依然正常工作,然后他可以把合并的新工作推送到服务器上: ``` $ git push origin master ``` 最终,John 的提交历史看起来像这样: ![](https://img.kancloud.cn/ef/3b/ef3b81465901293ff885382be9d5d367_800x286.png) 而在此期间,Jessica 新建了一个分支 `issue54`,并在该分支上做了多次提交: ![](https://img.kancloud.cn/d8/53/d853d41b6c2351f27dbbd2dfebc32f7a_800x189.png) Jessica 为了同步 John 的工作,拉取了远程库: ``` $ git fetch origin ``` 现在 Jessica 的本地库为: ![](https://img.kancloud.cn/dc/dd/dcdd8b42c2f53b2fe0354d725a5b95c6_800x251.png) Jessica 认为她的特性分支已经准备好了,但是她想要知道必须合并什么进入她的工作才能推送。 她运行`git log`来找出: ``` $ git log --no-merges issue54..origin/master ``` `issue54..origin/master`语法是一个日志过滤器,要求 Git 只显示所有在后面分支不在前面分支的提交的列表。 然后 jessica 将 `issue54` 分支合并到 `master` 分支上: ``` $ git checkout master $ git merge issue54 ``` 接着将远程分支合并进 `master` : ``` $ git merge origin/master ``` 此时 Jessica 的本地库: ![](https://img.kancloud.cn/30/ca/30ca22af32a87281a1a1cb7c827609cb_800x215.png) 最后将工作上传: ``` $ git push origin master ``` ![](https://img.kancloud.cn/7b/6d/7b6d005214a1ec9839afefc03aba7e19_800x215.png) ### 5.2.3 私有管理团队 现在假设团队的贡献者有 John、Jessica 和 Josie,其中 John 与 Jessica 在一个特性上工作,同时 Jessica 与 Josie 在第二个特性上工作。 首先 Jessica 已经克隆了仓库,并且在 `featureA` 上工作: ``` $ git checkout -b featureA $ git commit -am "33009" ``` 然后她将工作提交到服务器上,由于 Jessica 没有 `master` 分支的推送权限,所以将其推送到另一个分支: ``` $ git push -u origin featureA ``` 推送结束后,Jessica 向 John 发邮件告诉他,在等待结果时,Jessica 决定在 `featureB` 上工作。 ``` $ git fetch origin $ git checkout -b featureB origin/master ... $ git commit -am "85127" ``` 此时 Jessica 的仓库为: ![](https://img.kancloud.cn/13/31/13315134401820ec197bbc3b4cfd2293_800x356.png) 当她要推送修改时,收到 Josie 的邮件指明一些工作已经被推送到服务器上的 `featureBee` 上,于是她拉去这些改动并合并到自己的分支上: ``` $ git fetch origin $ git merge origin/featureBee ``` 合并后,Jessica 需要将本地库的分支上传: ``` $ git push -u origin featureB:featureBee ``` 紧接着,John 发来邮件说他已经推送了一些改动到 `featureA` 分支,于是 Jessica 运行 `git fetch` 来拉去改动,并且通过 `git log` 来查看变化: ``` $ git fetch origin $ git log featureA..origin/featureA ``` 并合并到自己的 `featureA` 分支上: ``` $ git checkout featureA $ git merge origin/featureA ``` 现在,Jessica 想要轻微调整一些东西,于是她做出修改并推送回服务器: ``` $ git commit -m"774b3" ``` 此时,Jessica 的提交历史为: ![](https://img.kancloud.cn/c6/2a/c62adc6c142555a0d78edebe34e3a4c4_800x451.png) 最后,分支 `featureA` 和 `featureB` 被统一合并到 `master` 分支上: ![](https://img.kancloud.cn/a7/34/a734a12a0a79a2bf61c0f769030058be_800x376.png) 管理团队工作流程的基本顺序: ![](https://img.kancloud.cn/47/3c/473c46f30a8113748068473e8b5db121_718x800.png) ### 5.2.4 派生公开项目 首先克隆主仓库: ``` $ git clone [url] ``` 创建自己的特性分支,并在该分支上工作: ``` $ git checkout -b featureA ... $ git commit ``` 在自己的 Github 上克隆一份作为可写的项目派生,并添加到本地库的远程库中,再将工作推送上去: ``` $ git remote add myfork [url] $ git push -u myfork featureA ``` 当工作已经被推送上去后,需要通知维护者,该操作被称为拉去请求(Pull Request) ``` $ git pull-request origin/master myfork ``` 如果你不是一个公开项目的维护者,一般会设置一个跟踪分支: ``` $ git checkout -b featureB origin/master ``` ### 5.2.5 通过邮件的公开项目 历史悠久的、大型的项目会通过一个开发者的邮件列表接受补丁。 通过 `format-patch`命令打印出它创建的补丁文件名字: ``` $ git format-patch -M origin/master ``` 需要在`~/.gitconfig`文件中设置 imap 区块。 可以通过一系列的`git config`命令来分别设置每一个值,或者手动添加它们: ``` [imap] folder = "[Gmail]/Drafts" host = imaps://imap.gmail.com user = user@gmail.com pass = p4ssw0rd port = 993 sslverify = false ``` 如果 IMAP 服务器不使用 SSL,最后两行可能没有必要,host 的值会是`imap://`而不是`imaps://`。 通过 `imap-send` 可以将补丁放到特定 IMAP 服务器的 Drafts 文件夹中: ``` $ cat *.patch |git imap-send ``` 也可以通过一个 SMTP 服务器发送补丁,同样需要在配置里面声明: ``` [sendemail] smtpencryption = tls smtpserver = smtp.gmail.com smtpuser = user@gmail.com smtpserverport = 587 ``` 最后,使用`git send-email`发送补丁: ``` $ git send-email *.patch ```