[译] 怎样(以及为何要)保持你的 Git 提交记录的整洁

怎样(以及为何要)保持你的 Git 提交记录的整洁

Git 提交记录很容易变得混乱不堪,如今教你怎么保持整洁!

提交功能是 Git 仓库的关键部分之一,不只如此,提交信息也是仓库的生命日志。项目或者仓库在随着时间的推移不断演变(新功能不断加入,Bug 被不断修复,体系架构也被重构),提交信息成为了人们查看仓库所发生的变化或者怎么发生变化的地方。所以使用简短精确的提交信息反映出内部的变化是很是重要的。css

为何有意义的提交记录很是重要?

Git 提交信息是你在你所写的代码上所留下的指纹。无论你今天提交了什么代码,一年以后你再看到这个变化;你会很是感谢你所写的有意义的、干净整洁的提交信息,这也会使得你的同事工做更轻松。当根据上下文分开提交时,能够更快地找到 Bug 是在哪一次提交中被引入的,将首先引发 Bug 的此次提交进行回退能够很是简便的修复 Bug。html

当开发大型项目时,咱们常常处理一大堆部件变更,包括更新、添加和移除。在这种场景中确保好好维护提交信息是很艰难的,尤为是当开发周期是数天、数周、甚至数月时。所以为了简化维护提交记录的工做,这篇文章会使用许多开发人员在 Git 仓库上工做时可能会常常遇到的常见场景。前端

可是在咱们深刻了解以前,让咱们快速浏览一下咱们假设的 Ruby 应用程序中典型的开发工做流程。android

注意: 这篇文章默认你已经掌握 Git 基础,分支如何工做,如何将分支的未提交更改添加到暂存区以及如何提交更改。若是你不太熟悉这些流程,咱们的文档是一个好的起点。ios

生活中的某天

如今,咱们正在开发一个小型的 Ruby on Rails 项目,在这个项目中咱们须要在首页添加一个导航视图,这须要更新和添加许多文件。下面是整个流程分解的每一个步骤:git

  • 你开始开发某个功能,更新了一个文件;让咱们称它为 application_controller.rb
  • 这个功能还须要你更新一个视图:index.html.haml
  • 你添加了索引页所使用的一个部分:_navigation.html.haml
  • 为了体现你所添加的那一部分,样式表也须要被更新:styles.css.scss
  • 改完这些模块,功能已经完成了,是时候更新测试文件了;要更新的文件以下:
    • application_controller_spec.rb
    • navigation_spec.rb
  • 测试也更新了,而且如期地经过了全部的测试案例,如今是时候提交更改了!

由于全部的这些文件属于不一样的架构领域,咱们彼此隔离地提交这些文件的更改,以确保每次提交表明了特定的上下文,而且按照特定顺序进行提交。我一般偏向于后端 -> 前端的提交顺序:首先提交之后端为中心的更改,其次提交中间层文件的更改,最后提交之前端为中心的更改。github

  1. application_controller.rb & application_controller_spec.rb添加导航路由
  2. _navigation.html.haml & navigation_spec.rb页面导航视图
  3. index.html.haml渲染导航部分
  4. styles.css.scss为导航添加样式

在提交更改以后,咱们会为分支建立一个合并请求。一旦建立了合并请求,在被合并到仓库的 master 分支以前,一般会由你的同事对代码进行审查。如今咱们了解一下代码审查过程当中可能会遇到的不一样状况。shell

场景 1:我须要修改最近一次的提交

想象一下代码审查者在审查 styles.css.scss 时提出了一个修改建议。这种状况,修改起来很是简单,由于样式表修改是你分支上的最后一次提交。下面是咱们应该怎样处理这种状况:后端

  • 你直接在你的分支上对 styles.css.scss 作必要的修改。
  • 一旦你完成了修改,将这些修改添加到暂存区进行暂存;运行命令 git add styles.css.scss
  • 一旦修改被添加到暂存区,咱们须要将这些修改添加到咱们的最后一次提交;运行命令: git commit --amend
    • 命令分解:这里,咱们使用 git commit 命令修改最近一次提交,把暂存中的任何修改合并到最近一次提交。
  • 这会在你的 Git 定义的文本编辑器中打开你最后一次的提交,它具备提交信息为导航添加样式
  • 由于咱们只更新了 CSS 声明,因此咱们不须要修改提交信息。你能够只作保存而后退出 Git 为你打开的文本编辑器,你的更改会被反映到提交上。

因为你修改了一个已经存在的提交,你须要使用 git push --force-with-lease <remote_name> <branch_name> 命令将这些修改强制推送到你的远程仓库。这个命令会使用咱们本地仓库中所作的修改来覆盖远程仓库中为导航添加样式这个提交。bash

当你强制推送分支时,有一点须要注意,那就是当你所在分支是一个多人协做的分支时,你的强制推送可能会给其余人的正常推送形成麻烦,由于远程分支上有一些强制推送的新的提交。所以,你应该合理地使用这个功能。你能够在这里学习到更多有关 Git 强制推送选项的信息。

