Git 和 Github 入门指南(三)
十六、高级 Git
上一章,我们学习了如何在图形环境中实现基本的 Git 特性。现在,让我们来看看更多的 Git 命令,这些命令您不会像其他命令一样经常使用,但是对于更好的工作效率来说是强大而必要的。这些都是非常容易学习的命令,如果您在使用 Git 时犯了错误,这些命令将对您非常有用。
我们将会看到一些你在使用 Git 几次后肯定会遇到的常见问题。然后我们将看到解决它们的最简单的方法。这是一个非常简单的章节,但是我们将学习一些强大的 Git 特性。
恢复
在前面的章节中,我们已经看到了如何恢复提交。但是大多数时候,您想要做的只是将单个文件恢复到以前的状态。这通常发生在当你编码了一段时间后才意识到你的整个策略是错误的时候。与其敲 Cmd-Z 几百次,不如还原文件。
您可能已经知道如何做到这一点,因为 git 会在您检查 Git 状态后告诉您如何做到这一点。首先,让我们打开 README.md,然后在其中添加一些文本。
# TODO list
A simple app to manage your daily tasks.
It uses HTML5 and CSS3.
## Features
* List of daily tasks
* Pretty colors
License: MIT
现在,让我们看看状态。
$ git status
像往常一样,您将看到您的存储库的状态(如图 16-1 所示)。
图 16-1
更改文件后的 Git 状态
这里没有什么新内容,但是请注意修改后的文件上面显示的指令。如您所见,将文件恢复到以前的状态只是意味着将其签出。命令是这样的
$ git checkout -- <file>
此命令将放弃您对特定文件所做的任何更改。使用时要小心,不要擦除有价值的代码。使用 GUI 可能会更好,这样您就可以在丢弃它们之前快速获得当前更改的详细视图。让我们用下面的命令尝试放弃对 README.md 的更改。
$ git checkout –- README.md
您不会从这个命令得到任何响应,但是如果您再次检查 git 状态,您会看到 README.md 回到了它以前的状态。
隐藏
很多时候,您想要在分支之间导航,但是因为您的工作目录是脏的而不能。在这种情况下,脏意味着您有未提交的已更改文件,无论它们处于已修改或暂存状态。改变分支的唯一方法是首先提交它们。但是大多数时候,你还没有准备好做出承诺,因为手头的问题还没有解决。
对此的一个解决方案是进行临时提交,改变分支,处理它,然后返回并修改临时提交。这种方法有很多问题:首先,当您提交时,您的工作目录将是干净的,这意味着您不再知道哪些文件被更改了。第二,这是一个简单的肮脏和丑陋的方法。这并不是创建 amend 命令的原因。
理想的解决方案是使用一种叫做“隐藏”的技术 Stashing 意味着将任何修改过的跟踪文件放在工作目录中,并放在一边以备后用。这意味着您将拥有一个干净的目录,并且可以在您的存储库中导航,而不必提交您的更改。这些变化存储在一个叫做“stash”的小数据库中。您可以将 stash 看作是未完成提交的临时存储库。它被设计成一个后进先出的数据库,这意味着你最后保存的更改将首先呈现给你。理解它的最好方法是尝试。所以,让我们再次更改我们的 README.md 文件。
# TODO list
A simple app to manage your daily tasks.
It uses HTML5 and CSS3.
## Features
* List of daily tasks
* Pretty colors
License: MIT
如果检查状态,您会看到 README.md 已被修改,但未转移。你会得到与先前相同的结果(图 16-1 )。
现在让我们假设当你在处理这个问题的时候,有一个紧急的问题需要你的关注。显然,您现在不能检查主分支,因为您的工作目录是脏的,并且您不能恢复您当前的更改,因为您还没有完全完成。解决方案是把你当前的修改藏在某个地方,这样你就可以有一个干净的目录来工作。为此,您必须使用 stash 命令,这非常简单:
$ git stash push
注意
仅仅使用命令“git stash”和使用“git stash push”是一样的。建议使用完整命令,因为它更直观,更容易理解。
这个命令将获取您修改过的文件,暂存它们,并在存储中创建一个临时提交,保持您的工作目录干净。试试看,你会得到如图 16-2 所示的结果。
图 16-2
粉碎当前的变化
如您所见,您隐藏的更改被赋予了名称和描述,就像常规提交一样。这很正常,因为 stash 只是一个只有一个分支的临时存储库。如果您检查存储库状态,您将得到一个干净的工作目录(如图 16-3 所示);你最终可以导航到其他分支。
图 16-3
存储推送产生一个干净的工作目录
因此,将改变放入存储库可以给你更多的行动自由,而不会丢失你当前的工作。在快节奏的开发中非常有用。
警告
即使这不是一本关于生产力的书,这里有一个小提示:如果你发现自己在问题之间来回跳跃,当然你的问题是你的优先事项,同时解决两个问题会花费你宝贵的时间。
由于 stash 只是一个小型存储库,因此您可以在其上执行大多数 Git 特性,比如检查历史日志或获得详细的变更视图。让我们探索一下藏毒之处,以便更好地了解它。首先,让我们使用 stash list 命令显示历史日志。
$ git stash list
这将为您提供一个熟悉但简化的历史日志视图,如图 16-4 所示。
图 16-4
隐藏的更改列表
正如我们前面所说的,这个数据库是基于后进先出的,所以如果我们对我们的工作目录做了其他的修改并保存了它们,它们将会出现在我们当前保存的目录之上。
你会注意到在图 16-4 中,每个贮藏都有一个数字。这种方式更容易与它们交互,不像提交时必须用名字来称呼它们。让我们通过使用命令 stash show 来查看我们隐藏的变更的详细视图。
$ git stash show
这个简单的命令将向您显示在存储区顶端更改的文件,这意味着最后的更改被推送到存储区。查看图 16-5 中的示例。
图 16-5
藏毒点的详细视图
stash show 命令只会向您显示包含在 stash 中的变更的描述,而不会显示其他内容。要查看更改,您必须应用存储。应用存储非常简单:只需执行下面的命令。
$ git stash pop
该命令将获取存储中的最新更改,并将其应用到当前分支。顾名思义,弹出更改会将它们从存储中取出。所以,如果你的储物袋里只有一套零钱,那么在你掏出小费后,它就会是空的。如果您执行前面的命令,您得到的结果将与您重新创建更改然后检查状态的结果相同(如图 16-6 所示)。
图 16-6
弹出最后一组更改
我们又回到了起点!但是,如果我们愿意,我们可以改变分支,提交,或推到原点,而不会丢失我们宝贵的变化。当您想将当前的更改放在一边,以便在其他地方进行快速更改时,隐藏特别有用。根据经验,如果您需要使用不止一组隐藏的变更,那么您的工作流就有问题。
重复定位
我希望你不要经常使用这个功能,因为它的破坏性很大!有时,你想放弃你所做的一切,重新开始工作,即使你已经提交了你的项目。为了更好地理解它,让我们创建一个提交,然后丢弃它。
在 README.md 上做一些修改,进行 stage,然后提交项目,如图 16-7 所示。
图 16-7
向项目添加错误的提交
为了正确理解这一点,让我们使用 git log 命令在提交之后检查当前的历史日志。
$ git log --oneline
该命令将显示该分支上的最新提交,如图 16-8 所示。
图 16-8
当前分支的历史日志
如您所见,我们的最新提交位于日志的顶部。注意,HEAD 引用指向它;这意味着我们的下一个提交(或分支)将该提交作为父提交。您还会注意到,远程分支来源/分离代码和样式没有改变;那是因为我们的项目还没推。
但是让我们想象一下,你对上一次提交完全不满意,想重做一次。然后,您唯一的选择是将分支重置回之前的状态。为了重置项目,我们使用 git reset 命令,后跟要重置到的项目状态。您必须使用选项"- hard "来实现这一点,因为这是一个非常危险的命令。例如,返回到与远程分支相同的状态将需要以下命令:
$ git reset --hard origin/separate-code-and-styles
此命令将删除所有内容,以便项目可以恢复到以前的状态。见图 16-9 其结果。
图 16-9
重置后项目的状态
由于“- hard”选项会覆盖其路径上的所有内容,因此在目标状态之后所做的提交、当前更改和暂存文件都将被删除。这是 Git 中最危险的命令,在使用之前应该仔细考虑。
复位只能在万不得已的情况下进行。如果可能的话,最好恢复提交,或者直接继续在新的分支上工作。如果使用不慎,重置可能会破坏您的数据。
摘要
这一章讨论了 Git 的一些高级概念,当你面对某些情况时,这些概念会对你有用。您需要使用 reset 来轻松地将文件恢复到以前的状态;当然,您也可以使用 GUI 恢复这些更改。如果你需要快速改变环境,藏起来也会非常有用。最后,硬复位是一个非常强大的功能,非常具有破坏性;不要,除非你没有其他选择。
我们关于高级 Git 命令的课程到此结束。现在让我们回到 GitHub,来发现更多可以帮助我们进行项目管理的特性。
十七、更多关于 GitHub 的信息
在前几章中,我们已经看到了几乎每一个你每天都会用到的 Git 特性。现在,让我们把目光转向 GitHub,它直到现在还只是一个代码托管站点。但是我们已经确定 GitHub 远不止于此。您可以使用它来托管项目文档和托管软件版本。您还将主要使用它作为项目管理工具和与合作者联系的方式。让我们来了解一下这些特性。
维基百科
你的项目可能是同类项目中最好的,但是如果其他人不知道如何使用它或如何工作,你将一事无成。这就是为什么文档很重要,尤其是在软件开发中。GitHub 提供了一个很好的方法来记录你的项目:wikis。
GitHub wikis 的工作方式与世界上最流行的 wiki: Wikipedia 基本相同。它的目标是提供关于你的项目的深入信息:它是做什么的,它是如何工作的,有人如何贡献…
让我们为我们的项目创建一个 wiki 页面,这样我们可以更好地理解它。只需进入你的项目主页,点击“wiki”;您将到达图 17-1 所示的页面。
图 17-1
Wiki 主页
你会在 wiki 主页上看到一个大的行动按钮,点击它创建你的第一个 wiki 页面。您将到达页面创建页面,如图 17-2 所示。
图 17-2
页面的创建
如您所见,这是一个非常简单的视图,分为三个部分:标题、内容和编辑消息。把标题想象成一个网页标题,所以它必须遵循同样的标准:它必须是清晰的、吸引人的。内容应该以 Markdown 格式编写,就像 README.md 一样。你可以选择以其他格式编写维基,但 Markdown 是推荐的选择,因为许多编辑已经在使用它,它更容易阅读。编辑消息就像提交消息一样,是对您提议的更改的简单描述。
更改您的维基中的内容;这里有一个例子:
# What is this
This is a simple app to track your daily goals
# Why another TODO app
Because that is never enough TODO apps in the world
# How does it work
Open `index.html` and update the goals as you wish
# How can I contribute to the project
You can contribute by forking the project and proposing Pull Requests. Check [Issues](https://github.com/mtsitoara/issues) to see the current areas that need help
保存更改,您将被重定向到 wiki 主页,如图 17-3 所示。
图 17-3
显示新创建的维基的维基主页
如您所见,您刚刚创建的 wiki 在您的项目页面上自动可见,并且您创建的每个页面将出现在右侧的侧边栏上。
你可以想做多少维基页面就做多少,但要确保它们是可理解的和有用的;别忘了添加图片和相关链接!
github pages-github 页面
简而言之,GitHub Pages 是一个在 GitHub 上为你托管的网站。你可以用它来展示一个项目,管理你的作品集,或者只是把它作为你简历的在线版本。
GitHub 页面可以是你的个人账户(作品集和简历),也可以是你的项目(展示)。如果你决定使用它作为你的帐户,你只能创建一个页面;但是如果是为了您的项目展示,您可以为其中任何一个项目创建一个页面。你可以查看 https://pages.github.com/ 以获得更好的解释。
让我们假设您想要创建一个页面来展示您的待办事项列表项目。首先,你需要回到你的项目页面,点击“设置”;您将进入图 17-4 所示的页面。
图 17-4
设置页面
向下滚动到页面设置,如图 17-5 所示。
图 17-5
GitHub 页面设置
第一个选项是包含页面源位置的下拉列表。您必须在主分支上承载您的页面,但是您有两个位置来存放源文件。一个是直接上 master 另一个在 master 上一个名为“docs”的目录下。我推荐第二种选择,因为它对任何访问者来说都更清晰。然后,我们必须首先创建该目录。
使用 GitHub 或 Git 工具,在 docs 目录下创建一个名为 index.html 的文件。在文件中,只需编写一些基本的 HTML:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Docs</title>
</head>
<body>
<h1>Docs</h1>
<p>Example of documentation</p>
</body>
</html>
这将是你的文件。因此你的主树枝必须看起来像我的,如图 17-6 所示。
图 17-6
文档文件夹和 index.html
然后,我们可以返回到设置页面,并选择文档的来源。选择 docs 文件夹作为源,页面将重新加载并显示如图 17-7 所示的链接。
图 17-7
页面已发布
如果你点击显示给你的链接,你会看到你的 GitHub 项目页面的壮丽景色!可能性是无限的,因为你可以像设计任何其他静态网站页面一样设计你的页面!如果想要更好的风格,勾选https://jekyllrb.com/;它可以帮助您立即生成 GitHub 页面!
小费
由于你的项目是一个静态的 HTML 页面,你可以指向它作为你的页面的位置;你会得到它的实时版本!
放
您的项目不会无限期地处于开发阶段;它迟早会被释放。还有什么平台比 GitHub 更适合发布你的应用呢?这很容易。
再次返回到您的项目页面,然后单击“发布”;您将看到如图 17-8 所示的主页面。
图 17-8
发布页面
让我们创建我们的第一个版本!点击行动号召按钮,您将看到发布创建视图,如图 17-9 所示。
图 17-9
发布创建表单
这是一个非常容易填写的表格,因为各个部分简单明了。要做的主要事情是通过将发布的二进制文件放到前面的表单上来上传它们。因为我们的应用是 HTML 格式的,所以让我们附上 master 分支的压缩版本。对于可安装的应用,它将是一个要执行的二进制文件;对于我们来说,它将是 zip 和 7z 文件。如果需要的话,不要忘记改变发布的目标。默认选项是主分支,但是您可以指向另一个分支或特定的提交!该表单将与图 17-10 所示的表单相同。
图 17-10
用二进制文件填充的发布表单
单击“发布”查看结果。您将被重定向回发布列表,并在那里看到您的新版本!查看图 17-11 中的示例。
图 17-11
所有版本的列表
如您所见,GitHub 也自动将源代码捆绑到您的发行版中!创建发布时要小心;务必正确测试和重新测试一切!
项目板
项目板是 GitHub 的一个非常有用的特性,因为它提供了一种跟踪和组织项目的方法。例如,您可以为您的任何新想法创建卡片,以便稍后与您的团队讨论。但是项目板的主要用途是跟踪项目的进展。它超越了问题,因为问题仅仅描述了一个特性或者一个需要解决的 bug 但是 Project Board 可以告诉你是否有人正在做,或者只是一个要执行的计划。
理解项目板的最好方法是直接用它们做实验。所以回到你的项目页面,选择“项目”您将得到如图 17-12 所示的空项目。
图 17-12
项目主页
项目主页仍然是空的,因为我们还没有创建任何项目。它还向您展示了您想要使用项目板的不同情况。单击“创建项目”继续;您将获得如图 17-13 所示的视图。
图 17-13
项目的创建
同样,这是一个非常简单的形式。但是请注意模板:它非常重要。作为初学者,你应该使用基本的看板模板,因为它是一个预填充的模板。您可以选择自己创建板,但现在,让我们坚持基础。创建项目,您将会看到如图 17-14 所示的半空板。
图 17-14
新项目已创建
如你所见,创建了三块板:“待办事项”、“进行中”和“完成”就像我们的 app 一样!在屏幕右侧,您可以看到我们未解决问题的列表。将这些问题拖放到各自的板上。在“待办事项”板上,你有一个你可以用你的板子做什么的小例子;它不仅适用于问题,也适用于拉取请求或简单的注释。在你把你的问题放在想要的板上后,你会得到如图 17-15 所示的结果。
图 17-15
我们的第一个项目板
一点小奖励:当你在棋盘上移动问题时,项目名称附近的彩色条会改变。这是一个跟踪你进步的好方法!
但是项目板不仅仅是一个项目进度追踪器!您可以为许多情况创建项目板:发布跟踪、会议记录、开发人员想法记录、用户反馈……您可以在图 17-16 中找到本书的项目板,您也可以在 https://github.com/mariot/boky/projects/1 上找到。
图 17-16
本书的当前项目板
我建议你在未来的项目中使用项目板,因为对自己的进展有一个清晰的认识是通往成功的必由之路。如果你感到无畏,你也可以检查自动看板,它会自动为你移动卡片!例如,每一个新问题将被填入“待办事项”下,而每一个已关闭的问题将被移至“已完成”
摘要
这一章让我们暂时离开 Git,把注意力放在 GitHub 上。我们已经看到 GitHub 不仅仅是一个代码存储库,而是一个管理和发布项目的完整工具。读完这一章后,你应该能够设计一个迷你网站,并拥有一些文档。你也应该有你的应用的第一个版本。
前面展示的最重要的特性是项目板。用它们来清楚地了解你做了什么,你要去哪里。它们看似简单,但在项目管理中非常有用。
您现在已经掌握了 Git 和 GitHub 的基础知识。但是在你的道路上仍然有障碍:你仍然不确定在真实世界的环境中等待着你的是什么。在下一章,我们将探讨你在与他人合作时肯定会面临的问题以及如何解决它们。敬请关注!
十八、常见的 Git 问题
自从我们的第一个 Git 命令以来,我们已经取得了很大的进步!我们已经了解了很多关于基本和高级 Git 特性以及何时使用它们的知识。但是因为我们只是人类,所以在我们的 Git 之旅中我们会面临很多问题。大多数这些问题都是由于疏忽造成的,所以意识到它们的存在就是朝着避免它们前进了一大步。但是如果你仍然碰到他们,这里有最好的解决方案!
贮藏室ˌ仓库
存储库是您 Git 体验的支柱;一切都在那里开始和结束。很难把事情搞砸,但是万一有不好的事情发生,这里有一些建议。
重新开始
这是本章中最激进的“解决方案”,我希望你永远不要使用它。这个解决方案基本上是删除一切,重新开始!只有当您有一个远程存储库,并且出于某种原因想要删除您的本地存储库时,这才应该是一个选项。这样做的原因包括
-
更换工作电脑
-
硬盘中不可读的扇区
-
中不可恢复的错误。git”目录
要重新开始,您只需要用 git clone 命令克隆远程存储库:
$ git clone <repository_location>
存储库位置是到您的远程存储库的 HTTPS 或 SSH 链接;您可以在您的 GitHub 项目页面上找到它。
克隆与初始化存储库的效果相同,但是有一个很大的好处:所有的历史和提交都将被复制到新的本地存储库中。你不再需要精确的原始链接。
改变原点
在正常情况下,您会希望在整个开发过程中保持远程存储库的 URL 不变。但是在某些情况下有必要改变它:
-
在 HTTPS 和 SSH 链接之间切换
-
将存储库转移到另一台主机
-
添加用于发布或测试的专用存储库
首先,让我们获得更多关于我们当前遥控器的信息。为此,使用带有“-v”选项的 git remote 命令。
$ git remote -v
这会给你一个当前遥控器的列表,如图 18-1 所示。
图 18-1
当前遥控器列表
这里,我们只有一个指向 GitHub HTTPS 链接的远程“起点”。要修改此链接,您需要使用 set-url 子命令:
$ git remote set-url <remote_name> <remote_url>
例如,如果我想切换到 SSH 而不是 HTTPS 来访问 GitHub,我会执行
$ git remote set-url origin git@github.com:mtsitoara/todo-list.git
这样做将允许我在不提供用户名和密码的情况下在 GitHub 之间进行推/拉操作。认证将通过两组密钥来完成:一个我保存在本地计算机上的私钥和一个我必须上传到 GitHub 的公钥。如果您对使用 SSH 进行身份验证感兴趣,请根据您的操作系统( https://help.github.com/en/articles/which-remote-url-should-i-use )前往 GitHub 帮助获取更多信息。如果您决定继续使用 HTTPS,但要缓存什么作为密码,这样您就不必总是键入密码,您可以使用凭据帮助器。同样,GitHub 帮助上有更多关于这个的信息,这取决于你的操作系统( https://help.github.com/en/articles/caching-your-github-password-in-git )。
警告
如果您更改了您的远程名称,不要忘记为每个推拉动作使用新名称。
工作目录
您将花费大部分时间在工作目录上,这里也没有太多东西可以破坏。
Git diff 为空
这种情况经常出现,但并不危险。有时,您做了很多更改,并希望检查这些更改。但是当运行 git diff 时,结果是空的。别慌!Git diff 只显示修改过的文件,所以如果你的文件是暂存的,你不会在那里看到它。要查看对暂存文件所做的更改,您必须运行:
$ git diff --staged
小费
在审查变更时,使用 GUI 工具会给你很大的帮助。
撤消对文件的更改
当您使用 Git 时,这将会经常出现。有时,您只想将文件恢复到其以前的状态,而不必签出整个提交,然后复制粘贴代码。我们已经在前面看到过这个命令:
$ git checkout <commit_name> -- <file_name>
该命令将按照提交时的样子签出文件,因此将更改您的工作目录。小心不要丢失任何未提交的更改!
承诺
当你试图提交你当前的项目时,大多数问题都会出现。但是不要担心,对于这类问题总有一个简单的解决方案。要考虑的最重要的事情是:你正在使用的命令是破坏性的吗?像 reset 或 check out 这样的命令会改变你的工作目录,所以在执行它们之前,请确保你知道你在做什么。
提交时出错
这是 Git 中的一个基本错误。在您提交您的努力工作之后,您有时会注意到一个小小的语法错误出现在您的提交消息中,或者您忘记上传一个文件。这些问题的解决方案是修改提交,这意味着您将取消立即提交并进行新的提交。命令很简单:
$ git commit --amend
提交名称将会改变,因为您基本上是在改变它的内容。这就是为什么您不应该修改已经推送到远程分支的提交,尤其是如果有人在那个分支上工作。这是在改写历史,你绝对不应该这么做。
也就是说,如果您已经提交了提交,并且单独在分支上,您可以修改提交并尝试再次提交。但是由于 commit 的名字改变了,Git 不会允许你不战而降地改变历史。您必须清除远程分支上的所有历史记录,并用您的历史记录替换,这意味着您将覆盖远程分支上的所有内容。这就是为什么如果你不是单独在一个分支上,就不应该修改提交。要使用修改的提交来推送分支,您需要强制它。
$ git push <remote_name> <branch_name> -f
“-f”选项强制 Git 覆盖远程分支上的所有内容,并用您当前的分支历史替换它。
警告
在别人工作的地方重写历史是非常粗鲁和自私的。别这么做。
只有当您想要修改提交消息或添加/删除文件时,才应该使用修改提交。不要修改提交更改代码。
撤消提交
如果您提交了一个分支,但随后意识到它是错误的,您可以撤销它,但只有当您没有推送到远程分支时。
这个命令很简单但是很危险:它是 reset 命令。但是与清除所有内容的“硬”重置相反,“软”重置是撤销提交但保留更改所必需的。
$ git reset HEAD~ --soft
然后提交将会消失,留给您一些选项来隐藏更改并将它们应用到另一个分支。
同样,这是在重写历史,如果您已经推送到一个远程分支,就不应该使用它。
分支
您将需要与分支机构合作很多,以优化工作流程。当处理一个新的特性或者 bug 时,你的第一反应应该是创建一个分支。但是你对分支越熟悉,你就越有可能忘记一个可能导致问题的小细节。以下是您在使用 Git 时会遇到的最常见的问题。
分离头
HEAD 是对当前签出提交的引用,意味着您将创建的任何未来提交的父提交。通常,HEAD 指向当前分支的最后一次提交;并且所有将来的分支和提交都将它作为父级。
当您签出分支时,头将在分支的最后一次提交之间来回移动。但是当你检查一个特定的提交时,你进入了一个被称为“分离头”的状态,这意味着你将创建的任何东西都不会被附加到任何东西上。在那种状态下尝试提交是没有用的,因为任何改变都会丢失。
Git 会告诉你什么时候你处于那种状态(如图 18-2 ),这样你就不会不知不觉地处于那种状态。
图 18-2
检查提交
因此,只有在软件上测试某些东西时,才需要检查提交。但是,如果您希望保留您打算进行的提交,您可以从该特定提交创建一个分支。该命令与从另一个分支创建分支相同:
$ git checkout -b <branch_name>
在错误的分支工作
这种情况经常发生。情况通常是这样的:你接到一个任务,你是如此渴望完成它,以至于你立即开始编码。当你注意到你一直在主分支工作时,你已经工作了一个小时了!别担心,解决这个问题非常简单。
如果您在错误的分支上修改了一些文件,您可以直接创建一个新的分支(并将其签出)以将当前的更改带到那里。又是同一个命令:
$ git checkout -b <branch_name>
这将使用您当前的更改创建一个新的分支,并将其签出。然后,您可以暂存修改后的文件并提交项目。
然而,如果您已经将分支推送到远程存储库,这将不起作用;历史就是历史,不要改变。解决这个问题的唯一方法是改变你所做的承诺,并且带着这种耻辱生活一辈子。
赶上母分公司
当您从另一个分支(通常是主分支)创建一个分支时,它们的历史不再链接,因此在一个分支中发生的事情不会影响到另一个分支。这意味着当您在您的分支上工作时,其他人可以在基础分支上提交;并且这些提交对您的分支不可用。
如果您仍然在您的分支上工作,但是对基础分支上的那些新提交感兴趣,您必须首先有一个干净的盘子,这意味着您必须提交您的项目(或者隐藏您当前的变更)。
然后,您必须签出父分支,提取新的提交,然后回到您的分支。
$ git checkout master
$ git pull origin master
$ git checkout <branch_name>
安全地放在您的本地分支上,然后您可以赶上父分支。概念很简单:Git 将取出您当前的提交,并从父分支的顶端创建新的分支;您的提交将应用到您的新分支。这就像您从主分支的最新提交中创建一个分支。该命令称为 rebase。
$ git rebase master
master 上的提交可能会在您的分支中引入冲突,所以要做好动手的准备。这些合并冲突的解决与我们之前看到的一样:打开每个冲突的文件,选择您想要保留的代码;然后你就可以上演它们并提交。
你可以在图 18-3 中找到一个 rebase 冲突的例子,其中 master 和 test_branch 上的提交都修改了 README.md。
图 18-3
重设基础期间合并冲突
如您所见,这几乎与任何合并冲突完全一样;分辨率是一样的:
$ git add <conflicted_files>
$ git rebase --continue
同样,如果你对冲突没有足够的勇气,你可以中止重置基础并回到初始状态。
$ git rebase --abort
如果你在一个分支上工作了很长时间,不时地调整基础是个好主意,这样你就不会离母分支太远。当然,您可能会面临合并冲突,但是您的变更越大,这些冲突就越有可能出现。如果你因为害怕冲突而延迟重定基础,你只会让自己失败,因为当你试图合并分支时,这些冲突会再次出现。不时地用 rebase 处理小的冲突比在合并时不得不同时合并许多冲突的文件要好。
分支已经分叉
如果您使用的是糟糕的 Git 工作流,就会发生这种情况。正如我们前面所说的,您应该在您自己的分支上工作来解决问题,因为多个人在同一个分支上工作是导致灾难的最佳方法。
我们说,当您由于历史更改而无法再推进到远程分支时,两个分支就会分叉。当您在本地分支上提交时,会发生这种情况,但是其他人已经在您之前在远程分支上提交了他们的提交。到了推的时候,Git 不会让你这么做,因为远程分支的最后一次提交不属于本地历史。您将得到如图 18-4 所示的错误。
图 18-4
拒绝的更改
下面是最明智的解决方案:提取远程分支的提交并合并您的更改。然后,您将在您的历史中记录他们的更改(在解决最终的合并冲突之后),并可以在之后进行推送。
$ git pull origin <branch_name>
$ git push origin <branch_name>
这会给你一个难看的历史日志,但是至少所有的提交都被保存了。这方面的一个例子如图 18-5 所示。
图 18-5
合并本地和远程分支
另一个解决方案更加残酷:覆盖远程分支上的所有内容,并用您的历史替换它的历史。为此,您必须使用“强制”选项进行推送。
$ git push origin <branch_name> -f
这导致提交失败和打斗;永远不要这样做。
同样,如果你使用一个好的 Git 和 GitHub 工作流,这不应该发生。
摘要
这一章是为了在面对常见的 Git 问题时给你指出正确的解决方案。当然,你会发现新的、更难的问题,但这是一个好的开始。要记住的主要事情是,在做任何事情之前,尤其是承诺之前,总是要检查你在哪里。
但是如果你使用通用的 Git 和 GitHub 工作流,这些问题根本不应该出现。所以,让我们在下一章重新发现这一点。我们已经在前面的章节中谈到了这一点,但是在您看到了所有最常用的 Git 和 GitHub 特性之后,是时候回顾一下了。
十九、Git 和 GitHub 工作流程
在前几章中,我们学到了很多,尤其是关于 Git 的技术方面。您现在知道如何正确地版本化您的项目,以及如何处理最终的问题。我们还深入研究了 GitHub 项目管理的基础知识。
现在是时候把所有这些放在一起,为你的项目准备一个完美的游戏计划。在这一章中,你将看到一个精心设计的工作流程,一个成功的项目应该遵循这个流程。您可以将其视为“最佳实践”部分或“操作”指南。
如何使用此工作流程
本章介绍的工作流是为初学者和有经验的用户设计的。它在开源项目中也经常被使用,所以很多开发人员已经在使用它了。请记住,这个工作流程不是一成不变的,它可以在合理的范围内进行调整以满足您的需求。
我的建议是,当你还是一个初学者时,就虔诚地遵循这个工作流程,这样你就可以了解它是如何工作的,以及需要经历哪些仪式。当你感觉有一点经验时,你可以稍微修改一下工作流程,如果这能让你更有效率的话;但永远不要为了时间而牺牲安全。绕过一些惯例可能会为您赢得一些时间,但是如果它导致更多的错误和合并冲突,它将会适得其反。在你使用 Git 和 GitHub 几年后,你会成为它的主人,可以创建自己的工作流,前提是你带来的东西会让你的团队更有效率。
GitHub 工作流程
在使用 GitHub 时,你可能犯的最基本的错误是只把它看作一个代码托管服务,也就是说,仅仅为了在你的合作者之间共享代码或者仅仅为了向用户发布你的产品而使用它。GitHub 是一个如此强大的工具,如果不充分利用它的潜力将是一个巨大的浪费。
将 GitHub 视为您的主要项目管理工具。你打算在项目中做的每一个动作都应该在 GitHub 中被跟踪,这样你就可以回去了解历史。你不能在没有正确记录你为什么要做这些改变的情况下就去做一些改变。以下是 GitHub 的黄金法则。
每个项目都是从一个项目开始的
当您开始一个新项目时,您应该在创建存储库之后立即创建一个 GitHub 项目。你需要尽快这样做,因为使用项目板是追踪你的发展的最好方式。你至少应该有一块看板来跟踪项目的“待办事项”。你还可以使用其他的留言板来跟踪用户的反馈或者整理你的随机想法。最主要的是要把你脑海中的想法写下来,因为你很可能会忘记大部分内容。
每个行动都始于一个问题
问题是记录项目需要做什么的好方法。当您注意到程序中的一个 bug 时,您的第一反应不应该是打开 IDE 来修复它,而是创建一个问题来跟踪它。同样的事情也发生在一个特性的想法上,即使你不确定你是否会在将来从事这项工作。创建一个问题来记录你的意图,如果你决定不执行它,你可以关闭它。
这个仪式意味着您在本地 Git 上所做的一切都应该以解决问题为目标。因此,当您在 IDE 上工作时,您应该总是问自己:“这解决了什么问题?”如果答案是“没有”,你应该为它制造一个问题,不管这个任务有多小。
没有直接推送到 master
这是一个主要的仪式,很难遵循,但对参与项目的每个人来说,这让生活变得容易多了。想法很简单:任何人都不应该直接将提交推送到主分支。向 master 引入更改的唯一方法是将其他分支合并到其中。
这直接意味着您创建的每一个变更都应该包含在它自己的分支中,然后才能合并到 master 中。因此,任何新特性或错误修复都应该从一个分支开始,然后在准备好的时候合并到主目录中。“就绪”意味着经过适当的审查和测试。
任何与 master 的合并都需要公关
既然不能直接推入 master,那么唯一的选择就是把分支合并进去。但是你也不应该盲目的把任何一个分支机构合并成 master。您必须创建拉取请求来提出更改。这样,另一个团队成员可以调查您的代码,以验证是否一切正常。
您应该在 PR 描述中引用 PR 解决的问题编号,这样当 PR 被接受时,问题会自动关闭。
使用维基来记录你的代码
这可能看起来很麻烦,但是这是记录代码的最好方法。README 文件对于完整的代码文档来说是不够的,所以需要 wiki。这似乎是一个巨大的任务,但是最好的方法是在编写代码的同时编写文档。所以,你只需要时不时的写点小改动。如果你等了很长时间才决定写文档,你会不知所措,很可能会忘记关键信息。
Git 工作流
现在让我们来谈谈 Git。到目前为止,您肯定知道 Git 所有最常用的特性;但是在正确的时候使用它们是避免错误(和冲突)的最好方法。
永远知道你在哪里
这是非常基本的,因此很容易忘记。在进行任何更改或执行任何命令之前,您应该始终知道您在哪个分支上。如果您使用的是现代 IDE,您当前的分支应该出现在屏幕的底部。如果没有,没有什么比旧的可靠的 git 状态更好的了!
在任何操作之前提取远程更改
在从远程主分支创建分支之前,先提取它。这将允许你与你的同事保持同步,并且你将避免大多数合并冲突。
当您在本地分支上工作时,您还应该不时地调整基础以接收最新的更新,从而减少将来合并冲突的数量。作为奖励,你的 git 日志图会更漂亮。☺
注意你的提交信息
请参考关于提交的第五章,回顾如何编写一个好的提交消息。不要低估这个过程,因为它将是你的历史日志的支柱。一开始,编写一个错误的提交消息可能会节省您几分钟的时间,但是到了错误修复的时候(相信我,它会来的),您将会浪费无数的时间来搜索引入错误的提交。
不要改写历史
就是不要。这是在团队中使用 Git 时最糟糕的事情之一。如果您更改了一个提交并将其强制推送到一个远程分支,那么对该分支所做的一切都将被您的更改所覆盖。这意味着,如果有人在那个分支上工作,他们将不得不放弃他们所做的一切,并重置他们的本地分支。如果你真的必须做,确保你是唯一一个在那个分支上工作的人。
摘要
这么短的一章!但这是一个成功项目的最佳方式。要记住的主要一点是,GitHub 不仅仅是一个代码托管服务。您应该使用它来正确地跟踪您的项目进展,并跟踪您或您的客户可能有的任何想法。通过遵循这个工作流程,您将会成功,因为您将会避免 Git 和 GitHub 的大多数问题。
您现在拥有了使用 Git 和 GitHub 取得成功的所有工具!现在一切都取决于你的想象力和勇气。正确使用这些工具,你将引导你的项目进入最佳路径。祝你好运!