描述如何向一個(gè)項(xiàng)目貢獻(xiàn)的主要困難在于完成貢獻(xiàn)有很多不同的方式。因?yàn)?Git 非常靈活,人們可以通過(guò)不同的方式來(lái)一起工作,所以描述應(yīng)該如何貢獻(xiàn)并不是非常準(zhǔn)確 - 每一個(gè)項(xiàng)目都有一點(diǎn)兒不同。影響因素包括活躍貢獻(xiàn)者的數(shù)量、選擇的工作流程、提交權(quán)限與可能包含的外部貢獻(xiàn)方法。
第一個(gè)影響因素是活躍貢獻(xiàn)者的數(shù)量 - 積極地向這個(gè)項(xiàng)目貢獻(xiàn)代碼的用戶(hù)數(shù)量以及他們的貢獻(xiàn)頻率。在許多情況下,你可能會(huì)有兩三個(gè)開(kāi)發(fā)者一天提交幾次,對(duì)于不活躍的項(xiàng)目可能更少。對(duì)于大一些的公司或項(xiàng)目,開(kāi)發(fā)者的數(shù)量可能會(huì)是上千,每天都有成百上千次提交。這很重要,因?yàn)殡S著開(kāi)發(fā)者越來(lái)越多,在確保你的代碼能干凈地應(yīng)用或輕松地合并時(shí)會(huì)遇到更多問(wèn)題。提交的改動(dòng)可能表現(xiàn)為過(guò)時(shí)的,也可能在你正在做改動(dòng)或者等待改動(dòng)被批準(zhǔn)應(yīng)用時(shí)被合并入的工作嚴(yán)重?fù)p壞。如何保證代碼始終是最新的,并且提交始終是有效的?
下一個(gè)影響因素是項(xiàng)目使用的工作流程。它是中心化的嗎,即每一個(gè)開(kāi)發(fā)者都對(duì)主線(xiàn)代碼有相同的寫(xiě)入權(quán)限?項(xiàng)目是否有一個(gè)檢查所有補(bǔ)丁的維護(hù)者或整合者?是否所有的補(bǔ)丁是同行評(píng)審后批準(zhǔn)的?你是否參與了那個(gè)過(guò)程?是否存在副官系統(tǒng),你必須先將你的工作提交到上面?
下一個(gè)問(wèn)題是提交權(quán)限。是否有項(xiàng)目的寫(xiě)權(quán)限會(huì)使向項(xiàng)目貢獻(xiàn)所需的流程有極大的不同。如果沒(méi)有寫(xiě)權(quán)限,項(xiàng)目會(huì)選擇何種方式接受貢獻(xiàn)的工作?是否甚至有一個(gè)如何貢獻(xiàn)的規(guī)范?你一次貢獻(xiàn)多少工作?你多久貢獻(xiàn)一次?
所有這些問(wèn)題都會(huì)影響實(shí)際如何向一個(gè)項(xiàng)目貢獻(xiàn),以及對(duì)你來(lái)說(shuō)哪些工作流程更適合或者可用。我們將會(huì)由淺入深,通過(guò)一系列用例來(lái)講述其中的每一個(gè)方面;從這些例子應(yīng)該能夠建立實(shí)際中你需要的特定工作流程。
在我們開(kāi)始查看特定的用例前,這里有一個(gè)關(guān)于提交信息的快速說(shuō)明。有一個(gè)好的創(chuàng)建提交的準(zhǔn)則并且堅(jiān)持使用會(huì)讓與 Git 工作和與其他人協(xié)作更容易。Git 項(xiàng)目提供了一個(gè)文檔,其中列舉了關(guān)于創(chuàng)建提交到提交補(bǔ)丁的若干好的提示 - 可以在 Git 源代碼中的 Documentation/SubmittingPatches
文件中閱讀它。
首先,你不會(huì)想要把空白錯(cuò)誤(根據(jù) git help diff 的描述,結(jié)合下面給出的圖片,空白錯(cuò)誤是指行尾的空格、Tab 制表符,和行首空格后跟 Tab 制表符的行為)提交上去。Git 提供了一個(gè)簡(jiǎn)單的方式來(lái)檢查這點(diǎn) - 在提交前,運(yùn)行 git diff --check
,它將會(huì)找到可能的空白錯(cuò)誤并將它們?yōu)槟懔谐鰜?lái)。
“提交區(qū)間” 中詳細(xì)介紹這個(gè)語(yǔ)法。
目前,我們可以從輸出中看到有一個(gè) John 生成的但是 Jessica 還沒(méi)有合并入的提交。如果她合并 origin/master
,也就是說(shuō)將會(huì)修改她的本地工作的那個(gè)單個(gè)提交。
現(xiàn)在,Jessica 可以合并她的特性工作到她的 master 分支,合并 John 的工作(origin/master
)進(jìn)入她的 master
分支,然后再次推送回服務(wù)器。首先,為了整合所有這些工作她切換回她的 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
- 它們都是上游,所以順序并沒(méi)有關(guān)系。不論她選擇的順序是什么最終的結(jié)果快照是完全一樣的;只是歷史會(huì)有一點(diǎn)輕微的區(qū)別。她選擇先合并入 issue54
:
$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
README | 1 +
lib/simplegit.rb | 6 +++++-
2 files changed, 6 insertions(+), 1 deletions(-)
沒(méi)有發(fā)生問(wèn)題;如你所見(jiàn)它是一次簡(jiǎn)單的快進(jìn)?,F(xiàn)在 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(-)
每一個(gè)文件都干凈地合并了,Jessica 的歷史看起來(lái)像這樣:
Figure 5-11. 推送所有的改動(dòng)回服務(wù)器后 Jessica 的歷史
這是一個(gè)最簡(jiǎn)單的工作流程。你通常在一個(gè)特性分支工作一會(huì)兒,當(dāng)它準(zhǔn)備好整合時(shí)合并回你的 master 分支。當(dāng)想要共享工作時(shí),將其合并回你自己的 master 分支,如果有改動(dòng)的話(huà)然后抓取并合并 origin/master
,最終推送到服務(wù)器上的 master
分支。通常順序像這樣:
Figure 5-13. Jessica 的初始提交歷史
她準(zhǔn)備好推送工作了,但是一封來(lái)自 Josie 的郵件告知一些初始工作已經(jīng)被推送到服務(wù)器上的 featureBee
上了。Jessica 在能推送到服務(wù)器前首先需要將那些改動(dòng)與她自己的合并。然后她可以通過(guò) git fetch
抓取 Josie 的改動(dòng):
$ git fetch origin
...
From jessica@githost:simplegit
* [new branch] featureBee -> origin/featureBee
Jessica 現(xiàn)在可以通過(guò) 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(-)
有點(diǎn)兒?jiǎn)栴} - 她需要將在 featureB
分支上合并的工作推送到服務(wù)器上的 featureBee
分支。她可以通過(guò)指定本地分支加上冒號(hào)(:)加上遠(yuǎn)程分支給 git push
命令來(lái)這樣做:
$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
fba9af8..cd685d1 featureB -> featureBee
這稱(chēng)作一個(gè) 引用規(guī)格。查看 “引用規(guī)格” 了解關(guān)于 Git 引用規(guī)格與通過(guò)它們可以做的不同的事情的詳細(xì)討論。也要注意 -u
標(biāo)記;這是 --set-upstream
的簡(jiǎn)寫(xiě),該標(biāo)記會(huì)為之后輕松地推送與拉取配置分支。
緊接著,John 發(fā)郵件給 Jessica 說(shuō)他已經(jīng)推送了一些改動(dòng)到 featureA
分支并要求她去驗(yàn)證它們。她運(yùn)行一個(gè) git fetch
來(lái)拉取下那些改動(dòng):
$ git fetch origin
...
From jessica@githost:simplegit
3300904..aad881d featureA -> origin/featureA
然后,通過(guò) git log
她可以看到哪些發(fā)生了改變:
$ 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 想要輕微調(diào)整一些東西,所以她再次提交然后將其推送回服務(wù)器:
$ 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 的提交歷史現(xiàn)在看起來(lái)像這樣:
Figure 5-15. 合并了 Jessica 的兩個(gè)特性分支后她的歷史
許多團(tuán)隊(duì)切換到 Git 是因?yàn)檫@一允許多個(gè)團(tuán)隊(duì)并行工作、并在之后合并不同工作的能力。團(tuán)隊(duì)中更小一些的子小組可以通過(guò)遠(yuǎn)程分支協(xié)作而不必影響或妨礙整個(gè)團(tuán)隊(duì)的能力是 Git 的一個(gè)巨大優(yōu)勢(shì)。在這兒看到的工作流程順序類(lèi)似這樣:
Figure?5-18
Figure 5-19. featureBv2
工作之后的提交歷史
許多項(xiàng)目建立了接受補(bǔ)丁的流程 - 需要檢查每一個(gè)項(xiàng)目的特定規(guī)則,因?yàn)樗鼈冎g有區(qū)別。因?yàn)橛袔讉€(gè)歷史悠久的、大型的項(xiàng)目會(huì)通過(guò)一個(gè)開(kāi)發(fā)者的郵件列表接受補(bǔ)丁,現(xiàn)在我們將會(huì)通過(guò)一個(gè)例子來(lái)演示。
工作流程與之前的用例是類(lèi)似的 - 你為工作的每一個(gè)補(bǔ)丁序列創(chuàng)建特性分支。區(qū)別是如何提交它們到項(xiàng)目中。生成每一個(gè)提交序列的電子郵件版本然后郵寄它們到開(kāi)發(fā)者郵件列表,而不是派生項(xiàng)目然后推送到你自己的可寫(xiě)版本。
$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit
現(xiàn)在有兩個(gè)提交要發(fā)送到郵件列表。使用 git format-patch
來(lái)生成可以郵寄到列表的 mbox 格式的文件 - 它將每一個(gè)提交轉(zhuǎn)換為一封電子郵件,提交信息的第一行作為主題,剩余信息與提交引入的補(bǔ)丁作為正文。它有一個(gè)好處是是使用 format-patch
生成的一封電子郵件應(yīng)用的提交正確地保留了所有的提交信息。
$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
format-patch
命令打印出它創(chuàng)建的補(bǔ)丁文件名字。-M
開(kāi)關(guān)告訴 Git 查找重命名。文件最后看起來(lái)像這樣:
$ 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
也可以編輯這些補(bǔ)丁文件為郵件列表添加更多不想要在提交信息中顯示出來(lái)的信息。如果在 ---
行與補(bǔ)丁開(kāi)頭(diff --git
行)之間添加文本,那么開(kāi)發(fā)者就可以閱讀它;但是應(yīng)用補(bǔ)丁時(shí)會(huì)排除它。
為了將其郵寄到郵件列表,你既可以將文件粘貼進(jìn)電子郵件客戶(hù)端,也可以通過(guò)命令行程序發(fā)送它。粘貼文本經(jīng)常會(huì)發(fā)生格式化問(wèn)題,特別是那些不會(huì)合適地保留換行符與其他空白的 “更聰明的” 客戶(hù)端。幸運(yùn)的是,Git 提供了一個(gè)工具幫助你通過(guò) IMAP 發(fā)送正確格式化的補(bǔ)丁,這可能對(duì)你更容易些。我們將會(huì)演示如何通過(guò) Gmail 發(fā)送一個(gè)補(bǔ)丁,它正好是我們所知最好的郵件代理;可以在之前提到的 Git 源代碼中的 Documentation/SubmittingPatches
文件的最下面了解一系列郵件程序的詳細(xì)指令。
首先,需要在 ~/.gitconfig
文件中設(shè)置 imap 區(qū)塊??梢酝ㄟ^(guò)一系列的 git config
命令來(lái)分別設(shè)置每一個(gè)值,或者手動(dòng)添加它們,不管怎樣最后配置文件應(yīng)該看起來(lái)像這樣:
[imap]
folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com
user = user@gmail.com
pass = p4ssw0rd
port = 993
sslverify = false
如果 IMAP 服務(wù)器不使用 SSL,最后兩行可能沒(méi)有必要,host 的值會(huì)是 imap://
而不是 imaps://
。當(dāng)那些設(shè)置完成后,可以使用 git imap-send
將補(bǔ)丁序列放在特定 IMAP 服務(wù)器的 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
在這個(gè)時(shí)候,你應(yīng)該能夠到 Drafts 文件夾中,修改收件人字段為想要發(fā)送補(bǔ)丁的郵件列表,可能需要抄送給維護(hù)者或負(fù)責(zé)那個(gè)部分的人,然后發(fā)送。
你也可以通過(guò)一個(gè) SMTP 服務(wù)器發(fā)送補(bǔ)丁。同之前一樣,你可以通過(guò)一系列的 git config
命令來(lái)分別設(shè)置選項(xiàng),或者你可以手動(dòng)地將它們添加到你的 ~/.gitconfig
文件的 sendmail 區(qū)塊:
[sendemail]
smtpencryption = tls
smtpserver = smtp.gmail.com
smtpuser = user@gmail.com
smtpserverport = 587
當(dāng)這完成后,你可以使用 git send-email
發(fā)送你的補(bǔ)?。?/p>
$ 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
然后,對(duì)于正在發(fā)送的每一個(gè)補(bǔ)丁,Git 會(huì)吐出這樣的一串日志信息:
(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
這個(gè)部分介紹了處理可能會(huì)遇到的幾個(gè)迥然不同類(lèi)型的 Git 項(xiàng)目的一些常見(jiàn)的工作流程,介紹了幫助管理這個(gè)過(guò)程的一些新工具。接下來(lái),你會(huì)了解到如何在貢獻(xiàn)的另一面工作:維護(hù)一個(gè) Git 項(xiàng)目。你將會(huì)學(xué)習(xí)如何成為一個(gè)仁慈的獨(dú)裁者或整合管理者。
更多建議: