描述如何为项目做出贡献的主要困难是如何做到这一点的众多变化。因为 Git 非常灵活,人们可以而且确实以多种方式一起工作,而且描述你应该如何贡献是有问题的——每个项目都有点不同。涉及的一些变量包括活动参与者计数、所选工作流、提交访问权限以及可能的外部贡献者方法。
第一个变量是活动贡献者计数 — 有多少用户正在为此项目积极贡献代码,以及多久贡献一次?在许多情况下,您将有两到三个开发人员,每天提交几个,或者对于有些休眠的项目,可能更少。对于较大的公司或项目,开发人员的数量可能达到数千,每天有数百或数千个提交。这很重要,因为随着越来越多的开发人员,您在确保代码干净地应用或可以轻松合并方面会遇到更多问题。您提交的更改可能会因在您工作时或等待批准或应用时合并的工作而过时或严重中断。如何使代码始终保持最新状态且提交有效?
下一个变量是用于项目的工作流。它是否是集中式的,每个开发人员对主代码线具有平等的写入权限?项目是否有维护者或集成经理检查所有补丁?所有补丁都经过同行评审和批准吗?您是否参与了该过程?中尉制度是否到位,您是否必须首先向他们提交您的工作?
下一个变量是提交访问权限。如果您具有项目的写入权限,则为项目做出贡献所需的工作流与没有写入权限时的工作流有很大不同。如果您没有写入权限,项目如何更愿意接受贡献的工作?它甚至有政策吗?您一次贡献了多少工作?您多久贡献一次?
所有这些问题都会影响您如何有效地为项目做出贡献,以及哪些工作流程是首选的或可用的。我们将在一系列用例中介绍其中每个方面,从简单到更复杂;您应该能够从这些示例中构建实践中所需的特定工作流。
提交准则
在我们开始查看特定用例之前,下面是有关提交消息的快速说明。拥有一个很好的创建提交并坚持下去的指南,使得使用Git和与他人协作变得更加容易。Git 项目提供了一个文档,其中列出了许多创建提交以提交补丁的良好提示 — 您可以在文件的 Git 源代码中读取它。Documentation/SubmittingPatches
首先,您的提交不应包含任何空格错误。Git 提供了一种简单的方法来检查此问题 — 在提交之前,运行 ,它可以识别可能的空格错误并为您列出它们。git diff --check
如果在提交之前运行该命令,则可以判断是否要提交可能惹恼其他开发人员的空格问题。
接下来,尝试使每个提交在逻辑上都是单独的变更集。如果可以的话,试着让你的更改易于消化——不要在五个不同的问题上为整个周末编写代码,然后在周一将它们全部作为一个大规模提交提交。即使您在周末不提交,也可以使用星期一的暂存区域将工作拆分为每个问题至少一个提交,每个提交都有一条有用的消息。如果某些更改修改了同一文件,请尝试使用 来暂存文件(在交互式暂存中详细介绍)。无论您执行一次提交还是五次提交,分支顶部的项目快照都是相同的,只要在某个时刻添加了所有更改,因此,当您的开发人员必须查看您的更改时,请尝试使其他开发人员更容易。git add --patch
此方法还使以后需要时可以更轻松地拉出或还原其中一个变更集。重写历史记录描述了许多有用的 Git 技巧,用于重写历史记录和交互式暂存文件 — 在将工作发送给其他人之前,使用这些工具帮助制作干净且易于理解的历史记录。
最后要记住的是提交消息。养成创建高质量提交消息的习惯,使得使用和协作 Git 变得更加容易。作为一般规则,您的邮件应以不超过约 50 个字符的一行开头,并简明扼要地描述变更集,后跟一个空行,后跟更详细的说明。Git 项目要求更详细的解释包括你对更改的动机,并将其实现与以前的行为进行对比 — 这是一个很好的遵循准则。在命令式中写下你的提交消息:“修复错误”,而不是“修复错误”或“修复错误”。
私人小团队
您可能会遇到的最简单的设置是一个包含一两个其他开发人员的私有项目。在这种情况下,“私有”意味着闭源——外部世界无法访问。您和其他开发人员都具有对存储库的推送访问权限。
在此环境中,您可以遵循类似于使用 Subversion 或其他集中式系统时可能执行的操作的工作流。您仍然可以获得离线提交和更简单的分支和合并等优点,但工作流程可能非常相似;主要区别在于合并在提交时在客户端而不是在服务器上进行。让我们看看当两个开发人员开始使用共享存储库时,它会是什么样子。第一个开发人员 John 克隆存储库,进行更改,并在本地提交。在这些示例中,协议消息已被替换为,以缩短它们。…
# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'Remove invalid default value'
[master 738ee87] Remove invalid default value
1 files changed, 1 insertions(+), 1 deletions(-)
第二个开发人员Jessica也做了同样的事情 —— 克隆存储库并提交更改:
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'Add reset task'
[master fbff5bc] Add reset task
1 files changed, 1 insertions(+), 0 deletions(-)
现在,Jessica 将她的工作推送到服务器,这工作正常:
# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc master -> master
上面输出的最后一行显示了来自推送操作的有用返回消息。基本格式为 ,其中表示旧引用,表示新引用,是正在推送的本地引用的名称,并且是正在更新的远程引用的名称。您将在下面的讨论中看到类似的输出,因此对含义有一个基本的想法将有助于理解存储库的各种状态。有关 git-push 的文档提供了更多详细信息。… fromref → torefoldrefnewreffromreftoref
继续此示例,不久之后,John 进行了一些更改,将它们提交到他的本地存储库,并尝试将它们推送到同一服务器:
# John's Machine
$ git push origin master
To john@githost:simplegit.git
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'
在这种情况下,约翰的推动失败了,因为杰西卡早些时候推动了她的改变。如果您习惯于 Subversion,了解这一点尤其重要,因为您会注意到这两个开发人员没有编辑同一个文件。尽管如果编辑了不同的文件,Subversion 会自动在服务器上执行此类合并,但对于 Git,您必须首先在本地合并提交。换句话说,John 必须首先获取 Jessica 的上游更改,并将它们合并到他的本地存储库中,然后才能允许他推送。
作为第一步,约翰获取了杰西卡的工作(这只提取了杰西卡的上游工作,它还没有将其合并到约翰的工作中):
$ git fetch origin
...
From john@githost:simplegit
+ 049d078...fbff5bc master ->