## 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 的本地库为:

John 有一个引用指向 Jessica 推送上去的改动,但是他必须将它们合并入自己的工作中之后才能被允许推送:
```
$ git merge origin/master
```
合并后 John 的本地库为:

现在,John 可以测试代码,确保它依然正常工作,然后他可以把合并的新工作推送到服务器上:
```
$ git push origin master
```
最终,John 的提交历史看起来像这样:

而在此期间,Jessica 新建了一个分支 `issue54`,并在该分支上做了多次提交:

Jessica 为了同步 John 的工作,拉取了远程库:
```
$ git fetch origin
```
现在 Jessica 的本地库为:

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 的本地库:

最后将工作上传:
```
$ git push origin master
```

### 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 的仓库为:

当她要推送修改时,收到 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 的提交历史为:

最后,分支 `featureA` 和 `featureB` 被统一合并到 `master` 分支上:

管理团队工作流程的基本顺序:

### 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
```
- 介绍
- 第一章 起步
- 1.1 关于版本控制
- 1.2 Git 简史
- 1.3 Git 基础
- 1.4 命令行
- 1.5 安装 Git
- 1.6 初次运行 Git 前的配置
- 1.7 获得帮助
- 第二章 基础
- 2.1 获取仓库
- 2.2 记录每次更新到仓库
- 2.3 查看提交历史
- 2.4 撤销操作
- 2.5 远程仓库的使用
- 2.6 打标签
- 2.7 Git 别名
- 第三章 分支
- 3.1 分支简介
- 3.2 分支的新建与合并
- 3.3 分支管理
- 3.4 分支开发工作流
- 3.5 远程分支
- 3.6 变基
- 第四章 服务器上的 Git
- 4.1 协议
- 4.2 在服务器上搭建 Git
- 4.3 生成 SSH 公钥
- 4.4 配置服务器
- 4.5 Git 守护进程
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管的选择
- 第五章 分布式 Git
- 5.1 分布式工作流程
- 5.2 向一个项目贡献
- 5.3 维护项目
- 第六章 GitHub
- 6.1 账户的创建和配置
- 6.2 对项目做出贡献
- 6.3 维护项目
- 6.4 管理组织
- 6.5 脚本 GitHub
- 第七章 Git 工具
- 7.1 选择修订版本
- 7.2 交互式暂存
- 7.3 储藏与清理
- 7.4 签署工作
- 7.5 搜索
- 7.6 重写历史
- 7.7 重置揭密
- 7.8 高级合并
- 7.9 Rerere
- 7.10 使用Git调试
- 7.11 子模板
- 7.12 打包
- 7.13 替换
- 7.14 凭证存储
- 第八章 自定义 Git
- 8.1 配置 Git
- 8.2 Git 属性
- 8.3 Git 钩子
- 8.4 使用强制策略的一个例子
- 第九章 Git 与其他系统
- 9.1 作为客户端的 Git
- 9.2 迁移到 Git
- 第十章 Git 内部原理
- 10.1 底层命令和高层命令
- 10.2 Git 对象
- 10.3 Git 引用
- 10.4 包文件
- 10.5 引用规格
- 10.6 传输协议
- 10.7 维护与数据恢复
- 10.8 环境变量