场景 2:我须要修改一次特定的提交

在上一个场景中,由于咱们只须要修改最近的一次提交,因此作起来很是简单,可是想象一下若是代码审查者建议修改 _navigation.html.haml 文件中的某些部分。在这种场景下,它是第二次提交,因此修改起来不像第一个场景中那么直接。让咱们看看怎么处理这种状况:

每次在分支上提交更改,都会有一个独一无二的 SHA1 哈希字符串做为更改提交的标志。能够把它看作区分每次提交的独特 ID。能够经过运行 git log 命令查看某个分支上的全部提交以及它们分别的 SHA1 哈希值。运行命令以后,能够看到相似下面的输出,其中最近一次的提交在顶部。

commit aa0a35a867ed2094da60042062e8f3d6000e3952 (HEAD -> add-page-navigation)
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 15:24:02 2018 +0530

    为导航添加样式

commit c22a3fa0c5cdc175f2b8232b9704079d27c619d0
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:52 2018 +0000

    渲染导航部分

commit 4155df1cdc7be01c98b0773497ff65c22ba1549f
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:51 2018 +0000

    页面导航视图

commit 8d74af102941aa0b51e1a35b8ad731284e4b5a20
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:12:20 2018 +0000

    添加导航路由
复制代码

如今轮到 git rebase 命令表演了。无论何时咱们想要用 git rebase 命令修改一个特定的更改提交,咱们首先要将咱们分支的 HEAD 变基到咱们想要修改的更改提交以前。在这个场景中,咱们须要修改页面导航视图的更改提交。

更改提交日志

如今,注意咱们想要修改的更改提交以前的一个更改提交的哈希值;复制这个哈希值而后按照一下步骤进行操做:

  • 经过运行命令 git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20 来将分支变基到咱们要修改的更改提交的前一个更改提交
    • 命令分解:如今咱们正在使用 Git 的 rebase 命令的交互模式,经过提交 SHA1 哈希值咱们能够将分支进变基。
  • 这条命令会运行 Git 变基命令的交互模式,而且会打开文本编辑器展现你所变基到的更改提交以后的全部更改提交。它看起来是这样的:
pick 4155df1cdc7 页面导航视图
pick c22a3fa0c5c 渲染导航部分
pick aa0a35a867e 为导航添加样式

# Rebase 8d74af10294..aa0a35a867e onto 8d74af10294 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
复制代码

注意到每一个更改提交以前都有一个单词 pick,而且在它下面的内容里面,有全部的咱们可使用的关键字。由于咱们想要编辑一个更改提交,因此咱们将命令 pick 4155df1cdc7 页面导航视图 修改成 edit 4155df1cdc7 页面导航视图。保存更改并退出编辑器。

如今你的分支已经被变基到包含 _navigation.html.haml 的更改提交以前了。打开文件并完成每一个审查反馈中的修改需求。一旦你完成了修改,使用命令 git add _navigation.html.haml 将它们暂存起来。

由于咱们已经暂存了这些更改,因此如今应该把分支 HEAD 从新移动到咱们原来的更改提交(同时包含咱们全部的新的更改的提交),运行 git rebase --continue,这将会在终端中打开你的默认编辑器而且向你展现变基期间咱们所作的更改的提交信息;页面导航视图。若是须要你能够修改这个提交信息,但如今咱们保留它,所以接下来保存修改而后退出编辑器。这个时候,Git 会从新展现你刚刚修改的更改提交以后的全部更改提交而且分支的 HEAD 已经回到了咱们原来的全部更改提交的顶部,它包含全部你对其中某个更改提交所作的全部新的更改。

由于咱们又一次修改了远程仓库中的一个提交,咱们须要再次使用 git push --force-with-lease <remote_name> <branch_name> 命令将分支强制提交。

场景 3:我须要添加、移除或者合并提交

一个常见的场景就是当咱们刚刚修改了一些以前的提交并从新提交了一些新的更改。如今让咱们尽量的精简一下这些提交,用原来的提交合并它们。

你所要作的就是像其它场景中所作的那样开始交互性的变基操做。

pick 4155df1cdc7 页面导航视图
pick c22a3fa0c5c 渲染导航部分
pick aa0a35a867e 为导航添加样式
pick 62e858a322 Fix a typo
pick 5c25eb48c8 Ops another fix
pick 7f0718efe9 Fix 2
pick f0ffc19ef7 Argh Another fix!
复制代码

如今假设你想要合并全部的那些提交到 c22a3fa0c5c 渲染导航部分。你只须要作:

  1. 把你想要合并的那些更改提交往上移动,以使得它们位于最终合并的更改提交之下。
  2. 将每个更改提交的模式由 pick 改成 squash 或者 fixup

注意: squash 模式会在描述中保留修改时的信息。而fixup 不会,它只会保留原来的提交信息。

你会如下面这种结果结束实验:

pick 4155df1cdc7 页面导航视图
pick c22a3fa0c5c 渲染导航部分
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e 为导航添加样式
复制代码

保存更改并退出编辑器,你就完成了!这就是完成以后的历史提交记录:

pick 4155df1cdc7 页面导航视图
pick 96373c0bcf 渲染导航部分
pick aa0a35a867e 为导航添加样式
复制代码

像以前同样,你如今所要作的全部工做只是运行 git push --force-with-lease <remote_name> <branch_name> 命令,而后全部的修改都被强制推送了。

若是你想要彻底地移除一个更改提交,而不是 squash 或者 fixup,你只须要输入 drop 或者简单地删除这一行。

避免冲突

为避免发生冲突,请确保您在时间线上上移的提交不会触及其后的提交所触及的相同文件。

pick 4155df1cdc7 页面导航视图
pick c22a3fa0c5c 渲染导航部分
fixup 62e858a322 Fix a typo                 # this changes styles.css
fixup 5c25eb48c8 Ops another fix            # this changes image/logo.svg
fixup 7f0718efe9 Fix 2                      # this changes styles.css
fixup f0ffc19ef7 Argh Another fix!          # this changes styles.css
pick aa0a35a867e 为导航添加样式  # this changes index.html (no conflict)
复制代码

附加提示:快速 fixup

若是你很清楚你想要修改哪个更改提交,在提交更改时没必要浪费脑力思考一些 "Fix 1", "Fix 2", …, "Fix 42" 这样的名字。

步骤 1:初识 --fixup

在你暂存那些更改以后,使用如下命令提交更改:

git commit --fixup c22a3fa0c5c
复制代码

(注意到这个哈希值是属于 c22a3fa0c5c 渲染导航部分这个更改提交的)

这会产生这样的提交信息:fixup! 渲染导航部分

步骤 2:还有这个小伙伴 --autosquash

经过简单的使用交互变基操做。你可让 git 自动的把全部 fixup 放到正确的位置。

git rebase -i 4155df1cdc7 --autosquash

历史提交记录会变成下面这样:

pick 4155df1cdc7 页面导航视图
pick c22a3fa0c5c 渲染导航部分
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e 为导航添加样式
复制代码

一切就绪,你只须要审查并继续。

若是你以为本身喜欢冒险,你能够作一个非交互式的变基 git rebase --autosquash,但前提是你喜欢过这种有风险的生活,由于你没有机会在这些合并应用前检查它们。

场景 4:个人提交记录没啥有用的内容,我须要从新开始!

若是你在开发一个大型的功能,那一般会有许多修复和代码审查反馈的修改频繁的被提交。咱们能够将提交的清理工做留到开发结束,而不是不断从新设计分支。

这是建立补丁文件很是方便的地方。实际上,在开发人员可使用以 Git 为基础的服务好比 GitLab 以前,补丁文件一直是开发大型开源项目经过邮件分享代码与合并代码的主要方式。假设你有一个提交量很是巨大的分支(例如;add-page-navigation),它对于仓库的变动历史表述得不是很清晰。如下是如何为您在此分支中所作的全部更改建立补丁文件:

  • 建立补丁文件的第一步是确保您的分支具备来自 master 分支的全部更改而且与这些更改没有冲突。
  • 您能够在 add-page-navigation 分支中签出时运行 git rebase mastergit merge master,以将全部从 master 进行的更改转移到您的分支上。
  • 如今建立补丁文件;运行 git diff master add-page-navigation > ~/add_page_navigation.patch
    • 命令分解:在这里咱们使用了 Git 的 diff 特性,查询 master 分支和 add-page-navigation 分支之间的差别,而后重定向输出(经过 > 符号)到一个文件,在咱们的用户主目录(在 *nix 系操做系统中一般是 ~/)中命名为 add_page_navigation.patch
  • 你能够指定你想保存这个文件的路径,文件名和扩展名为任意你想要的值。
  • 一旦命令运行而且没有看到任何错误,就会生成补丁文件。
  • 如今签出 master 分支;运行 git checkout master
  • 从本地仓库删除分支 add-page-navigation;运行 git branch -D add-page-navigation。请记住,咱们已经在建立的补丁文件中更改了此分支。
  • 如今建立一个具备相同名称的新分支(master 被签出);运行 git checkout -b add-page-navigation
  • 如今,这是一个新的分支,没有任何你所作的修改。
  • 最后,从修补程序文件中应用您的更改;git apply ~/add_page_navigation.patch
  • 在这里,全部更改都会应用到分支中,而且它们将显示为未提交,就好像您所作的全部修改都完成了,但没有任何修改是在分支中实际提交的。
  • 如今,您能够继续并按照所需顺序提交按影响区域分组的单个文件或文件,并使用简单明了的提交信息。

跟以前的场景同样,咱们修改了整个分支,如今是时候强制推送了!

结论

虽然咱们已经介绍了使用 Git 进行平常工做流程中出现的大多数常见和基本状况,但重写 Git 提交历史是一个巨大的话题,若是你已经熟悉上述建议,您能够在 Git 官方文档。快乐的 git'ing!

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索