diff --git a/sources/使用分支.md b/sources/使用分支.md new file mode 100644 index 0000000..32c75f5 --- /dev/null +++ b/sources/使用分支.md @@ -0,0 +1,331 @@ +# 使用分支 + +> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/)) +> +> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/using-branches)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。 + +这份教程是Git分支的综合介绍。首先,我们简单讲解如何创建分支,就像请求一份新的项目历史一样。然后,我们会看到git checkout是如何切换分支的。最后,学习一下git merge是如何整合独立分支的历史。 + +我们已经知道,Git分支和SVN分支不同。SVN分支只被用来记录偶尔大规模的开发效果,而Git分支是你日常工作流中不可缺失的一部分。 + +## git branch + +分支代表了一条独立的开发流水线。分支是我们在第二篇中讨论过的“编辑/缓存/提交”流程的抽象。你可以把它看作请求全新“工作目录、缓存区、项目历史”的一种方式。新的提交被存放在当前分支的历史中,导致了项目历史被fork了一份。 + +`git branch`命令允许你创建、列出、重命名和删除分支。它不允许你切换分支或是将被fork的历史放回去。因此,`git branch`和`git checkout`、`git merge`这两个命令通常紧密地结合在一起使用。 + +### 用法 + +``` +git branch +``` + +列出仓库中所有分支。 + +``` +git branch +``` + +创建一个名为``的分支。*不会* 自动切换到那个分支去。 + +``` +git branch -d +``` + +删除指定分支。这是一个“安全”的操作,Git会阻止你删除包含未合并更改的分支。 + +``` +git branch -D +``` + +强制删除指定分支,即使包含未合并更改。如果你希望永远删除某条开发线的所有提交,你应该用这个命令。 + +``` +git branch -m +``` + +将当前分支命名为``。 + +### 讨论 + +在Git中,分支是你日常开发流程中的一部分。当你想要添加一个新的功能或是修复一个bug时——不管bug是大是小——你都应该新建一个分支来封装你的修改。这确保了不稳定的代码永远不会被提交到主代码库中,它同时给了你机会,在并入主分支前清理你feature分支的历史。 + + + +![Git Tutorial: git branch](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/01.svg) + + + +比如,上图将一个拥有两条独立开发线的仓库可视化,其中一条是一个不起眼的功能,另一条是长期运行的功能。使用分支开发时,不仅可以同时在两条线上工作,还可以保持主要的`master branch`混入奇怪的代码。 + +#### 分支的顶端 + +Git分支背后的实现远比SVN的模型要轻量。与其在目录之间复制文件,Git将分支存为指向提交的引用。换句话说,分支代表了一系列提交的 *顶端* ——而不是提交的 *容器* 。分支历史通过提交之间的关系来推断。 + +这使得Git的合并模型变成了动态的。SVN中的合并是基于文件的,而Git让你在更抽象的提交层面操作。事实上,你可以看到项目历史中的合并其实是将两个独立的提交历史连接起来。 + +### 栗子 + +#### 创建分支 + +分支只是指向提交的 *指针* ,理解这一点很重要。当你创建一个分支是,Git只需要创建一个新的指针——仓库不会受到任何影响。因此,如果你最开始有这样一个仓库: + + + +![Git Tutorial: repository without any branches](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/02.svg) + + + +接下来你用下面的命令创建了一个分支: + +``` +git branch crazy-experiment +``` + +仓库历史保持不变。你得到的是一个指向当前提交的新的指针: + + + +![Git Tutorial: Create new branch](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/03.svg) + + + +注意,这只会 *创建* 一个新的分支。要开始在上面添加提交,你需要用`git checkout`来选中这个分支,然后使用标准的`git addh`和`git commit`命令。 + +#### 删除分支 + +一旦你完成了分支上的工作,准备将它并入主代码库,你可以自由地删除这个分支,而不丢失项目历史: + +``` +git branch -d crazy-experiment +``` + +然后,如果分支还没有合并,下面的命令会产生一个错误信息: + +``` +error: The branch 'crazy-experiment' is not fully merged. +If you are sure you want to delete it, run 'git branch -D crazy-experiment'. +``` + +Git保护你不会丢失这些提交的引用,或者说丢失访问整条开发线的入口。如果你 *真的* 想要删除这个分支(比如说这是一个失败的实验),你可以用大写的`-D`标记: + +``` +git branch -D crazy-experiment +``` + +它会删除这个分支,无视它的状态和警告,因此需谨慎使用。 + +## git checkout + +`git checkout`命令允许你切换用`git branch`创建的分支。查看一个分支会更新工作目录中的文件,以符合分支中的版本,它还告诉Git记录那个分支上的新提交。将它看作一个选中你正在进行的开发的一种方式。 + +在上一篇中,我们看到了如何用`git checkout`来查看旧的提交。“查看分支”和“将工作目录更新到选中的版本/修改”很类似;但是,新的更改 *会* 保存在项目历史中——这不是一个只读的操作。 + +### 用法 + +``` +git checkout +``` + +查看特定分支,分支应该已经通过`git branch`创建。这使得成为当前的分支,并更新工作目录的版本。 + +``` +git checkout -b +``` + +创建并查看`-b`选项是一个方便的标记,告诉Git在运行`git checkout `之前运行`git branch `。 + +``` +git checkout -b +``` + +和上一条相同,但将作为新分支的基,而不是当前分支。 + +### 讨论 + +`git checkouth`和`git branch`是一对好基友。当你想要创建一个新功能时,你用`git branch`创建分支,然后用`git checkout`查看。你可以在一个仓库中用`git checkout`切换分支,同时开发几个功能。 + + + +![Git Tutorial: Switch between multiple features in a single repo with git checkout.](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/04.svg) + + + +每个功能专门一个分支对于传统SVN工作流来说是一个巨大的转变。这使得尝试新的实验超乎想象的简单,不用担心毁坏已有的功能,并且可以同时开发几个不相关的功能。另外,分支可以促进了不同的协作工作流。 + +#### 分离的`HEAD` + +现在我们已经看到了`git checkout`最主要的三种用法,我们可以讨论上一篇中提到的“分离`HEAD`”状态了。 + +记住,`HEAD`是Git指向当前快照的引用。`git checkout`命令内部只是更新`HEAD`,指向特定分支或提交。当它指向分支时,Git不会报错,但当你check out提交时,它会进入“分离`HEAD`”状态。 + + + +![Git Tutorial: Attached vs Detached Head](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/05.svg) + + + +有个警告会告诉你所做的更改和项目的其余历史处于“分离”的状态。如果你在分离`HEAD`状态开始开发新功能,没有分支可以让你回到之前的状态。当你不可避免地checkout到了另一个分支(比如你的更改并入了这个分支),你将不再能够引用你的feature分支: + + + +![Git Tutorial: Detached Head state](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/06.svg) + + + +重点是,你应该永远在分支上开发——而绝不在分离的`HEAD`上。这样确保你一直可以引用到你的新提交。不过,如果你只是想查看旧的提交,那么是否处于分离`HEAD`状态并不重要。 + +### 栗子 + +下面的栗子演示了基本的Git分支流程。当你想要开发新功能时,你创建一个专门的分支,切换过去: + +``` +git branch new-feature +git checkout new-feature +``` + +接下来,你可以和以往一样提交新的快照: + +``` +# 编辑文件 +git add +git commit -m "Started work on a new feature" +# 周而复始… +``` + +这些操作都被记录在`new-feature`上,和`master`完全独立。你想添加多少提交就可以添加多少,不用关心你其它分支的修改。当你想要回到“主”代码库时,只要check out到`master`分支即可: + +``` +git checkout master +``` + +这个命令在你开始新的分支之前,告诉你仓库的状态。在这里,你可以选择并入完成的新功能,或者在你项目稳定的版本上继续工作。 + +## git merge + +合并是Git将被fork的历史放回到一起的方式。`git merge`命令允许你将`git branch`创建的多条分支合并成一个。 + +注意,下面所有命令将更改 *并入* 当前分支。当前分支会被更新,以响应合并操作,但目标分支完全不受影响。也就是说`git merge`经常和`git checkout`一起使用,选择当前分支,然后用`git branch -d`删除废弃的目标分支。 + +### 用法 + +``` +git merge +``` + +将指定分支并入当前分支。Git会决定使用哪种合并算法(下文讨论)。 + +``` +git merge --no-ff +``` + +将指定分支并入当前分支,但 *总是* 生成一个合并提交(即使是快速向前合并)。这可以用来记录仓库中发生的所有合并。 + +### 讨论 + +一旦你在单独的分支上完成了功能的开发,重要的是将它放回主代码库。取决于你的仓库结构,Git有几种不同的算法来完成合并:快速向前合并或者三路合并。 + +当当前分支顶端到目标分支路径是线性之时,我们可以采取 **快速向前合并** 。Git只需要将当前分支顶端(快速向前地)移动到目标分支顶端,即可整合两个分支的历史,而不需要“真正”合并分支。它在效果上合并了历史,因为目标分支上的提交现在在当前分支可以访问到。比如,`some-feature`到`master`分支的快速向前合并会是这样的: + + + +![Git Tutorial: Fast-forward merge](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/07.svg) + + + +但是,如果分支已经分叉了,那么就无法进行快速向前合并。当和目标分支之间的路径不是线性之时,Git只能执行 **三路合并** 。三路合并使用一个专门的提交来合并两个分支的历史。这个术语取自这样一个事实,Git使用 *三个* 提交来生成合并提交:两个分支顶端和它们共同的祖先。 + + + +![Git Tutorial: Three way merge](https://www.atlassian.com/git/images/tutorials/collaborating/using-branches/08.svg) + + + +但你可以选择使用哪一种合并策略时,很多开发者喜欢使用快速向前合并(搭配rebase使用)来合并微小的功能或者修复bug,使用三路合并来整合长期运行的功能。后者导致的合并提交作为两个分支的连接标志。 + +#### 解决冲突 + +如果你尝试合并的两个分支同一个文件的同一个部分,Git将无法决定使用哪个版本。当这种情况发生时,它会停在合并提交,让你手动解决这些冲突。 + +Git的合并流程令人称赞的一点是,它使用我们熟悉的“编辑/缓存/提交”工作流来解决冲突。当你遇到合并冲突时,运行`git status`命令来查看哪些文件存在需要解决的冲突。比如,如果两个分支都修改了`hello.py`的同一处,你会看到下面的信息: + +``` +# On branch master +# Unmerged paths: +# (use "git add/rm ..." as appropriate to mark resolution) +# +# both modified: hello.py +# +``` + +接下来,你可以自己修复这个合并。当你准备结束合并时,你只需对冲突的文件运行`git add`告诉Git冲突已解决。然后,运行`git commit`生成一个合并提交。这和提交一个普通的快照有着完全相同的流程,也就是说,开发者能够轻而易举地管理他们的合并。 + +注意,提交冲突只会出现在三路合并中。在快速向前合并中,我们不可能出现冲突的更改。 + +### 栗子 + +#### 快速向前合并 + +我们第一个🌰演示了快速向前合并。下面的代码创建了一个分支,在后面添加了两个提交,然后使用快速向前合并将它并入主分支。 + +``` +# 开始新功能 +git checkout -b new-feature master + +# 编辑文件 +git add +git commit -m "开始新功能" + +# 编辑文件 +git add +git commit -m "完成功能" + +# 合并new-feature分支 +git checkout master +git merge new-feature +git branch -d new-feature +``` + +对于临时存在、用作独立开发环境而不是组织长期运行功能的工具的分支来说,这是一种常见的工作流。 + +同时注意,运行`git branch -d`时Git不应该产生错误提示,因为`new-feature`现在可以在主分支上访问了。 + +#### 三路合并 + +下一个栗子很相似,但需要进行三路合并,因为`master`在这个功能开发时取得了新进展。这是复杂功能和多个开发者同时工作时常见的情形。 + +``` +# 开始新功能 +git checkout -b new-feature master + +# 编辑文件 +git add +git commit -m "开始新功能" + +# 编辑文件 +git add +git commit -m "完成功能" + +# 在master分支上开发 +git checkout master + +# 编辑文件 +git add +git commit -m "在master上添加了一些极其稳定的功能" + +# 合并new-feature分支 +git merge new-feature +git branch -d new-feature +``` + +注意,Git现在无法进行快速向前合并,因为无法将`master`直接移动到`new-feature`。 + +对大多数工作流来说,`new-feature`会是一个需要一段时间来开发的复杂功能,这也是为什么同时`master`会有新的提交出现。如果你的分支上的功能像上面的一样简单,你会更想将它rebase到`master`,使用快速向前合并。它会通过整理项目历史来避免多余的合并提交。 + + + +> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。 +> +> 如果你觉得文章对你有帮助,欢迎点击右上角的***Star***:star2:或***Fork***:fork_and_knife:。 +> +> 如果你发现了错误,或是想要加入协作,请参阅[Wiki协作说明](https://github.com/geeeeeeeeek/git-recipes/issues/1)。 \ No newline at end of file diff --git a/sources/创建PullRequest.md b/sources/创建PullRequest.md new file mode 100644 index 0000000..38e3516 --- /dev/null +++ b/sources/创建PullRequest.md @@ -0,0 +1,189 @@ +# 创建Pull Request + +> BY 童仲毅([geeeeeeeeek@github](https://github.com/geeeeeeeeek/git-recipes/)) +> +> 这是一篇在[原文(BY atlassian)](https://www.atlassian.com/git/tutorials/making-a-pull-request)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名([CC BY 2.5 AU](http://creativecommons.org/licenses/by/2.5/au/deed.zh))协议共享。 +> +> 原文以Bitbucket为例,考虑到[git-recipes](https://github.com/geeeeeeeeek/git-recipes/)主要面向Github用户,因此栗子替换成了Github。Pull Request在GitLab等平台上也有,用法和本教程基本一致。 + + + +Pull request是开发者使用Github进行协作的利器。这个功能为用户提供了友好的页面,让提议的更改在并入官方项目之前,可以得到充分的讨论。 + +![qq20160127-0](https://cloud.githubusercontent.com/assets/7262715/12608331/8ece897e-c516-11e5-91c0-f7a44434478f.png) + +最简单地来说,pull request是一种机制,让开发者告诉项目成员一个功能已经完成。一旦feature分支开发完毕,开发者使用Github账号提交一个pull request。它告诉所有参与者,他们需要审查代码,并将代码并入`master`分支。 + +但是,pull request不只是一个通知,还是一个专注于某个提议功能的讨论版。 如果更改导致了任何问题,团队成员可以在pull request下发布反馈,甚至推送后续提交来修改这个pull request。所有的活动都在这个pull request里之间追踪。 + +![Git Workflows: Activity inside a pull request](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/02.svg) + +和其他协作模型相比,这种共享提交的解决方案形成了更加线性的工作流。SVN和Git都能通过一个简单的脚本发送通知邮件;但是,如果要讨论更改,开发者不得不在邮件里回复。这会变得愈发杂乱无章,尤其是后续提交出现时。Pull request将所有这些功能放入了一个友好的网页,在每个Github仓库上方都能找到。 + +### 剖析一个Pull Request + +当你提交一个pull request的时候,你做的事情是 *请求 (request)* 另一个开发者(比如项目维护者)来 *拉取 (pull)* 你仓库中的一个分支到他们的仓库。也就是说你需要提供4个信息来完成一个pull request:源仓库、源分支、目标仓库、目标分支。 + +![Git Workflows: Pull Requests](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/03.svg) + +Github会机智地帮你将一些值设为默认值。但是,取决于你的协作工作流,你的团队可能需要设置不同的值。上图显示了一个请求从feature分支合并到官方master分支的一个pull request,但除此之外还有好多种使用pull request的方式。 + +## Pull Request是如何工作的 + +Pull request可以和feature分支工作流、Gitflow工作流或者Fork工作流一起使用。但pull request需要两个不同的分支或是两个不同的仓库,因此它们不能和中心化的工作流一起使用。在不同的工作流中使用pull request有些不同,但大致的流程如下: + +1. 开发者在他们的本地仓库中为某个功能创建一个专门的分支。 +2. 开发者将分支推送到公共的Github仓库。 +3. 开发者用Github发起一个pull request。 +4. 其余的团队成员审查代码,讨论并且做出修改。 +5. 项目维护者将这个功能并入官方的仓库,然后关闭这个pull request。 + +下面的章节讨论pull request在不同的协作工作流中有哪些不同。 + +### Feature分支工作流中的Pull Request + +Feature分支工作流使用共享的Github仓库来管理协作,开发者在单独的feature分支中添加功能。开发者在将代码并入主代码库之前,应该发起一个pull request来启动这个功能的讨论,而不是直接将它们合并到`master`。 + +![Pull Request: Feature Branch workflow](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/04.svg) + +在Feature分支工作流中只有一个公共的仓库,因此pull request的目标和源仓库永远是同一个。一般来说,开发者会将他们的feature分支作为源分支,`master`作为目标分支。 + +在收到pull request之后,项目维护者将会做出决定。如果这个功能可以立即发布,他们只需要将代码合并进`master`,然后关闭pull request即可。但是,如果提议的更改有一些问题,他们可以在pull request下发布反馈。后续提交将会显示在相关评论的下方。 + +你也可以发布一个未完成功能的pull request。例如,如果开发者在实现一个特殊的需求时遇到了问题,同样可以发布一个包含工作进展的pull request。其他开发者可以在这个pull request后面提供建议,甚至自己发布后续的提交来解决这个问题。 + +### Gitflow工作流中的Pull Request + +Gitflow工作流和Feature分支工作流类似,但定义了围绕项目发布的一个严格的分支模型。在Gitflow工作流之上添加pull request使得开发者方便地讨论发布分支或是所在的维护分支。 + +![Pull Requests: Gitflow Workflow](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/05.svg) + + + +![Pull Requests: Gitflow Workflow 2](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/06.svg) + +在Gitflow工作流中的Pull request和上一节中的完全一致:开发者只需在功能、发布或是快速修复分支需要审查时发布一个pull request,Github会通知到其余的团队成员。 + +功能一般都会合并到`develop`分支,而发布和快速修复分支会被同时合并到`develop`和`master`当中。 Pull request可以用来妥善管理这些合并。 + +### Fork工作流中的Pull Request + +在Fork工作流中,开发者将一个完成的功能推送到 *他们自己的* 仓库,而不是公共的仓库。在这之后,他们发布一个pull request,告诉项目维护者代码需要审查了。 + +在这个工作流中,pull request的通知作用显得非常有用,因为项目维护者无法获知其他开发者什么时候向他们自己的Github仓库中添加了提交。 + +![Pull Requests: Forking workflow](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/07.svg) + +因为每个开发者都有他们自己的公共仓库,pull request的源仓库和目标仓库不是同一个。源仓库是开发者的公开仓库,源分支是包含提议更改的那一个。如果开发者想要将功能合并到主代码库,目标仓库便是官方的项目仓库,目标分支为`master`。 + +Pull request还可以用来和官方项目之外的开发者进行协作。比如说,一个开发者正在和同事一起开发一个功能,他们可以向 *同事的* Github仓库发起一个pull request,而不是官方仓库。他们将feature分支同时作为源分支和目标分支。 + +![Pull Requests: Forking workflow](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/08.svg) + +两个开发者可以在pull request中讨论和开发分支。当功能完成时,其中一位可以发起另一个pull request,请求将功能合并到官方的master分支中去。这种灵活性使得pull request成为了Fork工作流中尤为强大的协作工具。 + +## 栗子 + +下面的🌰演示了如何将pull request用在Fork工作流中。小团队中的开发和向一个开源项目贡献代码都可以这样做。 + +在这个栗子中,Mary是一位开发者,John是项目的维护者。他们都有自己公开的Github仓库,John的仓库之一便是下面的官方项目。 + +### Mary fork了官方项目 + +![Pull Requests: Fork the project](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/09.svg) + +为了参与这个项目,Mary首先要做的是fork John的Github仓库。她需要注册登录Github,找到John的仓库,点击Fork按钮。 + +> 下图显示的是geeeeeeeeek的WeChatLuckyMoney仓库。 + +![qq20160127-1](https://cloud.githubusercontent.com/assets/7262715/12614812/232fb7f2-c53d-11e5-80cb-68d2af29d6e9.png) + +选好fork的目标位置之后,她在服务端就有了一个项目的副本。 + +### Mary克隆了她的Github仓库 + +![Pull Request: Clone the Bitbucket repo](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/11.svg) + +接下来,Mary需要将她刚刚fork的Github仓库克隆下来。她在本地会有一份项目的副本。她需要运行下面这个命令: + +``` +git clone https://github.com/user/repo.git +``` + +请记住,`git clone`自动创建了一个名为`origin`的远端连接,指向Mary fork的仓库。 + +### Mary开发了一个新功能 + +![Pull Requests: develop a new feature](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/12.svg) + +在她写任何代码之前,Mary需要为这个功能创建一个新的分支。这个分支将是她随后发起pull request时要用到的源分支。 + +``` +git checkout -b some-feature +# 编辑一些代码 +git commit -a -m "新功能的一些草稿" +``` + +为了完成这个新功能,Mary想创建多少个提交都可以。如果feature分支的历史有些乱,她可以使用交互式的rebase来移除或者拼接不必要的提交。对于大项目来说,清理feature的项目历史使得项目维护者更容易看清楚pull request的所处的进展。 + +### Mary将feature分支推送到了她的Github仓库 + +![Pull Requests: Push feature to Bitbucket repository](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/13.svg) + +在功能完成后,Mary使用简单的`git push`将feature分支推送到了她自己的Github仓库上(不是官方的仓库): + +``` +git push origin some-branch +``` + +这样她的更改就可以被项目维护者看到了(或者任何有权限的协作者)。 + +### Mary创建了一个pull request + +![Pull Request: Create Pull Request](https://www.atlassian.com/git/images/tutorials/collaborating/making-a-pull-request/14.svg) + +Github上已经有了她的feature分支之后,Mary可以找到被她fork的仓库,点击项目简介下的 *New Pull request* 按钮,用她的Github账号创建一个pull request。Mary的仓库会被默认设置为源仓库(head fork),询问她指定源分支(compare)、目标仓库(base fork)和目标分支(base)。 + +Mary想要将她的功能并入主代码库,所以源分支就是她的feature分支,目标仓库就是John的公开仓库,目标分支为`master`。她还需要提供一个pull request的标题和简介。 + +> 下图展示的是将0492wzl/WeChatLuckyMoney(源仓库)的stable(源分支)合并到geeeeeeeeek/WeChatLuckyMoney(目标仓库)的stable(目标分支)。 + +![qq20160127-2](https://cloud.githubusercontent.com/assets/7262715/12615530/3088775a-c541-11e5-914e-d8232037e741.png) + +在她创建了pull request之后,Github会给John发送一条通知。 + +### John审查了这个pull request + +![qq20160127-3](https://cloud.githubusercontent.com/assets/7262715/12615618/b1373fd0-c541-11e5-9b91-47d40f8083ba.png) + +John可以在他自己的Github仓库下的 *Pull Request* 选项卡中看到所有的pull request。点击Mary的pull request会显示这个pull request的简介、feature分支的提交历史,以及包含的更改。 + +如果他认为feature分支已经可以合并了,他只需点击*Merge Pull Request*按钮来通过这个pull request,将Mary的feature分支并入他的`master`分支。 + +但是,在这里栗子中,假设John发现了Mary代码中的一个小bug,需要她在合并前修复。他可以评论整个pull request,也可以评论feature分支中某个特定的提交。 + +![qq20160127-4](https://cloud.githubusercontent.com/assets/7262715/12615732/67c8c872-c542-11e5-9734-71751b83f63c.png) + +### Mary添加了一个后续提交 + +如果Mary对这个反馈感到困惑,她可以在pull request后回复,把这里当做是她的功能的讨论版。 + +为了修复错误,Mary在她的feature分支后面添加了另一个提交,并将它推送到了她的Github仓库,就像她之前做的一样。这个提交被自动添加到原来的pull request后面,John可以在他的评论下方再次审查这些修改。 + +### John接受了pull request + +最后,John接受了这些修改,将feature分支并入了master分支,关闭了这个pull request。功能现在已经整合到了项目中,其他在master分支上工作的开发者可以使用标准的`git pull`命令将这些修改拉取到自己的本地仓库。 + +> 如果你希望实践一下,可以按照上面的流程向这个项目发起一个pull request,修改任何你发现的错误:smile: + +## 接下来怎么做? + +你现在应该已经掌握了如何将你的pull request整合到你的工作流。记住,pull request不是替代任何Git工作流的万金油,而是一种让队员间协作锦上添花的工具。 + + + +> 这篇文章是[**『git-recipes』**](https://github.com/geeeeeeeeek/git-recipes/)的一部分,点击[**目录**](https://github.com/geeeeeeeeek/git-recipes/wiki/)查看所有章节。 +> +> 如果你觉得文章对你有帮助,欢迎点击右上角的***Star***:star2:或***Fork***:fork_and_knife:。 +> +> 如果你发现了错误,或是想要加入协作,请参阅[Wiki协作说明](https://github.com/geeeeeeeeek/git-recipes/issues/1)。 \ No newline at end of file