5.2 向一个项目贡献
向一个项目贡献
描述如何向一个项目贡献的主要困难在于完成贡献有很多不同的方式。因为 Git 非常灵活,人们可以通过不同的方式来一起工作,所以描述应该如何贡献并不是非常准确 - 每一个项目都有一点儿不同。影响因素包括活跃贡献者的数量、选择的工作流程、提交权限与可能包含的外部贡献方法。
第一个影响因素是活跃贡献者的数量 - 积极地向这个项目贡献代码的用户数量以及他们的贡献频率。在许多情况下,你可能会有两三个开发者一天提交几次,对于不活跃的项目可能更少。对于大一些的公司或项目,开发者的数量可能会是上千,每天都有成百上千次提交。这很重要,因为随着开发者越来越多,在确保你的代码能干净地应用或轻松地合并时会遇到更多问题。提交的改动可能表现为过时的,也可能在你正在做改动或者等待改动被批准应用时被合并入的工作严重损坏。如何保证代码始终是最新的,并且提交始终是有效的?
下一个影响因素是项目使用的工作流程。它是中心化的吗,即每一个开发者都对主线代码有相同的写入权限?项目是否有一个检查所有补丁的维护者或整合者?是否所有的补丁是同行评审后批准的?你是否参与了那个过程?是否存在副官系统,你必须先将你的工作提交到上面?
下一个问题是提交权限。是否有项目的写权限会使向项目贡献所需的流程有极大的不同。如果没有写权限,项目会选择何种方式接受贡献的工作?是否甚至有一个如何贡献的规范?你一次贡献多少工作?你多久贡献一次?
所有这些问题都会影响实际如何向一个项目贡献,以及对你来说哪些工作流程更适合或者可用。我们将会由浅入深,通过一系列用例来讲述其中的每一个方面;从这些例子应该能够建立实际中你需要的特定工作流程。
提交准则
在我们开始查看特定的用例前,这里有一个关于提交信息的快速说明。有一个好的创建提交的准则并且坚持使用会让与 Git 工作和与其他人协作更容易。Git 项目提供了一个文档,其中列举了关于创建提交到提交补丁的若干好的提示 - 可以在 Git 源代码中的 Documentation/SubmittingPatches
文件中阅读它。
首先,你不会想要把空白错误(根据 git help diff 的描述,结合下面给出的图片,空白错误是指行尾的空格、Tab 制表符,和行首空格后跟 Tab 制表符的行为)提交上去。Git 提供了一个简单的方式来检查这点 - 在提交前,运行 git diff --check
,它将会找到可能的空白错误并将它们为你列出来。
“提交区间” 中详细介绍这个语法。
目前,我们可以从输出中看到有一个 John 生成的但是 Jessica 还没有合并入的提交。如果她合并 origin/master
,也就是说将会修改她的本地工作的那个单个提交。
现在,Jessica 可以合并她的特性工作到她的 master 分支,合并 John 的工作(origin/master
)进入她的 master
分支,然后再次推送回服务器。首先,为了整合所有这些工作她切换回她的 master 分支。
$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
她既可以先合并 origin/master
也可以先合并 issue54
- 它们都是上游,所以顺序并没有关系。不论她选择的顺序是什么最终的结果快照是完全一样的;只是历史会有一点轻微的区别。她选择先合并入 issue54
:
$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
README | 1 +
lib/simplegit.rb | 6 +++++-
2 files changed, 6 insertions(+), 1 deletions(-)
没有发生问题;如你所见它是一次简单的快进。现在 Jessica 合并入 John 的工作(origin/master
):
$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
每一个文件都干净地合并了,Jessica 的历史看起来像这样:
Figure 5-11. 推送所有的改动回服务器后 Jessica 的历史
这是一个最简单的工作流程。你通常在一个特性分支工作一会儿,当它准备好整合时合并回你的 master 分支。当想要共享工作时,将其合并回你自己的 master 分支,如果有改动的话然后抓取并合并 origin/master
,最终推送到服务器上的 master
分支。通常顺序像这样:
Figure 5-13. Jessica 的初始提交历史
她准备好推送工作了,但是一封来自 Josie 的邮件告知一些初始工作已经被推送到服务器上的 featureBee
上了。Jessica 在能推送到服务器前首先需要将那些改动与她自己的合并。然后她可以通过 git fetch
抓取 Josie 的改动:
$ git fetch origin
...
From jessica@githost:simplegit
* [new branch] featureBee -> origin/featureBee
Jessica 现在可以通过 git merge
将其合并到她做的工作中:
$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
有点儿问题 - 她需要将在 featureB
分支上合并的工作推送到服务器上的 featureBee
分支。她可以通过指定本地分支加上冒号(:)加上远程分支给 git push
命令来这样做:
$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
fba9af8..cd685d1 featureB -> featureBee
这称作一个 引用规格。查看 “引用规格” 了解关于 Git 引用规格与通过它们可以做的不同的事情的详细讨论。也要注意 -u
标记;这是 --set-upstream
的简写,该标记会为之后轻松地推送与拉取配置分支。
紧接着,John 发邮件给 Jessica 说他已经推送了一些改动到 featureA
分支并要求她去验证它们。她运行一个 git fetch
来拉取下那些改动:
$ git fetch origin
...
From jessica@githost:simplegit
3300904..aad881d featureA -> origin/featureA
然后,通过 git log
她可以看到哪些发生了改变:
$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date: Fri May 29 19:57:33 2009 -0700
changed log output to 30 from 25
最终,她合并 John 的工作到她自己的 featureA
分支:
$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
lib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
Jessica 想要轻微调整一些东西,所以她再次提交然后将其推送回服务器:
$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
3300904..774b3ed featureA -> featureA
Jessica 的提交历史现在看起来像这样:
Figure 5-15. 合并了 Jessica 的两个特性分支后她的历史
许多团队切换到 Git 是因为这一允许多个团队并行工作、并在之后合并不同工作的能力。团队中更小一些的子小组可以通过远程分支协作而不必影响或妨碍整个团队的能力是 Git 的一个巨大优势。在这儿看到的工作流程顺序类似这样:
Figure 5-18
Figure 5-19. featureBv2
工作之后的提交历史
通过邮件的公开项目
许多项目建立了接受补丁的流程 - 需要检查每一个项目的特定规则,因为它们之间有区别。因为有几个历史悠久的、大型的项目会通过一个开发者的邮件列表接受补丁,现在我们将会通过一个例子来演示。
工作流程与之前的用例是类似的 - 你为工作的每一个补丁序列创建特性分支。区别是如何提交它们到项目中。生成每一个提交序列的电子邮件版本然后邮寄它们到开发者邮件列表,而不是派生项目然后推送到你自己的可写版本。
$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit
现在有两个提交要发送到邮件列表。使用 git format-patch
来生成可以邮寄到列表的 mbox 格式的文件 - 它将每一个提交转换为一封电子邮件,提交信息的第一行作为主题,剩余信息与提交引入的补丁作为正文。它有一个好处是是使用 format-patch
生成的一封电子邮件应用的提交正确地保留了所有的提交信息。
$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
format-patch
命令打印出它创建的补丁文件名字。-M
开关告诉 Git 查找重命名。文件最后看起来像这样:
$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function
Limit log functionality to the first 20
---
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
end
def log(treeish = 'master')
- command("git log #{treeish}")
+ command("git log -n 20 #{treeish}")
end
def ls_tree(treeish = 'master')
--
2.1.0
也可以编辑这些补丁文件为邮件列表添加更多不想要在提交信息中显示出来的信息。如果在 ---
行与补丁开头(diff --git
行)之间添加文本,那么开发者就可以阅读它;但是应用补丁时会排除它。
为了将其邮寄到邮件列表,你既可以将文件粘贴进电子邮件客户端,也可以通过命令行程序发送它。粘贴文本经常会发生格式化问题,特别是那些不会合适地保留换行符与其他空白的 “更聪明的” 客户端。幸运的是,Git 提供了一个工具帮助你通过 IMAP 发送正确格式化的补丁,这可能对你更容易些。我们将会演示如何通过 Gmail 发送一个补丁,它正好是我们所知最好的邮件代理;可以在之前提到的 Git 源代码中的 Documentation/SubmittingPatches
文件的最下面了解一系列邮件程序的详细指令。
首先,需要在 ~/.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://
。当那些设置完成后,可以使用 git imap-send
将补丁序列放在特定 IMAP 服务器的 Drafts 文件夹中:
$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done
在这个时候,你应该能够到 Drafts 文件夹中,修改收件人字段为想要发送补丁的邮件列表,可能需要抄送给维护者或负责那个部分的人,然后发送。
你也可以通过一个 SMTP 服务器发送补丁。同之前一样,你可以通过一系列的 git config
命令来分别设置选项,或者你可以手动地将它们添加到你的 ~/.gitconfig
文件的 sendmail 区块:
[sendemail]
smtpencryption = tls
smtpserver = smtp.gmail.com
smtpuser = user@gmail.com
smtpserverport = 587
当这完成后,你可以使用 git send-email
发送你的补丁:
$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y
然后,对于正在发送的每一个补丁,Git 会吐出这样的一串日志信息:
(mbox) Adding cc: Jessica Smith <jessica@example.com> from
\line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>
Result: OK
总结
这个部分介绍了处理可能会遇到的几个迥然不同类型的 Git 项目的一些常见的工作流程,介绍了帮助管理这个过程的一些新工具。接下来,你会了解到如何在贡献的另一面工作:维护一个 Git 项目。你将会学习如何成为一个仁慈的独裁者或整合管理者。
更多建议: