Git-和-Github-入门指南-二-

94 阅读1小时+

Git 和 Github 入门指南(二)

原文:Beginning DevOps on AWS for iOS Development

协议:CC BY-NC-SA 4.0

十、开始项目管理:问题

上一章,我们快速浏览了使用 GitHub 托管和共享我们的代码。但这还不足以描述 GitHub 能为您做什么;有很多特性可以帮助你的项目成熟。在这一章中,我们将开始学习如何用 GitHub 管理项目。因此,我们将从 GitHub 项目管理的基本形式开始:问题。

问题概述

要成功地管理一个项目,任何项目,你都要提前计划;仅仅对新的输入做出反应,通常做任何你想做的事情都是灾难的完美配方。GitHub 项目也不例外;你必须在考虑行动之前记录下你的行动。这就是为什么 GitHub 有一个很棒的功能叫做 Issues。我们将在本节中讨论它们,并学习如何正确管理它们。

在本书的所有章节中,你既是开发者又是项目经理;但是在一个大项目中,你可能不在计划阶段。但是现在,你暂时被提升为项目经理和首席开发人员(除了是唯一的开发人员),恭喜你!项目经理的职责之一是提前计划所有需要完成的任务。计划还不需要非常精确(在现实世界中从来都不是),但是有一个需要完成的所有任务的列表是必要的。这些任务可以是新特性、错误修复,或者只是团队讨论。在 GitHub 中,这些任务被称为问题。

问题用于跟踪团队成员提出的新功能开发、错误修复或新想法。他们是 GitHub 项目管理的基石;从理论上讲,不应该对附加的问题执行任何操作。你采取的每一个行动的目标都应该是解决一个问题。

通过无聊的团队会议来计划下一步的日子已经一去不复返了;现在你确切地知道你的下一步是什么,最重要的是知道其他人在做什么。向你的同事提出新想法比以往任何时候都容易;只需打开一个问题与您的团队讨论,无需使用电子邮件客户端的其他应用。使用 issues 的最大好处是历史可以永久保存——每个特性、每个 bug 和每个讨论。

制造问题

了解问题的最佳方式是直接与它们互动;所以,让我们回到我们的 GitHub 项目页面来处理它们。

当你打开你的 GitHub 项目页面时,你直接到达项目的“代码”部分。这是显示项目文件的部分。现在,你的项目页面应该看起来像我的,如图 10-1 所示。

img/484631_1_En_10_Fig1_HTML.jpg

图 10-1

项目页面在“代码”部分打开

就在项目名称下面,有许多选项卡显示项目的所有部分。你将主要处理“代码”、“问题”、“拉取请求”和“项目”但是现在,让我们把重点放在问题上。继续点击它开始。你应该到达一个如图 10-2 所示的空白部分,因为你的项目还没有问题。

img/484631_1_En_10_Fig2_HTML.jpg

图 10-2

问题部分

那里有许多关于制造新问题的行动呼吁。点击其中一个,你会看到一个类似于我的表单,如图 10-3 所示。

img/484631_1_En_10_Fig3_HTML.jpg

图 10-3

新问题表单

形式非常简单;只有标题是强制性的。如果你需要更多的空间来解释,在标题下面还有一个评论部分。让我们继续用基本的东西填充我们的第一期;暂时不要改变右边的值。

对于我们的第一期,我们开始讨论我们的产品将使用的技术。问题不仅仅是特性和 bug 跟踪所需要的;它们也被用来开始讨论和分享想法。继续填写你的第一期,就像我的一样,如图 10-4;我把我的标题定为“选择应用要使用的技术”,因为这是任何项目的第一步。

img/484631_1_En_10_Fig4_HTML.jpg

图 10-4

我们的第一期

既然我们已经填写了问题的基本信息,请提交它。然后,您将被重定向到新问题的详细视图。它应该类似于图 10-5 中显示的我的问题。

img/484631_1_En_10_Fig5_HTML.jpg

图 10-5

问题的详细信息

首先要注意的是,您的问题已经有了一个编号。每期都有一个唯一的编号,这些编号不会被回收,这意味着即使您删除了一期,它的编号也不会被重复使用。这个数字很重要,您将在本节中看到。

详细信息页面还包括一个评论部分,团队成员可以在这里讨论这个想法。它甚至包括数量有限的表情符号,你可以用它来代替评论。例如,如果你同意某人的观点,向他们竖起大拇指比评论或写“我也是”更好!这会阻碍交流,拖延对话。

在页面的右下方,您可以看到一个订阅按钮。如果您选择订阅某个问题,您将收到有关该问题所做更改的通知。您还会收到关于里程碑事件的新评论和新闻。

既然你是团队的唯一成员,就不多做讨论了。只需添加评论或反应图片,然后关闭问题。关闭问题不会删除它;它只会将其标记为已完成。不建议删除问题,因为需要保留项目的历史记录,而问题是跟踪变更的最佳方式。记住:如果你的知识库是公开的,任何人都可以阅读你的评论;所以,请善待和倒带任何可能出现的不愉快。

评论并关闭问题后,您将返回到问题详细信息页面,它看起来与我的类似,如图 10-6 所示。

img/484631_1_En_10_Fig6_HTML.jpg

图 10-6

结案的问题

您可以继续对已结束的问题发表评论,但不鼓励这样做,因为每个人都认为问题已经解决并继续前进。一个问题也可以被锁定,没有人可以再对它发表评论;这被认为是维持和平的最后努力。我们都有自己的观点,在互联网上讨论这些观点从来都不容易,尤其是在一个开放的论坛上。但是任何时候都要保持专业,因为你说的每一句话都可能被任何人看到。

与问题互动

我们已经成功创建并关闭了一个问题,但是我们并没有过多地参与其中。如果一个问题对项目没有任何影响,那么它有什么好处呢?在这一节中,我们将直接与 GitHub 和我们的代码中的问题进行交互。

在这一部分的第一部分,你将保持你的项目经理的帽子,因为我们将需要计划我们的项目。到目前为止,我们的待办事项应用只是一个挨着一个的多个文本文件。然后我们决定用 HTML5 来更好的呈现它们。为了编码,我们需要一个行动计划;作为一个项目经理,你的工作就是美化这个计划。

因为这是一个简单的 HTML5 应用,我们不需要一个非常大的计划,只需要一些必要的要点。因此,要创建这个应用,我们需要

  • 用 HTML5 写出 app 的骨架

  • 用 CSS3 添加一些样式使它更漂亮

  • 在 README.md 中描述应用

  • 记录代码

  • 为应用创建网页

这些是我们需要完成的一些基本步骤:发布一个 to do 应用。

既然您已经知道如何创建问题,我将让您为每个要点创建一个问题。完成后,你的问题页面应该看起来像我的,如图 10-7 所示。

img/484631_1_En_10_Fig7_HTML.jpg

图 10-7

所有未完成的任务

正如您所看到的,任务是按照它们被介绍的顺序显示的。除了它们的编号之外,也没有办法区分它们,如果问题太多,就很容易迷路。因此,为了更清楚地了解我们所有的任务,我们将使用标签。

标签

标签正是你所期望的:帮助你快速过滤问题的文本。让我们直接使用它们,这样您可以熟悉这个概念。

如图 10-7 所示,在问题页面中有一个搜索栏,您可以使用它来过滤问题。但是由于我们还没有任何标签,所以无法进行任何过滤;只是基本的搜索。点按搜索栏旁边的标签按钮以显示所有可用的标签。然后,您将看到可以使用的默认标签列表;查看图 10-8 中的示例。

img/484631_1_En_10_Fig8_HTML.jpg

图 10-8

默认标签列表

这些是开发者社区中最常用的标签。但这并不意味着它们是强制性的或不可改变的;你可以根据自己的喜好和需要改变它们。只有当你在做一个开源项目时,改变它们才是不明智的,因为大多数开发者已经习惯了它们。

但是因为这是你的个人项目,而你是项目经理,你可以添加、编辑或删除任何你想要的标签。例如,如果你在私人场合独自工作,那么“招聘”这个标签就没有用了。您还可以使用标签来标记问题的严重性;如果问题很严重,许多项目会使用“紧急”或“中断”这样的标签。如果项目足够大,标签也可以用来区分问题的来源。一个大项目可以使用标签“前端”、“后端”或“数据库”来将问题分成不同的组。

对标签进行更改后(尽管我建议只添加您需要的新标签,保留默认标签),回到您的问题并打开详细信息页面。然后,通过单击“标签”按钮在每个标签上应用一个或多个标签。例如,您可以查看图 10-9 。

img/484631_1_En_10_Fig9_HTML.jpg

图 10-9

向问题添加标签

添加标签后,通知将出现在问题页面的评论部分。您可以查看图 10-10 中的示例。

img/484631_1_En_10_Fig10_HTML.jpg

图 10-10

关于新添加标签的通知

现在,仔细检查你的每一个问题,并在上面贴上一些标签。然后,完成后,返回到问题页面。看起来应该是我的,如图 10-11 所示。

img/484631_1_En_10_Fig11_HTML.jpg

图 10-11

标记的问题

完美!既然我们给问题贴上了标签,我们就可以过滤它们了。例如,要查看每个标有“增强”的问题,只需点击过滤器(如图 10-12 所示),您将得到如图 10-13 所示类似于我的结果。

img/484631_1_En_10_Fig13_HTML.jpg

图 10-13

过滤的问题

img/484631_1_En_10_Fig12_HTML.jpg

图 10-12

按标签过滤

过滤不是很好玩吗?!但你知道什么更有趣吗?将问题分配给其他人!开始吧。

代理人

既然我们的问题已经被正确标记,是时候将它们分配给开发人员了。这是一项相当简单的任务,与标签没有太大区别。

您最多可以将一个问题分配给十名小组成员。但既然现在只有你一个人,你只能指派自己。开始吧!导航到标题为“用 HTML5 编写应用的框架”和“用 CSS3 添加一些样式使其更漂亮”的问题,并将它们分配给自己。将问题分配给团队成员的工作方式与添加标签完全一样。您可以查看图 10-14 中的示例。

img/484631_1_En_10_Fig14_HTML.jpg

图 10-14

分配问题

在您将这两个问题分配给自己后,您将会得到一个与我类似的结果,如您的问题页面上的图 10-15 所示。现在,您可以按标签和受托人过滤您的问题。

img/484631_1_En_10_Fig15_HTML.jpg

图 10-15

完整的问题列表

现在问题已经分配给你了,摘下经理的帽子,戴上开发人员的帽子。是时候把手弄脏了!

将问题与提交联系起来

正如我们在本章开始时所说的,你用 Git 采取的每一个行动都应该以解决问题为目标。大多数时候,在使用 Git 的时候,你会和 commits 一起工作;因此,这些提交中的每一个都应该与一个问题相关联。在本节中,我们将学习如何将我们的提交与问题联系起来。

首先,让我们决定我们将处理哪些问题。正如我们在图 10-15 中看到的,有两个问题分配给我们:“用 HTML5 编写应用的框架”和“用 CSS3 添加一些样式使它更漂亮。”我们将首先开始写框架,因为从这开始很有意义。所以打开这一期的详细页面,记下它的编号。如图 10-16 所示,我的是第 2 期。

img/484631_1_En_10_Fig16_HTML.jpg

图 10-16

问题编号 2 详细信息页面

处理提交

现在我们有了一个要解决的问题及其编号,是时候准备提交了。因为我们决定为这个应用使用简单的 HTML5,所以我们只需要一个文件作为框架。因此,在您的工作目录中创建一个名为 index.html 的文件,并粘贴以下代码:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

现在,我将让您暂存新创建的文件,但不要提交它;我们必须讨论提交消息。

引用问题

我们准备在当前状态下提交项目,但是我们必须调整提交消息,以便提交可以链接到一个问题。将提交与问题相关联的最常见方式是在提交消息中提及问题编号。

到目前为止,我们只使用了非常短的提交消息,因为我们试图将它们保持在一行之内。但是因为我们需要空间来用一种更精细的方式来描述我们的提交,所以从现在开始,我们将按照这种方式来构造我们的提交消息:标题、主体和页脚用一个空行隔开。为了帮助您理解,您可以在图 10-17 中找到它的图示。

img/484631_1_En_10_Fig17_HTML.jpg

图 10-17

提交消息结构

警告

不要忘记提交消息的每个部分之间的空行。它们真的很重要。

正文和页脚是可选的;只有在必要的时候才使用它们,尤其是身体。人很懒;他们可能只会阅读标题并继续前进,所以即使没有正文也要特别清楚。

页脚是我们现在感兴趣的;这是为 GitHub 等问题跟踪者保留的部分。我们使用页脚引用问题的数字。例如,要引用我们正在处理的问题,我们只需将其编号放在页脚中,前面加“#”当 GitHub 看到这一点时,它会立即将提交与引用的问题联系起来。

注意

我们可以将对问题的引用放在提交消息中的任何地方,甚至放在标题中。但这种做法很难看,应该劝阻。

综合所有这些,让我们用一个合适的提交消息进行提交。以我的提交为例,如图 10-18 所示。

img/484631_1_En_10_Fig18_HTML.jpg

图 10-18

提交链接到问题#2 的消息

在我的提交消息中,我跳过了正文部分,因为它是不必要的。我只需要将这个提交链接到问题#2,所以我将这个数字放在页脚中。

现在,推它!如果你忘了怎么做,看一下上一章(提示:git push origin master)。

现在让我们回到本期的详细页面。您将注意到的第一件事是添加了一个新的注释:这是对我们的提交的引用。它应该看起来像图 10-19 中描绘的我的。

img/484631_1_En_10_Fig19_HTML.jpg

图 10-19

对我们上次提交的引用

这是 GitHub 的一个非常有用的特性,您肯定会经常用到:显示所有与特定问题相关的提交。这就是为什么不应该在没有绑定到某个问题的情况下进行提交;这样对项目的管理更好。

如果点击参考上显示的提交标题(见图 10-19 ,您将看到一个熟悉的屏幕。我会让你自己发现图 10-20 中描绘的是哪个屏幕。

img/484631_1_En_10_Fig20_HTML.jpg

图 10-20

提交的详细视图

没错!这是“git show”视图。没有必要迷失在 Git 命令中去查看 commit 做了什么,你可以直接在 GitHub 中看到它!

既然我们已经成功解决了该问题,请返回其详细信息页面并关闭它。让我们解决下一个问题!

使用关键字结束问题

解决一个问题并结束它感觉很好,对吧?嗯,还有更有趣的事情:通过在提交消息中使用关键字来结束一个问题!

首先,我们必须决定要解决哪个问题。我们的下一期是“用 CSS3 添加一些样式使它更漂亮”,它的数字是 3。大家一起解决吧!打开 index.html,将内容更改为:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align:center;
            }
            h3 {
                text-transform: uppercase;
            }
            li {
                overflow: hidden;
                padding: 20px 0;
                border-bottom: 1px solid #eee;
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

暂存文件,但不要提交。关闭问题的关键词是

  • 关闭

  • 关闭的

  • 固定

  • 修理

  • 固定的;不变的

  • 分解

  • 分解

  • 断然的

使用这些单词中的一个后跟一个问题编号,会将其标记为已解决并关闭它。我们的提交将解决问题#3,因此我们将把它放在提交消息页脚中。你的提交消息应该看起来像我的,如图 10-21 所示。

img/484631_1_En_10_Fig21_HTML.jpg

图 10-21

通过提交消息解决问题

就像提交消息一样,问题引用应该使用命令式语气;所以最好用“resolve”而不是“resolved”现在,是时候推动我们的承诺并亲眼看看了!

导航到您处理的问题(您不会在打开的问题中找到它,请使用过滤器查看关闭的问题)并打开详细信息页面。你应该会看到一个和我一样的新评论,如图 10-22 所示。

img/484631_1_En_10_Fig22_HTML.jpg

图 10-22

按关键字关闭的问题

如果您单击提交名称,您将再次看到提交的“git show”视图。

GitHub 的这个小特性很有用,但是使用时要非常小心。仅当您完全确定问题已经解决时,才关闭该问题。关闭和重新打开问题会让人们感到困惑,并生成大量通知。不要错误地关闭不同的问题!83%的工作场所暴力是由于问题解决失误造成的。我刚刚发明了这个统计数据,但这并不意味着你应该认真对待它!

摘要

哦!那一章有点长,不是吗?我们学到了很多关于问题的知识,但最重要的是,如何将它们与提交联系起来。永远记住,在采取行动之前,要把所有的行动都放到问题中去。别忘了用标签和受托人对它们进行分类。

我们关于基本项目管理的章节到此结束。现在你应该知道如何在 GitHub 中计划你的下一步行动了。但是项目管理不仅仅是预先计划任务;你还应该对过去发生了什么以及达到了哪些里程碑有一个清晰的认识。因此,我们将对项目进行“适当的”项目管理;本节还包括 GitHub 工作流的大部分形式的非常简短的总结。走吧!

十一、深入项目管理:分支

上一章,我们发现了问题并利用它们来计划我们的项目。我们还学习了如何将我们的提交与问题联系起来,这样我们就可以跟踪项目中的每个变更。我们的工作方式很简单:选择一个问题,做出可以解决它的承诺,然后推给 GitHub。该问题随后得到解决并关闭。但这种工作方式在大多数现实项目中并不太适应;搞砸的可能性太大了。

如果您需要多个提交来解决一个问题,该怎么办?如果其他团队成员提交了一个包含对您正在处理的相同文件的更改的提交,该怎么办?如何确保推送的提交真正解决了问题?所有这些都是不建议对项目进行直接变更的部分原因,即使你独自工作。

正如我们在上一章中所说的,通过提交消息中的关键字来结束一个问题是很酷的,但是你应该非常小心。只有你看过你的作品,它可能无法解决问题。或者它可能在项目中引入新的 bug。这就是为什么在接受修改之前,最好让别人来检查你的代码。

这就是我们在本章将要讨论的部分。首先,将向您介绍最常见的 GitHub 工作流(大多数团队如何在 GitHub 上工作),然后我们将了解分支的概念。

但在我们开始这一章之前,有一件小事你应该永远记住:“你会犯错误。很多时候。所以你必须确保使用尽可能多的安全措施。”走吧!

GitHub 工作流程

在本节中,我们将讨论开发人员使用 GitHub 的最常见方式。请记住,每个团队都有自己的做事方式,但是每种工作方式都受到我们将要介绍的基本工作流程的启发。

还记得关于犯错的小事实吗?这种错误无处不在的可能性就是你需要遵循 GitHub 工作流程的原因,所以即使错误发生了,你也要以可控的方式隔离它的影响。我们从上一章开始的工作方式是将一切直接提交给主项目,这是非常危险的。主项目大部分时间是“生产”线,客户看到和使用的版本。所以,这个版本必须非常干净,应该总是可利用的。如果任何错误出现在主版本中,客户将会遇到错误,并且会扰乱每个团队成员。

解决这个问题的一个方法是创建一个主项目的副本,并处理这个克隆。您对此副本所做的每个更改都不会影响主项目,因此您的任何错误都不会影响客户。当您(和其他人)完全确定所做的更改解决了问题时,您可以在主版本中重现这些更改。

主项目的那些副本被称为分支,将变更复制到另一个分支的概念被称为合并。您可以创建任意多的分支,并且可以在它们之间交换提交。当您第一次创建存储库时,Git 会为您创建一个新的分支;它叫“主人”大多数开发人员将他们的主版本或生产版本放在 master 中,只有当他们完全确定可以这样做时,才在那里重新创建更改。

就像树的分支一样,Git 分支可以有许多分支,这意味着您甚至可以从主分支之外的分支创建新的分支,即使很难维护这样的架构。大多数情况下,您会在处理问题时创建一个分支,并在问题解决后删除它。

为了正确看待这一切,我们将学习默认的或常见的 GitHub 工作流。如你所知,一切都应该从一个问题开始。我们已经讨论了最后一章,所以你已经很熟悉了。因此,我们将讨论工作流程的每个后续步骤。

当您打算通过更改代码来解决问题时,您应该首先创建项目的当前工作版本的副本:创建一个新的分支。

然后,像往常一样,您进行更改并提交项目的状态。您可以根据需要进行任意数量的提交;不会影响主枝。你也可以将你的提交推送到 GitHub,这样你的代码就可以被看到了。

然后,您将您的分支链接到主分支,这样其他人就可以比较更改并审查您的代码。这个链接称为“拉”请求:您请求将您的提交应用到主分支。

然后,其他团队成员可以在 GitHub 上审查您的代码并发表评论。然后,您会提交更多的提交来处理这些注释,直到所有问题都解决了。

如果每一方(开发人员、管理人员、测试人员或客户)都同意您的更改是可以的,并且解决了手边的问题,那么拉请求就被接受了。这意味着您在分支上进行的每个提交都将应用到主分支。然后,您可以删除您创建的分支。

就是这样!你可能想知道它与直接推入 master 有何不同。这是非常不同的,因为错误和遗漏是在将更改应用到生产版本之前发现的;这意味着生产缺陷的数量减少到了最低限度。这也使得你的团队中的不同成员能够在应用变更之前对其进行审核,这是大多数科技公司的标准工作方式。将变更捆绑到一个拉请求中也解决了多人同时提交解决不同问题的问题。它可以保持历史日志的整洁。

只有当您觉得您的工作已经完成时,您才可能想要打开“拉”请求。除非你做的工作很小很简单,否则不要等太久才打开一个 PR。通过在开发的早期进行公关,你可以在做出太多改变之前收到反馈。这对初学者来说非常有用,尤其是因为从一开始就走上错误的道路将需要很长时间来纠正,而且你会希望早点被告知正确的道路。打开一个拉请求并不意味着工作已经完成;这仅仅意味着您正在考虑将提交从一个分支应用到另一个分支。

注意

如前所述,您可以从任何分支创建分支,并打开对它的拉请求。不仅仅是留给主人的。

总结所有这些步骤,你可以在图 11-1 中找到一个小插图。

img/484631_1_En_11_Fig1_HTML.jpg

图 11-1

基本 Git 工作流程

如您所见,我们可以从项目中的任何分支创建分支。Git 在存储库初始化时为我们创建了一个名为 master 的分支。然后我们可以创建更多的分支(例如,一个 bugfix 分支或者一个 feature 分支)来引入主分支中的变更。

分支

正如我们之前所说的,分支是代码评审背后的主要特征。你要先做好自己的分支再发表作品,这样就不会被别人的改动所困扰。简单来说,一个分支只是你自己在某个时间对项目的独立拷贝。让我们看看它们是如何工作的,并创建和删除一些。

分支背后的逻辑很简单:获取项目的当前状态,并制作一个副本。在这个副本中,您可以在不影响其他人的情况下进行更改。您可以使用分支来获得不同的发布渠道,或者只是尝试项目中的新事物。

创建存储库时,默认情况下会得到一个分支:master。在做非常小的项目的时候,这个分支就够了;但是大多数项目需要更多的分支才能得到最好的结果。首先,他们需要一个生产分支,客户可以在那里获得软件的最新稳定版本;这是主分支。只有当项目确定稳定时,生产分支才会被更新,因为这是发布分支。然后是开发分支,在那里所有的进展都被记录,所有的提交都被测试。你将主要在开发分支工作,因为这是最有趣的地方。最后,在将提交合并到开发分支之前,您将创建短命的修补分支来保存您的提交。那些打补丁的分支生死与拉请求;您可以在解决问题时创建一个,然后删除它。

简单总结一下,你会(大部分时间)有三种分支:

  • 生产分支,您将在这里发布项目的稳定版本

  • 开发分支,您将在那里测试您的最新版本

  • 修补分支,您将在那里处理您的问题

除非有非常紧急的重大问题需要立即解决,否则你永远不会直接向生产部门或开发部门提交任务。为了更新这些分支,您将使用 pull 请求,以便对变更进行检查和测试。有一些公司,每个开发人员都直接提交给开发分支,但是这是非常违反直觉的,因为如果发现了 bug,他们不知道是哪个提交引入的。此外,它迫使开发人员进行“一次完成”提交,这是一种反模式。全做提交是指尝试同时解决许多问题的提交,例如,修复一个错误并同时引入一个新功能的提交。这种做法通常是由开发人员的懒惰造成的,因为他们不想为另一个问题创建新的分支。这就产生了非常糟糕的拉请求,并且很难跟踪项目的进展。这也给测试人员带来了巨大的挑战,因为他们不知道哪个版本是稳定的。这是一个全方位的坏主意;即使是你的小项目也不要这样做。一直创建和删除分支似乎很累,但这是使用 Git 时最好的工作流程。

关于 Git 分支要记住的一件事是,它们只是提交的简单引用;这就是为什么创建和删除它们如此之快。还记得我们讨论过 Git 如何在链接中存储提交吗?嗯,分支只是对其中一个提交的引用。提交包含关于作者、日期、快照以及最重要的上一次提交的名称的信息。前一个提交的名称称为 parent,除了第一个提交之外,每个提交都至少有一个 parent。因此,每次提交都与前一次提交相关联,这样我们就可以重新创建项目的变更历史。

现在,您只有名为 master 的默认分支,它引用项目的最后一次提交。为了创建一个新的提交,Git 检查哪里是引用,并使用该提交中的信息在新提交和之前引用的提交之间建立链接。因此,每次提交时,引用都移动到新的提交,循环继续。因此,分支只是对提交的引用,而提交是下一个提交的父提交。

但是 Git 怎么知道我们在哪一个分支上呢?它使用了另一个名为 HEAD 的引用来引用当前的提交。如果在分支上,HEAD 引用该分支的最后一次提交。但是如果你正在签出一个先前的版本(就像我们使用“git checkout <commit_name>”)时所做的那样,HEAD 引用提交,你就处于一种被称为“分离 HEAD”的状态</commit_name>

警告

就像人体一样,如果可以避免,永远不要处于“脱头”的状态。发现自己处于非常危险的境地。

在大多数情况下,您可以将 HEAD 视为对当前分支的引用,并且您创建的每个提交都将使用该分支中的最后一个提交作为父提交。

当您将一个分支合并到另一个分支时,会创建一个具有两个父级的新提交:每个分支一个父级。因此,您可以通过提交类型的父类数量来识别提交类型:

  • 没有父母:第一次提交

  • 一个父级:分支中的正常提交

  • 多个父级:由分支合并创建的提交

创建分支

现在你已经知道了很多关于分支的知识,让我们创建一个吧!这很容易;您只需要使用“git branch”命令,后跟分支名称。请记住,分行名称应该只包含字母数字值和破折号或下划线;不允许有空格。

$ git branch <name>

例如,让我们为我们的项目创建一个开发分支。我们把它命名为“开发”以下是如何做到这一点:

$ git branch develop

执行该命令后,您会注意到项目中没有任何变化。这是因为创建一个分支仅仅是创建一个对当前分支的最后一次提交的引用,除此之外别无其他。要开始使用分支,您必须切换到它。

切换到另一个分支

我们创建了我们的开发分支,现在是时候切换到它了。但问题是:我忘记了我给这个分支取的名字。现在,有人可能会建议,我们可以回头看看前面的部分,看看名字。但我有一个更好的主意:列出我们目前所有的分支机构。为此,只需执行不带任何参数的 git branch 命令。

$ git branch

这个命令将给出你当前拥有的分支列表,并在你当前所在的分支(头部)旁边放一个小星星。检查图 11-2 中的分支列表示例。

img/484631_1_En_11_Fig2_HTML.jpg

图 11-2

我们项目中的分支列表

您会注意到,我们仍然在主分支上,因为除了创建一个分支之外,我们没有做任何事情。现在我们切换到它。

您已经知道了在版本之间切换的命令。我们将使用相同的命令在分支之间导航。只需使用“git checkout ”,并将分支的名称作为参数。

$ git checkout <name>

因此,如果我们想切换到 develop 分支,我们必须执行:

$ git checkout develop

注意

就像我们在版本间导航时,如果你有未提交的变更文件,你不能切换分支。行动前提交。或者使用一种叫做“隐藏”的技术,我们将在后面的章节中看到。

在签出新的分支后,您将从 git 得到一条确认消息,您还可以检查 Git 状态的结果以确保这一点。图 11-3 显示了这些命令的结果。

img/484631_1_En_11_Fig3_HTML.jpg

图 11-3

切换分支

练习:创建测试分支

在我们开始下一场战斗之前做一个简单的练习。这很简单,因为所有的答案都在这一部分。这个练习将创建一个名为“testing”的分支,在将所有提交合并到主分支之前,我们将在这个分支中测试我们的项目。你必须这么做

  • 回到主分支

  • 创建一个名为“testing”的新分支

  • 切换到新的分支

小费

要在创建分支后立即切换到新分支,可以在 git checkout 命令中使用选项“-b”。例如,“git 检验-b 测试”与“git 分支测试”和“git 检验测试”是一样的

删除分支

你喜欢创建测试分支吗?很好。是时候删除了,因为我们已经有了一个测试分支:开发。我们将在那里合并我们的修补分支,所有的测试都将在那里进行。

您可以删除推式分支,即远程存储库中存在的分支,方法是在创建拉取请求时选中“PR 合并后删除分支”。这将删除远程分支,但您的本地分支将保持不变。您必须手动删除本地分支。

要删除一个分支,只需使用与创建分支相同的命令,但要使用选项“-d”

$ git branch -d <name>

因此,要删除我们的测试分支,我们将使用

$ git branch -d testing

就像一个真正的树枝一样,你不会切断你现在站着的 Git 树枝。请在删除分支之前签出另一个分支;由于这个原因,一个项目中不能少于一个分支。如果您仍然尝试,您将得到如图 11-4 所示的错误。

img/484631_1_En_11_Fig4_HTML.jpg

图 11-4

删除当前分支

因此,您必须在删除测试分支之前检出主分支或开发分支。如果你做的正确,你应该得到一个如图 11-5 所示的结果。

img/484631_1_En_11_Fig5_HTML.jpg

图 11-5

删除一个分支(我们几乎不知道叶)

记下确认消息,它给出了您刚刚删除的分支的 SHA-1 名称。因为我们创建和删除的分支不包含提交,所以它只引用当前分支的最后一次提交。让我们检查历史日志来确认这一点。执行 git log 命令来获取最新提交的列表,如图 11-6 所示。

img/484631_1_En_11_Fig6_HTML.jpg

图 11-6

提交名称检查

您将看到最后一个提交名称和分支名称是相同的;这是因为我们还没有在我们的分支中进行任何提交。您还会在历史日志中看到分支的起始位置。在本例中,开发分支源自 80f145c 提交;是分支的母公司。

合并分支

我们在这一章中谈了很多关于合并分支的内容,但是我们还没有进行一次合并。让我们改变这一点。

假设您想通过添加一些信息来改进项目的自述文件。这项任务已经在我们的 GitHub 问题中列出,所以没有问题。下一步是从开发分支创建一个新的分支,这样我们可以在以后合并它们。您必须从 develop 分支而不是主分支创建一个新分支,因为我们不会触及主分支,直到一切都被正确测试。如果一切都清晰明了,我们将把开发分支合并到主分支中。

很明显,让我们创建新的分支,我们将在那里工作。我们把它命名为“改进-自述-描述”在从 develop 分支创建新的分支之前,不要忘记签出 develop 分支。因此,我们必须执行

$ git checkout develop
$ git branch improve-readme-description

现在已经创建了分支,切换到它,这样我们就可以开始工作了。要切换到新的分支,只需使用 checkout 命令。

$ git checkout improve-readme-description

完美!现在我们有了一个名为“改进-自述-描述”的分支,它源自于 develop 分支。我们如此喜欢树枝,以至于我们用树枝创造了树枝!

现在我们开始工作吧。打开 README.md 文件,将其内容更改为

# TODO list
A simple app to manage your daily tasks.
It uses HTML5 and CSS3.

## Features
* List of daily tasks

现在,存放文件并准备提交。我将让您选择提交消息,但是不要忘记引用您试图解决的问题!因此,接下来的步骤是

$ git add README.md
$ git commit

这里没有什么新的,因为每个命令在任何分支中都是一样的。唯一的细微变化是提交描述中的分支名称不同。你可以在图 11-7 显示的我的结果上看到。

img/484631_1_En_11_Fig7_HTML.jpg

图 11-7

提交到另一个分支

提交之后,检查 Git 历史记录,以便正确看待我们所做的一切。执行 git log 命令来查看我们的项目历史。

$ git log

小费

使用 git log 时使用选项“- oneline”可以获得更好的结果。

在你提交后,你的项目历史日志应该和我的一样,如图 11-8 所示。

img/484631_1_En_11_Fig8_HTML.jpg

图 11-8

提交分支后的历史日志

如图所示,HEAD 现在指向我们新分支的最后一次提交;这意味着我们将创建的每个提交都将有它作为父提交。您还会注意到主分支和开发分支没有改变;那是因为我们只在新成立的分公司工作。

既然我们对修复感到满意,让我们将分支合并到开发分支,这样我们就可以测试它了。要将我们的分支合并到 develop 中,我们首先必须检查它。因此,使用 git checkout 命令导航到那里。

$ git checkout develop

现在让我们试着将分支合并到开发分支。合并只是意味着将一个分支上的所有提交复制到另一个分支上。为此,我们将使用 git merge 命令,后跟要合并的分支的名称。

$ git merge <name>

因为我们希望将“改进-自述-描述”合并到“开发”中,所以我们要在开发分支上执行的命令是

$ git merge improve-readme-description

该命令将把您的提交从“改进-自述文件-描述”重新创建为“开发”因此,您将得到与提交确认类似的结果。查看图 11-9 中的示例。

img/484631_1_En_11_Fig9_HTML.jpg

图 11-9

合并结果

让我们重新检查一下 git 日志,以便更清楚地了解发生了什么。在执行如图 11-10 所示的“git log - oneline”后,您将得到与我类似的结果。

如您所见,HEAD 现在指向 develop,因为它是签出的分支。您还可以注意到 develop 和 improve-readme-description 现在指向相同提交;那是因为合并。

img/484631_1_En_11_Fig10_HTML.jpg

图 11-10

合并后的历史日志

恭喜你第一次合并!下一次就没那么容易了(提示:合并冲突,当同一行代码在不同的提交中被修改时就会出现)

将分支推到远程

分支不仅仅是为了在本地工作而创建的,您还可以通过将它们推送到远程存储库来将它们发布给全世界。例如,让我们将我们的开发分支推送到 GitHub,这样每个人都可以看到我们的进展。

将分支推到远程的命令是(你猜对了!)git 推送,就像我们上一章学的一样。命令是

$ git push <remote_name> <branch_name>

远程名称没有改变;还是“起源”这次不同的是分店名称。代替 master,我们将推动 develop 分支。因此,命令将是

$ git push origin develop

因为您之前已经推至远程,所以图 11-11 中所示的结果对您来说很熟悉。

img/484631_1_En_11_Fig11_HTML.jpg

图 11-11

推送到远程分支机构

正如您所看到的,结果有一点不同:它给了我们一个创建 pull 请求的链接,即请求允许在 develop to master 上复制提交。请注意这个链接,因为我们将在下一章学习拉请求。☺

如果您返回 GitHub 查看您的项目页面,您还会看到关于创建 pull 请求的行动号召按钮。现在忽略它们,转而在主分支和开发分支之间导航。您可以查看图 11-12 中新分支被推送后的项目页面示例。

img/484631_1_En_11_Fig12_HTML.jpg

图 11-12

我们的新项目页面

现在都是关于分支的。您现在知道如何创建、合并和删除它们。最重要的是,您对 GitHub 工作流有一个基本的了解:创建一个分支,处理这个分支,并创建一个 pull 请求。

现在,你可能会问自己:“但是你不是答应我们代码审查和拉请求吗?我们使用工作流程了吗?”你完全正确。我们没有使用工作流,因为我们使用了直接的方法:直接处理分支。在现实世界的项目中,你不会像我们之前所做的那样直接提交并推送到主项目或开发分支。相反,您将使用 Pull Request 将分支合并在一起。这样,在将您的工作合并到开发或主分支之前,您的同事可以审阅您的工作。

摘要

本章讨论了是什么让 Git 成为项目管理的强大工具:分支。在快节奏的开发中,分支是必要的,因为您可能会同时处理许多问题。将所有这些变化保持在同一个地方是一种灾难。比如,你需要在一个干净的环境中开始修复一个 bug 或者引入一个特性;试图同时做这两件事会严重增加引入更多 bug 的风险。

本章的主要内容是使用 Git 开发时使用工作流的重要性。这些工作流都使用分支来分离干净的问题解决所必需的不同类型的工作。

我们已经看到了如何创建、检出和删除一个分支。现在,让我们学习更多关于拉请求和代码审查的知识,这样我们就可以在我们的主分支中提出变更!

十二、更好的项目管理:拉取请求

在最后一章,我们了解了典型的 GitHub 工作流程;大多数公司在日常工作中使用这种工作流程的变体。我们也学到了很多关于树枝和如何使用它们的知识。但是有一点我们没有机会复习:如何将那两个概念结合起来。答案很简单:拉请求和代码审查。

前一章提供了许多使用传统的代码管理方法(每个人都提交到同一个分支)是个坏主意的原因。但是由于我们在当前的项目中单独工作,我们还没有看到不便之处。但是他们在这里,他们需要很多时间来解决;所以,相信我,还是跟着工作流程走比较好。

本章将向您展示如何实现前一章中介绍的工作流。我们将使用新创建的分支向旧分支引入变更。我们还将学习代码审查以及如何管理它们。

为什么使用拉取请求?

许多不遵循特定工作流程的开发人员说这是浪费时间,因为这会占用宝贵的开发时间。这句话是有道理的,因为遵循工作流意味着等待其他人来审查你的代码。但是你必须记住,你不必在等待审查的时候无所事事,你可以直接去解决另一个问题!这就是为什么分支在版本控制系统中如此强大;你可以同时处理多个问题。有了这个工作流程,你可以开始处理一个问题,向你的同事寻求一些想法或指导,然后在等待回复的时候处理另一个问题。收到必要的反馈后,您可以继续处理第一个问题,并重复此过程,直到所有问题都得到解决。使用工作流还可以让您开始处理某个问题,即使关于该做什么的信息尚未完成;你可以处理一个问题,中途停下来获取更多信息。最后一点:让别人重读你的代码是减少错误的最好方法;不到处追 bug 所获得的时间,比直接致力于 master 所获得的时间更大。

GitHub 工作流也是开源贡献者的首选工作方式。如果任何人都可以不经过任何审查就直接将提交推送到分支,那将是非常糟糕的。取而代之的是,每个贡献者都有一个项目的工作克隆,并且可以提出其他贡献者将审阅和讨论的变更。

因此,总之,使用 GitHub 工作流是最好的工作方式,使用它将大大减少您的错误。正如我们在上一章中看到的,使用分支只是第一步,所以您必须使用拉请求来完成工作流。让我们进一步了解他们吧!

拉取请求概述

拉请求虽然有用,但却是一个相当容易理解的概念。提交一个拉请求,或者 PR,只是请求将一个分支中的所有提交应用到另一个分支的许可。但是我们进展太快了。在了解拉请求之前,我们必须了解什么是“拉”。

在 Git 术语中,“拉”正好是“推”的反义词(如果你猜对了,给自己一个击掌吧!).Push 获取您的分支,并将其所有提交复制到远程分支,如果服务器上还不存在该分支,则创建该分支。拉就是这样,但是向后:它查看一个远程分支,并将提交复制到您的本地存储库。这只是一个提交的交换:如果是从本地到远程,就推;如果是从远程到本地,就拉。

语法也非常相似:

$ git pull <remote_name> <branch_name>

因此,例如,如果您想从 GitHub 上的主分支获得提交,您必须在检出主分支时执行该命令:

$ git pull origin master

在运行任何命令之前,请确保始终位于与您正在拉动的分支相对应的分支上。因此,在这种情况下,您必须在运行 git pull 之前检查 master。执行该命令后,你会得到一个如图 12-1 所示的结果。

img/484631_1_En_12_Fig1_HTML.jpg

图 12-1

从原点拉主控形状

因为您在本地存储库和 GitHub 上有相同的提交,所以什么也没发生。但是一旦你开始和其他人一起工作,你将不得不在你的本地机器上拉动他们的分支来审查他们的变更或者仅仅是在 GitHub 上审查变更。

基本就是它了!拉只是将提交从远程分支复制到本地分支。别担心,你很快会有更多的机会玩 git pull。

公关是做什么的

现在我们对拉取有了更多的了解,我们对什么是拉取请求有了更清晰的概念。PR 只是请求在远程存储库上执行“拉”操作的权限。但是拉动一个分支还不足以完成动作:你还必须将分支合并在一起。

还记得我们将补丁分支合并到开发分支的时候吗?公关只是在请求允许这样做。您可以对您的本地分支做任何您想做的事情,但是当您与上游分支(远程存储库中的分支)打交道时,您必须使用一点礼貌并首先请求许可。这确保了主分支中提交的每个修复都经过了适当的测试和评审。

所以,把它放在一起,拉请求就是你让 GitHub 执行那些动作的请求:拉你的补丁分支,并把它与另一个分支合并。例如,在我们的项目中,我们目前有三个本地分支(master、develop 和 improve-readme-description)和两个远程分支(master 和 develop)。如果我们作出任何新的承诺,以改善-自述-描述,我们想把它与开发,我们会打开一个公关。在 PR 被接受后,GitHub 将执行以下操作:拉出 improve-readme-description 分支,然后将其与 develop 分支合并。

您可能会问自己:“如果拉请求的最终目的是合并分支,为什么不称之为合并请求呢?”嗯,很多人(包括 GitLab 等其他 Git 托管服务)称之为 Merge Request。意思是一样的。在本书中,我们将交替使用这两个术语。

创建拉取请求

言归正传!创建一个新的公关是非常容易的;你只需要两个分支:一个工作,另一个合并。开始吧!

首先,让我们创建一个要处理的问题。所以去 GitHub,创建一个名为“改善应用风格”的问题是的,我们以前也遇到过类似的问题,但是既然我们已经解决了那个问题,我们将打开一个新的问题。回收问题不是一个好主意,因为这将使你更难跟踪你的进展。

创建问题后,是时候回到终端了,因为每个 PR 都是以分支开始的。我们将从最新的开发分支 develop 中创建一个名为“improve-app-style”的分支。正如我们在上一章中看到的,从另一个分支创建新分支的方法是检出源分支并执行分支创建命令。因此,我们必须一个接一个地执行这些命令:

$ git checkout develop
$ git branch improve-app-style
$ git checkout improve-app-style

执行完这三个命令后,你会发现新的分支被检出,如图 12-2 所示。

img/484631_1_En_12_Fig2_HTML.jpg

图 12-2

创建新的分支机构

在我们新成立的分支机构中,让我们来解决这个问题。打开 index.html 并将其内容替换为

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align:center;
            }
            h3 {
                text-transform: uppercase;
            }
            ul {
                margin: 0;
                padding: 0;
            }
            ul li {
                cursor: pointer;
                position: relative;
                padding: 12px 8px 12px 40px;
                background: #eee;
                font-size: 18px;
                transition: 0.2s;
            }
            ul li:nth-child(odd) {
                background: #f9f9f9;
            }
            ul li:hover {
                background: #ddd;
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

然后,存放文件并准备提交。把非常简单的东西作为提交消息,不需要引用问题;我们以后再做这个。作为一个提交消息,你可以简单地说:“在项目行上添加基本的颜色变化。”像往常一样,在提交之后,您将得到如图 12-3 所示的确认消息。

img/484631_1_En_12_Fig3_HTML.jpg

图 12-3

提交确认

现在该推到 GitHub 了。正如我们之前看到的,我们将不得不使用 git push 命令,后跟远程名称和分支名称。因此,命令将是

$ git push origin improve-app-style

在你把你的分支推送到 GitHub 之后,你会得到另一个熟悉的确认消息。你可以查看图 12-4 中的例子。

img/484631_1_En_12_Fig4_HTML.jpg

图 12-4

将分支推向 GitHub

正如您在确认消息中看到的,Git 直接向您显示一个链接,以便您可以创建一个 Pull 请求。但是让我们用另一种方式来创建一个 PR:直接在 GitHub 上。

转到您的项目页面,在演示文稿中寻找一些不同的东西。在最近推送到一个新的分支后,你的项目页面应该如图 12-5 所示。

img/484631_1_En_12_Fig5_HTML.jpg

图 12-5

最近推送后的项目页面

如您所见,页面上有一个新的行动号召,就在分支列表的上方。它显示了您刚刚创建的分支机构的名称和一个用于创建 PR 的大按钮。单击按钮继续;您应该会看到拉取请求创建表单,如图 12-6 所示。

img/484631_1_En_12_Fig6_HTML.jpg

图 12-6

拉取请求创建表单

您可以注意到,PR 创建表单与 issue 创建表单非常相似。在右边,你可以找到关于受托人和标签的相同信息;它们的工作原理完全一样。在页面的底部,您可以看到 Pull 请求所应用的提交;如果你向下滚动,你会发现不同版本之间的差异。查看图 12-7 中的示例。

img/484631_1_En_12_Fig7_HTML.jpg

图 12-7

版本之间的差异

但是您可能会问自己为什么要应用两个提交。是因为目标分支。如果您仔细查看图 12-6 ,您会发现 PR 的基本分支是 master。这不是我们想要的,因为我们的目标是开发分支。去吧,换个基地分支去发展。更改后,页面会重新加载,你会得到不同的结果,如图 12-8 所示。

img/484631_1_En_12_Fig8_HTML.jpg

图 12-8

开发时拉取请求

当您更改它时,请注意 PR 名称也已更改;这是因为 PR 名称将最后一条提交消息作为默认名称。但是如果您愿意,您可以更改它,尤其是如果您在一个 PR 中有多个提交。记住关于 PR 名称的一件事:它应该像提交消息一样清晰、直截了当。你的 PR 名要回应这个问题:“如果我合并了这个 PR 会怎么样?”所以要好好保管你的 PR 名和描述,这样评审人员不用看你的代码就能知道你在试图解决哪个问题。

您可以在“描述”文本框中扩展您的 PR 说明,并毫不犹豫地提供有关变更的更多信息。你应该把结束问题的关键词放在那里。查看图 12-9 中的示例。

img/484631_1_En_12_Fig9_HTML.jpg

图 12-9

已完成的拉取请求

准备好后,点击“创建拉取请求”即可完成;您将到达一个类似于图 12-10 所示的页面。

img/484631_1_En_12_Fig10_HTML.jpg

图 12-10

您的新拉动请求

同样,这个视图与它的 Issues 对应物非常相似,甚至 PR 号跟在 Issues 号后面。唯一的区别是合并拉请求的按钮。如果您点击此按钮,PR 将被接受,并且分支将被合并。但是先别这么做!在合并之前,让我们先玩玩我们的公关。

现在我们的 PR 提交了,是时候审核了!放下你的开发人员帽子,戴上你的技术领导帽子,是时候做代码审查了!

代码审查

代码审查是 GitHub 最好的特性之一。你不得不与你的技术主管安排一次一对一的会议,以便他们能检查你的代码,这样的日子已经一去不复返了。对于代码中的每个变更请求,不需要互相发送长长的电子邮件链(抄送列表上有一长串讨厌的人)。现在,一切都在 GitHub 中完成。让我们看看!

进行代码评审

在图 12-9 中,你可以看到代码评审过程。您看到了与当前版本相比对文件所做的所有更改,但是您还不能与它们进行交互。在本节中,您将学习如何评审您的共同贡献者的代码。

你可以在图 12-10 中看到,公关页面有许多部分,就像问题页面一样。您必须单击“文件已更改”来开始代码审查。然后你将到达一个类似于图 12-11 所示的页面。

img/484631_1_En_12_Fig11_HTML.jpg

图 12-11

代码审查部分

这个视图应该提醒您 git diff 结果,因为本质上是一样的。它向您详细展示了版本之间的差异,这意味着您将看到添加、删除或替换了什么。

留下评论

现在,让我们假装复习这段代码。在代码审查期间,您可以对整个更改或特定的一段代码进行注释。例如,让我们在第 17 行对“ul Li”CSS 定义进行注释。当您在代码评审变更上移动光标时,一个小的“加号”图标会跟随其后。这意味着你可以在那里发表评论。就这么办吧。将光标放在第 17 行,当“加号”图标出现时,单击它。它将打开一个小的评论区,如图 12-12 所示。

img/484631_1_En_12_Fig12_HTML.jpg

图 12-12

一行上的代码审查

和往常一样,您可以借助 Markdown 语法对这一部分进行各种各样的注释。对于这个例子,我们要加上这个注释:“为了一个更干净的 UX,使列表项不可选择。请使用“用户选择:无”你应该在离开评论前检查预览,就像图 12-13 一样。

img/484631_1_En_12_Fig13_HTML.jpg

图 12-13

评论预览

如果您对自己的评论感到满意,请点击“开始评论”进入下一步。评论会显示在评论页面,评论上也会有回复按钮,就像图 12-14 所示的结果。

img/484631_1_En_12_Fig14_HTML.jpg

图 12-14

发布的评论

使用此按钮,开发人员可以在开始修改 PR 之前与审阅者讨论注释。如果您愿意,您可以添加更多的注释,因为注释是构成代码评审的基本要素。如果您满意,请点击页面顶部的“完成您的评估”按钮。您将再次看到一个小部分,如图 12-15 所示。

img/484631_1_En_12_Fig15_HTML.jpg

图 12-15

完成审查

完成审核后,您将有三个选择:评论、批准或请求更改。因为这是我们自己的拉取请求,我们不能批准或请求对它进行更改,所以我们将只选择默认选项,这是对更改的一般反馈。让我们把“不要忘记考虑不同的浏览器”作为评论并提交评论。您将再次返回到 PR 详细信息页面,如图 12-16 所示。

img/484631_1_En_12_Fig16_HTML.jpg

图 12-16

您完成的代码审查

PR 详细信息页面将向您显示审阅者留下的不同评论,以及整个 PR 的一般评论。让我们来解决这些评论。

更新拉取请求

评论者留下的评论建议我们应该在我们的 PR 被接受之前改变一些代码。所以,让我们这样做吧!让我们通过将新的提交推送到修补分支来更新我们的 PR。

注意

修补分支也称为主题分支,因为每个分支都应该有自己的主题要解决。

再次打开 index.html,将其内容更改为:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align:center;
            }
            h3 {
                text-transform: uppercase;
            }
            ul {
                margin: 0;
                padding: 0;
            }
            ul li {
                cursor: pointer;
                position: relative;
                padding: 12px 8px 12px 40px;
                background: #eee;
                font-size: 18px;
                transition: 0.2s;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
            }
            ul li:nth-child(odd) {
                background: #f9f9f9;
            }
            ul li:hover {
                background: #ddd;
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

再次暂存文件,并提交项目,同时显示消息:“使列表项不可选择。”然后,再次将分支推送到 GitHub。如果您在这个练习中迷路了,请查看前面的部分。提示:git push origin improve-app 风格。

推完分支后,再回到 PR 页面。您将在详细信息页面上看到一条新的评论。查看图 12-17 中的示例。

img/484631_1_En_12_Fig17_HTML.jpg

图 12-17

GitHub 检测到的新变化

每次提交后,GitHub 会更新 PR 来反映应用到分支的变更;单击“查看更改”以查看新的更改。您将再次到达代码审查页面,但是有一点小小的变化:您将只注意到新的变化,意味着您还没有看到的变化。这使得审阅者更容易跟踪 PR 的进展。

由于我们没有任何其他意见,请点击“完成审核”,然后给出一般性意见。在工作环境中,您不会审查您自己的代码,因此 Approve 选项是可用的。但是既然我们是单独工作,就给出一个一般性的评价,比如“干得好!”因为开发者真的很努力。与图 12-18 一样,一般意见将出现在 PR 详情页面上。

img/484631_1_En_12_Fig18_HTML.jpg

图 12-18

最后的评论已经完成

现在,我们可以安全地将我们的分支合并到基础分支,因为我们的代码已经过了适当的审查。单击绿色大按钮接受并合并 PR。在分支机构合并之前,您将被要求确认。确认后,分支机构将被合并,采购申请将被关闭。你甚至可以删除源分支,如图 12-19 所示。

img/484631_1_En_12_Fig19_HTML.jpg

图 12-19

接受拉取请求

是否要删除该分支由您决定。有时,团队不会删除分支,直到测试人员确认一切正常。

“但为什么我的问题没有自动关闭?”你问。这是因为开发分支中的修复,而不是默认分支。只有在默认分支(主分支)中合并的修复才会自动关闭问题。但是既然你担心这个问题,让我们在进入下一章之前做一个小练习。

练习:将开发合并到主控形状中

让我们假设一个测试人员测试了我们的新特性,并说可以发布。所以,我们必须把发展融合成大师。这个练习是

  • 返回到项目页面

  • 打开一个 PR 以合并开发

  • 接受 PR 并合并

摘要

祝贺您的第一份 PRs 被接受!(但如果你自己不接受他们,印象会更深刻)。这一章已经很长了,但是你需要完全理解它才能从 GitHub 的强大功能中获益。对于您的下一个问题,打开一个公关,而不是直接提交给主人。请记住,在大多数专业设置中,GitHub 不仅不鼓励在 master 上提交,还默认拒绝提交。每个变更必须来自拉取请求。

现在你应该已经习惯使用公关了;如果没有,重读本章的第一节。要记住的一件事是,拉请求只是请求允许在分支上应用提交的一种奇特方式。

你现在可能会有一些问题:“如果在我完成我的 PR 之前,有人在基础分支中推动了一些更改,该怎么办?”,“如果别人修改了和我一样的文件怎么办?”,或者“如果我在处理一份公关工作时被要求解决另一个问题,该怎么办?”这些问题确实非常中肯;这就是为什么我们将在下一章讨论它们。我们将处理合并冲突以及如何解决它们。但是在学习如何解决它们之前,我们将学习如何完全避免它们!走吧!

十三、冲突

最后一章向我们介绍了合并请求的奇妙世界。你应该知道它们的用途,以及为什么使用它们是个好主意。即使它们是一个很容易掌握的概念,它们也有一些难以忽视的缺点。

你的旅程已经基本结束;你已经走了很长的路。但是在独自继续你的道路之前,你仍然需要学习一些东西。你需要知道在这个过程中你会遇到什么问题。我们将在本章中讨论这些问题。首先,我们将回顾分支机构合并是如何工作的,然后我们将介绍你在职业生涯中最有可能遇到的问题。最后,我们将看到这些问题的通用解决方案。不要害怕冲突,因为它们很容易解决;他们只是很烦人。

合并是如何工作的

让我们倒回去一点,回到基础:合并做什么?合并将分支中的每个提交应用到另一个分支。简单吧?好吧,一个精心策划的合并在大多数情况下进展顺利。但是,即使你计划了每一个细节,也有你无法控制的事情:其他人做什么。

不要忘记 Git 是一个分布式版本控制系统,这意味着每个贡献者都有他们自己的项目副本,并且可以对他们的本地存储库做任何事情。每个人都可以更改每个文件,因为没有像某些 VCS 上那样的“文件锁”。这意味着存在多人对同一个文件进行更改的情况。将所有这些变化结合在一起需要一个合并。

在进入下一节之前,您必须记住一件事:只有当您确定一个分支中的提交是最终提交时,才合并该分支。合并包含未完成工作的分支违背了分支的目的——拥有清晰的历史。即使您不打算实际合并分支,也可以打开一个拉请求;但实际上合并它们并不完整。

如前所述,合并是从分支开始的。大多数时候,它是一个本地存储库中还没有的分支。因此,您必须从 origin(远程存储库的默认名称)中提取它。

让我们第二次修改拉动命令。拉意味着将远程分支复制到本地存储库。例如,我们已经将一个分支合并到 develop 和 master 中,但是没有对我们的本地分支做任何事情。这意味着我们在历史时间线中“落后”,因为在远程存储库中有我们没有的提交。

事实上,“背后”这个词有点用词不当,因为正如我们所建立的,每个存储库都是独立的,Git 中没有中央存储库。我们选择有一个主远程存储库,因为它使团队工作更容易。但是,具体地说,你可以随意交换提交;“落后”这个概念的发明只是为了让开发者的生活更轻松。

让我们试着将 master 拉入我们的本地存储库。请记住,在进行本章的后续步骤之前,您需要完成上一章的练习(将 develop 合并到 master 中)。首先,检查你当地的总分行,确保它是干净的。

$ git checkout master
$ git status

如果你没有在你的工作目录上做任何有趣的事情,你应该得到如图 13-1 所示的结果:一个干净的目录。

img/484631_1_En_13_Fig1_HTML.jpg

图 13-1

在拉入之前,需要一个干净的目录

现在,让我们在进行任何更改之前检查一下历史日志。

$ git log --online

这将导致主分支机构历史记录的输出。它不会有我们最近所做的更改,因为那些更改现在只在远程存储库中。主历史日志应该如图 13-2 所示。

img/484631_1_En_13_Fig2_HTML.jpg

图 13-2

拉入前的历史日志

正如你在图 13-2 中所看到的,头部现在指向分支的最后一次提交(大部分时间都是这样)。根据这个结果,我们的本地主分支和远程主分支处于相同的级别,这意味着它们包含相同的提交。我们知道这不是真的,因为我们已经在远程主机上做了更改。我们的本地 Git 存储库不知道这一点,因为我们还没有从服务器获取任何提交。就这么办吧。

正如我们在上一章所看到的,pull 和 push 命令的工作方式是一样的:您只需要将远程存储库名称和远程分支名称作为参数传递。因此,命令将是

$ git pull origin master

在干净的工作目录上执行这段代码后,您将得到如图 13-3 所示的结果。

img/484631_1_En_13_Fig3_HTML.jpg

图 13-3

从原点拉主控形状

快进合并

当你把师父从原点拉出来后,你会得到一个操作摘要。您将看到已更改的文件数量和已完成的合并类型。这里的类型是“快进”,这是最简单的合并类型。快进意味着远程分支上的提交与本地分支在同一时间线上,所以 Git 只需移动到源分支的最后一次提交。还记得我们讨论过通过父子关系将提交链接到另一个提交吗?如果 Git 发现第一个分支上的提交和要合并的分支之间有链接,就会进行快速合并,这意味着只需要移动指针,这使得 Git 非常快。您应该始终努力使用快进作为合并的方法,因为它更容易,最重要的是,对历史日志来说最干净。

谈到历史日志,让我们检查一下它,看看我们从服务器获取的更改。再次使用“- oneline”选项来获得更好的结果。

$ git log --oneline

这将给出如图 13-4 所示的结果。

img/484631_1_En_13_Fig4_HTML.jpg

图 13-4

从原点提取后的历史日志

你有额外的承诺!来自远程分支的提交被合并到本地分支中。现在,您的本地主分支指向与原始分支相同的提交。

让我们把这些都打开。首先说一下树枝颜色。绿色分支是您的本地分支,而红色分支是远程分支。Remote 也有两个名称,因为它们的名称与远程存储库名称结合在一起。

可以看到,improve-readme-description,developer,origin/developer 在同一个层次上。我们知道这是不正确的,因为我们从 GitHub 改变了 develop。Git 不会知道发生了变化,直到您从原点拉出 develop 分支。

您会注意到在这个历史中有一些您没有提交的请求,即“来自 mtsitoara/improve-app-style 的合并请求#8”和“来自 mtsitoara/develop 的合并请求#9”它们被称为合并提交,由 Git 在合并两个或更多提交时创建。在我们的项目中,我们将 improve-app-style 合并为 develop,然后 develop 成为 master。这些合并中的每一个都会产生一个合并提交。

就像普通的提交一样,您可以使用 git show 命令显示关于它的更多信息。让我们展示第一个合并提交。

$ git show 33753ec

这将产生一个我们熟悉的视图:提交英特尔视图。您应该会得到如图 13-5 所示的相同结果。

img/484631_1_En_13_Fig5_HTML.jpg

图 13-5

合并提交的详细视图

这个视图并不特别有趣,因为它只显示了执行合并的提交父对象和用户。但是,有一点要记住,提交者和合并者可能是不同的人。您应该将解决问题的关键字放在合并提交消息中,而不是提交消息中。大多数时候,提交不足以解决问题;因此,将这些关键字放入“拉”请求消息中,这样只有在分支机构合并后,问题才会关闭。

图 13-4 中显示的历史日志很漂亮,但是它并没有真正显示分支和合并的概念。图形可能更合适,git log 命令中有一个参数。参数是"- graph ",您应该将它与"- oneline "一起使用,以获得最佳结果。

$ git log --oneline --graph

该命令将生成如图 13-6 所示的简单图形。

img/484631_1_En_13_Fig6_HTML.jpg

图 13-6

我们项目的历史图表

如您所见,日志图提供了我们项目的更详细的历史。一如既往,每个星号代表一次提交。但是在这张图上出现了一种新的元素类型:分支。你可以看到,我们从主分支中分支出来,创建了开发分支,开发分支又分成了改进应用风格的分支。我们对那个分支进行了两次提交,然后将它合并回去进行开发。之后,我们把 develop 合并成 master。

当您处理一个使用许多分支并经常合并的项目时(正如您应该做的),最好使用图表视图,因为它比传统视图更清晰。还有,颜色很好看。

为了获得更清晰的历史日志,我建议您删除本地的 improve-readme-description 分支。

$ git branch -D improve-readme-description

删除已经合并的分支几乎没有风险;但是许多开发人员并不经常这样做,以防以后需要返工。大多数时候,这种情况不会发生。一个很好的经验法则是,只有当你确定不需要再次签出来测试某个东西时,才删除分支。

我们在这里做的是最简单的合并形式:快进。但是请记住,在您从一个分支分叉之后(就像我们在 master 和 develop 上所做的那样),您就处于一个完全独立的区域。除非你向其他分支机构询问,否则你不会从他们那里得到任何更新。这也意味着其他分支将独立于您的分支进行评估。当您对分支发出拉请求时,它可能已经改变了。例如,多个贡献者可以开发新的分支,并致力于他们自己的问题。他们不会在同一时间完成,所以每个公关将被一个接一个地接受。这就是麻烦开始的地方:当你处理你的问题时,你的目标分支会在你的影响之外改变。当你完成你的改变时,你正在处理的现实可能会改变。可能多个人在各自的分支机构中更改了相同的文件。这在你的职业生涯中会经常发生,很多时候,一个公关不会像我们在本章中做的那样好。这些问题被称为“冲突”,解决这些问题对您的 Git 之旅至关重要。开始吧!

合并冲突

理解合并冲突的最好方法是创建一个合并冲突。所以,让我们搞砸我们的项目吧!首先,看看我们当地的发展分支。因为我们没有碰过这个树枝,所以它现在应该还是干净的。

$ git checkout develop

我们要做的第一件事是检查历史日志。

$ git log --oneline --graph

你会得到和以前一样的结果,因为我们还没有从原点出发。该结果如图 13-7 所示。

img/484631_1_En_13_Fig7_HTML.jpg

图 13-7

在拉取之前开发历史日志

这里没什么特别的,只是一根没有任何问题的旧木头。因为我们删除了 improve-readme-description 分支,所以开发历史日志中没有留下任何分支。

日志显示 develop 和 origin/develop 处于相同的状态;但这不是真的,因为我们是从 GitHub 改过来的。但是,我们不是从原点出发,而是首先在我们的分支中进行变更,这些变更会导致与原点的变更发生冲突。

打开 index.html 并用以下代码替换其内容:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align: left;
            }
            h3 {
                text-transform: capitalize;
            }
            li {
                overflow: hidden;
                padding: 22px 0;
                border-bottom: 2px solid #eee;
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

运行 git diff 来检查您的更改。我们只是做了些小改动,所以没什么大不了的,对吗?

$ git diff

这个结果对我们来说非常熟悉,因为我们在 GitHub 和 git show 上经常看到它。你的结果应该和我的一样,如图 13-8 所示。

img/484631_1_En_13_Fig8_HTML.jpg

图 13-8

开发目录和工作目录的区别

这里没什么新鲜的。让我们将更改后的文件添加到临时区域,然后提交当前项目。

$ git add index.html

小费

为每次提交打开文本编辑器是否令人厌烦?嗯,如果你赶时间的话可以跳过。要在跳过提交消息编辑阶段的同时提交项目,可以将提交消息作为参数传递:

$ git commit -m "<commit_message>"
Don't forget the `-m`!

$ git commit -m "Change CSS to introduce conflicts"

警告

使用 git commit 命令的简写形式可能会节省您几秒钟的时间,但是它更容易出错,因为您在提交之前没有机会检查您的更改。我强烈建议只在只有一个更改过的文件时使用它。另外,您不能用它来编写多行提交消息。

这不会产生任何我们没有见过的结果。正如你在图 13-9 中看到的,我们得到一个标准结果,因为还没有冲突。

img/484631_1_En_13_Fig9_HTML.jpg

图 13-9

将引入冲突的提交

为了产生冲突,我们需要在将分支合并到开发中时得到我们推进的提交。

从原点提取提交

我们已经看到了运行中的 pull 命令,但是,在这个场景中,我们会遇到一个小问题:我们在不同的提交中更改了同一个文件。这将产生冲突,我们必须在您完成拉动之前解决这些冲突。请记住,拉仅仅意味着将远程提交复制到您的本地存储库中。

先从原点直接拉 develop 开始吧。同样,该命令非常类似于 push 命令。您只需要远程存储库和分支名称。

$ git pull origin develop

我们得到的结果与我们之前看到的完全不同。我们得到的不是一个完整动作的结果,而是一个冲突,我们被困在两个状态之间。您可以查看图 13-10 中的示例。

img/484631_1_En_13_Fig10_HTML.jpg

图 13-10

执行 pull 命令时发生合并冲突

让我们一个一个的解开这个结果。首先,我们有用于拉取的 URL,所以这里没什么特别的。

接下来,Git 执行第一个动作。这个动作叫做“fetch”,它的作用是将选择的分支从远程复制到本地存储库中。然后,这个分支被存储到一个名为 FETCH_HEAD 的临时存储器中。就像 HEAD 是对我们正在处理的最后一个提交的引用一样,FETCH_HEAD 引用我们刚刚从 origin 获取的分支的顶端。

下一个动作是基本的合并,就像我们之前看到的一样。我们获取了远程分支,现在是时候将它与当前分支合并了。该操作详述了要执行的合并:分支 develop 和 origin/develop。它甚至指定了将要使用的提交。您的提交名称会有所不同,但是要验证第一次提交,您只需检查提交日志:

$ git log --oneline

您将在倒数第二个提交上找到提交名称,如图 13-11 所示。

img/484631_1_En_13_Fig11_HTML.jpg

图 13-11

倒数第二个提交将用于合并

请注意,合并不会使用最后一次提交,因为它是我们正在处理的提交,是引入了更改的提交。

图 13-10 也引用了合并的另一个提交,你可以在 origin/develop 上找到那个提交。转到 GitHub 上的项目页面,选择 develop 分支,查看远程分支的历史日志。你也可以通过 GitHub 链接直接访问,比如 https://github.com/mtsitoara/todo-list/commits/develop 。您将看到最后一次提交,如图 13-12 所示。

img/484631_1_En_13_Fig12_HTML.jpg

图 13-12

关于起源/开发的提交

如你所见,图 13-10 中引用的第二次提交是远程分支的最后一次提交,它是由我们之前在 GitHub 上的合并创建的。要获得更多信息,您可以单击它并获得提交的详细信息。查看图 13-13 中的示例。

img/484631_1_En_13_Fig13_HTML.jpg

图 13-13

有关合并提交的更多信息

在图 13-13 中可以看到,这个提交有两个父级;这是因为它是由两个分支的合并创建的提交。你还可以看到,图 13-10 中也引用了其中一个父节点,因为这是我们在 GitHub 上合并分支之前最后一次提交的。

让我们回到图 13-10 。在结果的下一部分,Git 试图“自动合并”分支,这意味着它试图自动合并分支。当不同的文件或文件的不同部分被分支改变为合并时,这可以顺利进行。但是由于发现了冲突,合并失败了。这要靠我们来解决。

Git 试图将我们的本地 develop 分支与 FETCH_HEAD 合并,但是由于两个分支都包含对 index.html 相同部分的更改,您必须决定保留哪些更改。我们将在下一节中看到如何做到这一点。

从图 13-10 中应该注意的最后一个信息是我们的本地存储库所处的状态。如果你观察控制台的左边部分,你会发现存储库处于“develop|merging”状态,而不是标准的“develop”分支。这意味着项目中仍然有未解决的冲突,合并(以及,通过扩展,拉)还没有完成。您可以检查状态,以了解关于存储库当前状态的更多信息。

$ git status

这会让你得到一个我们之前没有见过的新结果,如图 13-14 所示。

img/484631_1_En_13_Fig14_HTML.jpg

图 13-14

合并的状态

这个结果非常容易阅读,并为接下来的步骤提供了很好的建议。首先,它告诉我们接下来应该做的事情:解决冲突并提交项目。然后,它告诉我们如果我们决定退出冲突,中止当前合并的方法。在许多情况下,这是一个好主意,因为我们可以在本地分支工作,以解决我们知道会出现的冲突。例如,我们可以中止这个合并,恢复引入冲突的提交,然后再拉一次。然后我们将有一个没有任何冲突的自动合并。但是这对我们来说太简单太合理了,所以,让我们来点硬的吧!

接下来,我们有一个合并所涉及的文件列表。这里只涉及 index.html,并且在两个分支中都进行了修改。让我们打开它来看看冲突。如图 13-15 和图 13-16 所示。

img/484631_1_En_13_Fig16_HTML.jpg

图 13-16

维姆的 index.html

img/484631_1_En_13_Fig15_HTML.jpg

图 13-15

Visual Studio 代码中的 index.html

你会注意到文件中有三大行分隔你的代码。在每个代码冲突中,这些行总是相同的,但是不同的文本编辑器可能会呈现不同的内容。例如,像 Visual Studio 代码这样的 IDE 会用不同的颜色渲染代码,甚至会添加一些按钮来与代码进行交互(如图 13-15 )。相比之下,一个非常简单的文本编辑器会将代码行显示为普通的代码行,可能会打乱您的配色方案。在图 13-16 中,我使用了 Vim,没有任何额外的工具,所以渲染有点平淡无奇;但是很多插件可以用来修复这个。

解决合并冲突

让我们从解释这三行是什么意思开始。“<<<<<<> > > > > >”线划定了有冲突的区域。请记住,一个文件可以有多个冲突区域。

这些区域由“=======”行分隔,显示了两个分支的代码。第一部分是您当前分支上的代码;第二部分是您试图合并的分支上的代码。

所以,我们的文件里有两个相互冲突的代码。第一个是关于开发的代码,第二个是关于起源/开发的代码。要解决合并冲突,我们必须编辑文件,使其只有一个变更集。这并不意味着你必须在两个变更集中做出选择,只是意味着最后只能剩下一个;如果需要,您可以合并它们。

在我们的情况下,最好保留第二部分的大部分内容,因为我们已经审查并接受了这些更改。但也有一些东西我们可以从第一部分保留下来。因此,最好的做法是从第一部分复制我们需要的代码,并将其复制到第二部分。代码将变成

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align: left;
            }
            h3 {
                text-transform: capitalize;
            }
<<<<<<< HEAD
            li {
                overflow: hidden;
                padding: 22px 0;
                border-bottom: 2px solid #eee;
=======
            ul {
                margin: 0;
                padding: 0;
            }
            ul li {
                cursor: pointer;
                position: relative;
                padding: 12px 8px 12px 40px;
                background: #eee;
                font-size: 18px;
                transition: 0.2s;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
                overflow: hidden;
            }
            ul li:nth-child(odd) {
                background: #f9f9f9;
            }
            ul li:hover {
                background: #ddd;
>>>>>>> 33753ecaebae2ba1c3ffdc1e543d372385884c78
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

如你所见,我们只复制了第一部分的一行,因为第二部分已经快完成了。现在是清理文件中不必要部分的时候了。首先,我们可以删除代码冲突的第一部分(在<<<<<<< and =======) because we don’t need them anymore. Then we can just remove the remaining line (>> > > > > >之间),因为它不再有意义了。该文件将变成

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <style>
            h1 {
                text-align: left;
            }
            h3 {
                text-transform: capitalize;
            }
            ul {
                margin: 0;
                padding: 0;
            }
            ul li {
                cursor: pointer;
                position: relative;
                padding: 12px 8px 12px 40px;
                background: #eee;
                font-size: 18px;
                transition: 0.2s;
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
                overflow: hidden;
            }
            ul li:nth-child(odd) {
                background: #f9f9f9;
            }
            ul li:hover {
                background: #ddd;
            }
        </style>
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

文件恢复正常!合并冲突代码,不再有那三条大线。现在,您可以继续合并过程。如果您忘记了下一步,您可以再次运行 git status(或者检查图 13-14 )。

现在,文件已经准备好了,我们必须转移它。

$ git add index.html

之后,您必须像往常一样提交项目。

$ git commit

您将会看到熟悉的提交消息视图,但是有一点小小的变化:提交消息已经编写好了。查看图 13-17 中的示例。

img/484631_1_En_13_Fig17_HTML.jpg

图 13-17

默认提交消息

当然,您可以随时修改提交消息,但是我建议保留默认消息,除非您遵循个人或公司的指导原则。您可以保存提交消息并继续。

如果你查看命令结果(如图 13-18 所示),你会看到你回到了开发分支,不再处于“合并”状态。

img/484631_1_En_13_Fig18_HTML.jpg

图 13-18

回到正常状态

您还可以通过检查历史日志来检查合并是否已经完成。确保添加图形选项以获得漂亮的结果。

$ git log --oneline --graph

这将产生如图 13-19 所示的惊人视觉效果。

img/484631_1_En_13_Fig19_HTML.jpg

图 13-19

我们项目的近期历史

您可以在图中看到,当我们合并 origin/developer 分支时,我们导入了它的所有历史。所以,看起来我们有一个分支的分支。在大型 Git 项目中,这种情况经常发生。

摘要

这是这本书最大的一章。祝贺你到达那里!我们看到了如何从远程服务器获取代码,以及当相同的代码区域被两个不同的分支修改时如何解决冲突。

关于拉取的主要要点是,它实际上是两个相继执行的命令:

  • 获取,将远程分支复制到临时分支

  • 合并,将临时分支合并到当前分支

但是当两个分支包含相同代码的编辑时,合并有时会引发冲突。要解决这些冲突,您必须重新打开相关的文件,并决定保留哪个代码。然后,剩下的就是基本的了:准备和提交。

合并冲突是令人讨厌的事情之一,但不幸的是,在你的职业生涯中会发生很多,所以了解它们很重要。既然他们很讨厌,我们将在下一章学习如何减少他们的出现。坚持住!

十四、关于冲突的更多信息

最后一章很紧张,不是吗?我们讨论了什么是合并冲突以及它们何时会发生。我们还了解了如何手动解决这些问题。别担心,这一章会容易消化很多。我们将讨论如何在合并冲突后将分支推到远程。此外,我们还将看到一些可以用来减少可能发生的冲突的策略。走吧!

推动冲突的解决

正如我们在前面章节中看到的,推送意味着将本地提交复制到远程分支。这意味着我们在本地的每一次提交都将被应用到远程存储库。

我们在上一节中看到,拉操作只是一个接一个执行的两个操作:将远程分支复制到临时位置的获取操作和将临时分支合并到本地分支的合并操作。因为拉和推的动作是一样的,但是方向不同,所以把本地分支推到原点的方式是一样的。

因此,推送操作也分为两个部分:将本地分支复制到远程分支,以及分支的合并。push 和 pull 动作之间的唯一区别只是哪个参与者执行动作的问题:您还是服务器。

在正常情况下,推送会顺利进行,因为合并是使用“快进”自动执行的当本地分支上的提交可以与远程分支上的提交直接链接时,快进是可能的。例如,简单地在我们的主分支上一个接一个地添加提交(就像我们到目前为止所做的那样),然后推送它们会产生一个快速前进的合并,不需要创建一个合并提交。

在我们的情况下,这也会发生,因为我们只在我们的开发分支上添加了新的提交。我们不会有任何问题,除非我们或其他人回到过去,改变历史。千万不要尝试这样做。

也就是说,让我们使用通常的命令来推进我们的开发分支。

$ git push origin develop

正如所料,我们将得到如图 14-1 所示的通常结果。

img/484631_1_En_14_Fig1_HTML.jpg

图 14-1

推动我们的发展分支

总之,在提取和合并变更之后将分支推回到原点不应该导致意外的行为。除非有人改变了历史。

合并前检查更改

在尝试任何合并之前,您要做的最重要的事情是检查您的分支将引入的所有更改。这是一个不应该被忽略的关键步骤,因为它将节省您与 Git 斗争的无数时间。

检查分支位置

你首先要确定的是你的位置。若要将两个分支合并在一起,您必须签出目标分支。例如,如果您打算将 develop 合并到 master 中,您将需要首先检查后者。因此,代码应该是(现在不要实际执行第二个命令):

$ git checkout master
$ git merge develop

审查分支差异

审查差异不仅仅是提交的专利!您还可以使用它来检查两个分支之间的差异,这在合并这样的微妙情况下非常方便。这个命令相当简单:

$ git diff branch1..branch2

注意两个分支名称之间的两个点。这将在一个熟悉的 diff 视图中显示两个分支之间的差异。让我们比较一下开发人员和硕士:

$ git diff master..develop

比较提交时,结果与我们的 diff 结果非常相似。查看图 14-2 中的示例。

img/484631_1_En_14_Fig2_HTML.jpg

图 14-2

分支之间的差异

如果你做了很多修改,不想滚动太多,你也可以在 GitHub 上查看这些修改。就推分支,开一个拉请求!

了解合并

我们已经看到了许多关于 Git 合并的概念,但是让我们回顾一下,以便更清楚地了解这个特性。正如我们前面看到的,合并是将两个分支合并的行为,或者更准确地说,是将一个分支注入另一个分支。

分支可以由任何其他分支形成,当一个分支被创建后,它将独立于其父分支。在合并之前,对任何一个分支所做的更改都不会影响到另一个分支。

让我们想象这样一种情况,您创建了一个子分支,并在这个新分支上提交。当合并的时候,会出现几种情况。

如果父分支没有改变(没有提交)并且您试图合并,将会发生“快进”合并。“快进”合并在技术上不是合并,而只是 Git 中的引用更改。请记住,Git 提交的行为类似于链表,这意味着一个提交包含对前一个提交的引用。事实上,如果父分支没有改变,Git 只是将对父分支的引用向前移动(遵循链表),子分支中的最后一次提交成为父分支的最后一次提交。简单地说,Git 只是将子分支中的提交追加到父分支中。这是最简单的“合并”类型,但也是最不常见的,除非你独自工作。

相反,如果父分支已被更改(接收到提交),则不能进行快速合并。将要发生的被称为“真正的合并”或“三方合并”这就是我们上一章看到的合并类型。这种类型的合并将创建一个新的提交,它包含子分支中的所有更改,并将该提交附加到父分支。这个提交被称为“合并提交”,它有两个父分支:父分支和子分支。如果来自父分支和子分支的不同提交修改了同一行代码,就会出现冲突,开发人员必须手动选择保留哪些更改。

因此,合并只是创建包含子分支中所有更改的提交并将其附加到父分支的一种奇特方式。清楚地了解这一点非常重要,这样我们就可以减少合并冲突的频率。

减少冲突

我们在上一章中看到,解决冲突可能会很痛苦,而且根据冲突的大小,可能会花费很多时间。因此,将它们的出现减少到最低限度对我们是有益的。在这一节中,我们将看到限制冲突的策略。

拥有良好的工作流程

如果你使用一个好的工作流程,你在 Git 和 GitHub 中会遇到的大多数问题都是可以避免的。在前面的章节中我们已经看到了最常见的 Git 工作流,但是让我们再回顾一下。

要记住的第一件事是不要直接承诺你的主要分支。简单来说:你打算引入到你的主或者开发分支的每一个改变都应该通过合并来完成。并且每个合并必须由一个拉请求引入。这样,你可以在工作的时候收到反馈。它也给测试人员一个更好的方法来跟踪项目变更。即使你独自工作,你也应该总是使用 PRs 来引入主要分支的变化。这将提供一个比简单的提交消息更清晰的项目历史日志。

每个拉取请求都应该以解决问题为目标。因此,一个公关应该只做一件事,无论是一个 bug 修复,一个特性提案,还是文档变更。不要试图用一个公关来解决几个问题。无所不能的拉请求是合并冲突的完美配方。

开发人员经常忽略的一点是行尾和文件格式。正如我们在第二章看到的,不同的操作系统使用不同的行尾。你的团队有必要讨论每个项目用哪些;大多数团队使用 Unix 风格的行尾,所以 Windows 用户应该相应地配置他们的 Git 客户端。至于格式,这取决于您的团队,但唯一的规则是,您必须对缩进和换行符使用相同的格式。

警告

当讨论制表符和空格时,事情可能会变得激烈。提前准备好你的论点。

中止合并

许多合并冲突不是来自代码冲突;许多将来自格式和空白差异。例如,即使代码没有更改,尾随的回车空格或缩进空格的数量也会引起冲突。

当遇到这种冲突时,最好的办法就是中止合并,恢复格式差异,然后再次尝试合并。正如您在前面看到的,中止合并的命令是

$ git merge --abort

这不会破坏你的任何提交,它只会取消合并,你会停留在你当前的状态。

使用可视化 Git 工具

当使用简单的文本编辑器时,可能很难解决冲突,因为大多数时候,它会打乱代码的配色方案。一个简单的解决方案是使用专门的 Git 工具。它们可以是专门为 Git 开发的 IDE 扩展或工具。让我们在下一章发现它们!

摘要

这一章简单地提醒了我们什么是合并以及如何使用它们。我们看到了各种类型的 Git 合并以及它们可能出现的情况。我们还回顾了合并是如何工作的,目标是什么:将提交从一个分支转移到另一个分支。

要记住的主要事情是减少合并冲突的各种方法。你可能永远也摆脱不了它们,但是遵循这些建议会让它们的出现降到最低。

在我们的 Git 之旅中,我们已经取得了很大的进步,但是我们是使用我们简单而乏味的控制台完成的。是时候在我们的 Git 项目中加入更多的色彩了,所以让我们来学习一下 Git GUIs 吧!

十五、Git 图形用户界面工具

在前面的章节中,我们已经看到了很多最重要的 Git 特性和概念。我们已经学习了提交、分支、拉请求和合并。使用这些概念,您已经可以在 Git 中完成几乎任何事情。不过,只有一个小问题:我们只使用了终端或控制台窗口。在这一章中,你不会学到任何新概念或新特性;你将学习如何运用你已经知道的☺风格

首先,我们将研究 Git 附带的默认工具,然后学习更多关于集成 Git 的 ide,最后看一些专门为 Git 制作的工具。

默认工具

如果您已经按照第二章中的安装步骤进行了操作,那么您的计算机上已经安装了这些工具。如果没有,你可以很容易地在我们常用的软件商店里找到它们。Git 附带了这些默认工具,为用户提供了非常简单的 GUI 来浏览他们的存储库和准备提交。它们几乎适用于任何操作系统,所以不要担心,它们对您都适用。它们在本书中出现是出于历史原因,也因为它们内置于 Git 中。

提交:git-gui

我们将要看到的第一个工具叫做 git-gui,它是 git 的图形化提交界面。您将使用它来提交您的项目并审查提议的更改。你可以在 https://git-scm.com/docs/git-gui 上找到更多关于它的信息。

您可以像打开 Git Bash 一样打开它:通过命令行、上下文菜单或起始页。选择最适合你的选项。在基于 Windows 和 Debian 的操作系统上,您可以通过导航到存储库的目录并右键单击空白区域来打开 Git GUI。这样做会给你一个类似于图 15-1 的结果。

img/484631_1_En_15_Fig1_HTML.jpg

图 15-1

Windows 上下文菜单

如您所见,您可以在那里打开 Git GUI 和 Git Bash。继续并选择 Git GUI。你会看到一个小程序窗口,详细说明你当前的工作目录状态。该窗口如图 15-2 所示。

img/484631_1_En_15_Fig2_HTML.jpg

图 15-2

Git GUI 界面

如果您不想使用上下文菜单或者不能使用,您可以通过在 Git 存储库的位置打开一个终端并执行以下命令来打开它:

$ git gui

Git GUI 界面非常轻量级和直观;每个操作系统都一样,所以每个人都有宾至如归的感觉。它分为四个部分:

  • 左上角是尚未暂存的已编辑文件列表。

  • 左下角是已转移的文件列表。

  • 右上方是一个不同的视图。

  • 右下角是提交消息文本区域。

由于我们没有改变项目中的任何内容,所以所有内容都是空的。所以,让我们用额外的提交来打乱我们的项目。

首先,让我们确保我们在主分支中,然后从它创建一个新分支。转到“分支”菜单,选择“结帐…”;这将打开如图 15-3 所示的选择窗口。

img/484631_1_En_15_Fig3_HTML.jpg

图 15-3

选择要签出的分支

您会注意到,当您的光标悬停在某个分支上时,会出现关于其上次提交的信息。它将帮助您找到正确的分支机构,但如果您有一个好的分支机构名称,就没有必要了。签出主分支,然后通过选择“分支”菜单上的“创建…”来创建一个新分支。你将得到如图 15-4 所示的分支创建窗口。

img/484631_1_En_15_Fig4_HTML.jpg

图 15-4

创建新的分支机构

第一个输入区域是最重要的:新分行的名称。将该分支命名为“分离代码和样式”

第二个输入是一个选择输入,您必须选择从哪里创建分支。在我们的情况下,我们将从本地主分支创建一个新分支;所以选择“本地分支”,选择“主”

第三部分是选项,我建议保留默认选项。使用默认选项,Git 将获取远程(跟踪)分支上的最新提交,然后签出新分支。

现在,您可以单击“创建”来查看结果。您将会看到左上角的小消息框现在将“单独的代码和样式”列为当前分支。为了让您看得更清楚,下面是我们刚才所做的命令等价物:

$ git checkout master
$ git branch -b separate-code-and-styles

现在我们进入了正确的分支,我们可以继续我们的提交了。还记得我们讨论 Git 工作流时的黄金法则吗?每次提交都必须以解决某个问题为目标。我会让你创造这个问题。

练习:创建一个问题

转到 GitHub 问题。

创建一个名为“分离代码和样式”的问题

记下发行号。

现在我们准备好提交了!在存储库中创建一个名为“style.css”的新文件,并粘贴以下代码:

h1 {
    text-align:center;
}
h3 {
    text-transform: uppercase;
}
ul {
    margin: 0;
    padding: 0;
}
ul li {
    cursor: pointer;
    position: relative;
    padding: 12px 8px 12px 40px;
    background: #eee;
    font-size: 18px;
    transition: 0.2s;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
ul li:nth-child(odd) {
    background: #f9f9f9;
}
ul li:hover {
    background: #ddd;
}

然后,打开“index.html ”,将其内容更改为

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>TODO list</title>
        <link rel="stylesheet" href="style.css" />
    </head>
    <body>
        <h1>TODO list</h1>

        <h3>Todo</h3>
        <ul>
            <li>Buy a hat for the bat</li>
            <li>Clear the fogs for the frogs</li>
            <li>Bring a box to the fox</li>
        </ul>

        <h3>Done</h3>
        <ul>
            <li>Put the mittens on the kittens</li>
        </ul>
    </body>
</html>

保存这两个文件,让我们跳到 Git GUI 来查看结果。你会看到…没什么新鲜的!因为 Git GUI 还不知道我们的更改。单击提交消息框附近的“重新扫描”以查看更改;您将得到如图 15-5 所示的结果。

img/484631_1_En_15_Fig5_HTML.jpg

图 15-5

Git GUI 中显示的更改

现在我们有了我们的改变!您可以在 Git GUI 的左上方看到修改过的文件列表,这里是未登台的文件。您会注意到这些文件有不同的图标:

  • 新文件的空文件图标(从未提交)

  • 已修改文件的文件图标(以前是提交的一部分)

  • 一个"?"已删除文件的图标(以前是提交的一部分)

那景色没有让你想起什么吗?嗯,当然是状态视图了!单击“重新扫描”等同于在终端上执行以下命令:

$ git status

在这里,我们修改了“index.html”并创建了“style.css .”如果您单击文件名(不是图标;先不要点击图标),您将会看到 diff 视图的变化。查看图 15-6 中点击 style.css 后的结果示例。

img/484631_1_En_15_Fig6_HTML.jpg

图 15-6

新创建的 style.css 文件的差异

这肯定比执行“git diff”要快!此外,如果你有很多修改过的文件,看起来更容易。因此,单击文件名相当于执行以下命令:

$ git diff index.html
$ git diff style.css

现在是准备提交文件的时候了。暂存和取消暂存文件非常简单:你只需点击它的图标。或者,您也可以选择要暂存的文件(通过单击其名称),然后在“提交”菜单中选择“暂存以提交”。单击文件图标等同于执行以下命令:

$ git add index.html style.css
$ git reset HEAD index.html
$ git reset HEAD style.css

看到了吗?比输入命令要快得多!

我们终于可以提交我们的项目了!但是首先,确保您创建或修改的所有文件都是暂存的,这意味着它们位于左下部分。然后,您可以在 Git GUI 的右下部分编写提交消息,如图 15-7 所示。

img/484631_1_En_15_Fig7_HTML.jpg

图 15-7

提交消息的写入

现在,我们的文件已暂存,提交消息已写入,我们准备好提交了。只需单击提交消息框旁边的“提交”按钮。这样做之后,Git GUI 回到正常的空状态。我们已经通过图形工具提交了!

因此,单击“提交”按钮会产生与此命令相同的结果:

$ git commit -m "Move style code to external file"

既然你是我最好的学生(不要告诉其他人),我就让你在我们支部再干一次。

练习:再次提交

打开 README.md。

在文件末尾添加这一行:“许可证:麻省理工学院。”

创建名为 LICENSE 的新文件。

https://choosealicense.com/licenses/mit/ 中的许可文本复制到许可文件中。

暂存这两个文件。

提交并显示消息“添加 mit 许可证”

哦!现在您的新分支上有两个提交,是时候将它们推送到远程存储库了。您肯定已经猜到了要单击哪个按钮;是“推”点击它将得到图 15-8 中的结果。

img/484631_1_En_15_Fig8_HTML.jpg

图 15-8

推树枝

这是一个简单的界面;你只需要选择你要推的分支和你要推的位置。

默认选择当前分支,所以我们不需要做任何改变。第二部分是目的地选择下拉列表;同样,我们不需要做任何更改,因为我们只有一个远程存储库。暂时忽略这些选项;我们将在后面的章节中看到它们。

点击推送推送!如果你使用 HTTPS 认证来连接 GitHub,你将被要求输入你的 GitHub 用户名和密码,然后得到如图 15-9 所示的结果。

img/484631_1_En_15_Fig9_HTML.jpg

图 15-9

推送结果

小费

如果不想每次推送都写密码,可以缓存或者使用 SSL 认证;所有这些将在后面的章节中解释。

这里没有什么新东西,我们得到了与这个命令相同的结果:

$ git push origin separate-code-and-styles

练习:创建拉取请求

跟着推送后得到的链接走。

使用以下描述创建一个拉取请求:“修复#10”(用您之前创建的问题编号替换该编号)。

合并公关。

欢欣鼓舞。

这就是使用 Git GUI 提交的方式!简单吧?而且非常快。这是一个很棒的工具,可以在审查提交时节省您很多时间。谈到提交,让我们看看另一个默认工具!

浏览:gitk

在上一节中,我们讨论了很多关于创建和推送提交的内容。现在,我们将这些提交在它们的自然环境中可视化:存储库。gitk 是一个简单的工具,可以简单地查看您的项目历史。你可以把它想象成一个强大的“git log”命令。更多关于 gitk 的文档可以在 https://git-scm.com/docs/gitk 上找到。

既然已经打开了 git-gui,那就用它来打开 gitk 吧。只需从“存储库”菜单中选择“可视化所有分支历史”。这样做会打开 gitk,你会看到如图 15-10 所示的窗口。

img/484631_1_En_15_Fig10_HTML.jpg

图 15-10

gitk 介面

在窗口的顶部,您会发现来自所有分支的所有项目提交的列表。它呈现在一个漂亮的图形视图中,您可以使用以下命令在控制台上再现它:

$ git log --oneline --graph

您可以单击提交以获得有关它们的更多信息。选择提交将更新窗口底部的视图。左下角也是一个不同的视图,但是有一点不同:你也可以选择查看文件的旧版本或新版本。右下部分是提交中更改的所有文件的列表。您可以单击它们来查看 diff 视图上的更改。单击提交相当于执行以下代码:

$ git show <commit_name>

Git 的默认浏览工具 gitk 就是这样!既然您现在可以使用默认的图形工具提交和浏览,那么是时候向您展示其他工具了。

IDE 工具

正如我们在上一节中看到的,与在控制台中输入相比,使用图形工具提交非常快。但是仍然有一个问题:您必须离开您的集成开发环境才能使用它们。如果您可以直接从编辑器中使用图形工具,那不是很好吗?

对很多现代编辑来说这是可能的。我将向您介绍两个集成了 Git 的流行 ide,以便您可以在未来的开发中使用它们。如果你不想使用它们,或者你已经爱上了你当前的编辑器,如果足够现代的话,你的 IDE 也可以集成 Git 工具或插件。每个 IDE 都有自己的界面和用户体验,所以在这一节我就不赘述了。我只是想展示一下有哪些功能可用。

Visual Studio 代码

一个非常流行的编辑器,Visual Studio Code,是微软支持的轻量级 IDE 你可以在 https://code.visualstudio.com/ 上找到它。它是新的,所以它集成了所有闪亮的新玩具;Git 是其中的核心。你可以在图 15-11 中看到 VS 代码的观感。

img/484631_1_En_15_Fig11_HTML.jpg

图 15-11

Visual Studio 代码

它与任何其他 IDE 具有相同的接口,但是有一点额外的好处:你可以到处看到 Git 的痕迹。第一,如果你更改了一个被跟踪的文件(此处为 README.md),被编辑的部分会高亮显示;再也不需要执行 git diff 了!

并且在窗口的左下方,你有当前的分支名称;如果单击它,可以选择要导航到的分支或创建新分支。如果您有未分级的文件,在您的分支名称旁边会有一个小小的“⊙”符号,在相关的文件名旁边会有一个“M”图标。如果您已暂存未提交的推送文件,您会看到一个“+”号。

点击源代码控制图标进入 Git 选项卡,如图 15-12 所示。

img/484631_1_En_15_Fig12_HTML.jpg

图 15-12

源代码管理视图

这个视图的外观和工作方式非常像 git-gui,所以我将让您自己去发现它!

原子

Atom 是 GitHub 推出的 IDE,也是开发人员非常喜欢的选择。你可以在 https://atom.io/ 上查看。你可以在图 15-13 中看到它的界面。

img/484631_1_En_15_Fig13_HTML.jpg

图 15-13

原子界面

它具有与 Visual Studio 代码相同的 Git 特性,但稍有改动:您可以将您的 GitHub 帐户链接到它,并直接从编辑器中创建 PR!同样,我会让你发现。

专用工具

我们看到了默认的 Git 工具和一些集成了 Git 的 ide。现在,我们来看一些专门为 Git 开发的工具。

GitHub 台式机

如果你喜欢默认的 gitk 和 git-gui 工具,但讨厌它们的界面,GitHub Desktop 是你的完美工具。让我们面对它,默认的工具是伟大的,但他们的外观在现代感觉很奇怪。GitHub 桌面(在 https://desktop.github.com/ 上找到)已经被创造出来取代那些工具;它把它们所有的功能都集成在一个软件中。GitHub 桌面界面可以查看图 15-14 。

img/484631_1_En_15_Fig14_HTML.jpg

图 15-14

GitHub 台式机

基特克拉肯

GitKraken 是 Axolosoft 创建的 Git 客户端,越来越受欢迎。你可以在它的网站 www.gitkraken.com/ 上得到它。它比所有其他工具都更先进,因为它的目标是提高开发人员的生产力。它甚至有一个集成的代码编辑器!你可以在图 15-15 中看到它的界面。

img/484631_1_En_15_Fig15_HTML.jpg

图 15-15

gitkraken 概览

同样,界面和其他的一样,但是让 GitKraken 与众不同的是它的美丽:美得令人疯狂!

摘要

这一章很有趣,不是吗?我们学到了很多关于如何使用图形工具来提交和浏览它们的知识。我们还发现了大量可供我们使用的新工具,无论是集成到 IDE 中的工具还是专用工具。我们怎么能忘记我们的旧默认工具呢?!

你可能会问自己为什么不从一开始就使用图形工具?这是因为在不了解工具背后的概念的情况下使用工具会适得其反,而且是浪费时间。相信我,学习使用终端是值得的!谈到终端,让我们回到更高级的 Git 命令!