- 原文地址:How (and why!) to keep your Git commit history clean
- 原文做者:Kushal Pandya
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:DM.Zhong
- 校对者:Leo Lyu,YiLin Wang
提交功能是 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
application_controller.rb
& application_controller_spec.rb
;添加导航路由。_navigation.html.haml
& navigation_spec.rb
;页面导航视图。index.html.haml
;渲染导航部分。styles.css.scss
;为导航添加样式。在提交更改以后,咱们会为分支建立一个合并请求。一旦建立了合并请求,在被合并到仓库的 master
分支以前,一般会由你的同事对代码进行审查。如今咱们了解一下代码审查过程当中可能会遇到的不一样状况。shell
想象一下代码审查者在审查 styles.css.scss
时提出了一个修改建议。这种状况,修改起来很是简单,由于样式表修改是你分支上的最后一次提交。下面是咱们应该怎样处理这种状况:后端
styles.css.scss
作必要的修改。git add styles.css.scss
。git commit --amend
。
git commit
命令修改最近一次提交,把暂存中的任何修改合并到最近一次提交。因为你修改了一个已经存在的提交,你须要使用 git push --force-with-lease <remote_name> <branch_name>
命令将这些修改强制推送到你的远程仓库。这个命令会使用咱们本地仓库中所作的修改来覆盖远程仓库中为导航添加样式
这个提交。bash
当你强制推送分支时,有一点须要注意,那就是当你所在分支是一个多人协做的分支时,你的强制推送可能会给其余人的正常推送形成麻烦,由于远程分支上有一些强制推送的新的提交。所以,你应该合理地使用这个功能。你能够在这里学习到更多有关 Git 强制推送选项的信息。
在上一个场景中,由于咱们只须要修改最近的一次提交,因此作起来很是简单,可是想象一下若是代码审查者建议修改 _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
来将分支变基到咱们要修改的更改提交的前一个更改提交
rebase
命令的交互模式,经过提交 SHA1 哈希值咱们能够将分支进变基。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>
命令将分支强制提交。
一个常见的场景就是当咱们刚刚修改了一些以前的提交并从新提交了一些新的更改。如今让咱们尽量的精简一下这些提交,用原来的提交合并它们。
你所要作的就是像其它场景中所作的那样开始交互性的变基操做。
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 渲染导航部分
。你只须要作:
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
,但前提是你喜欢过这种有风险的生活,由于你没有机会在这些合并应用前检查它们。
若是你在开发一个大型的功能,那一般会有许多修复和代码审查反馈的修改频繁的被提交。咱们能够将提交的清理工做留到开发结束,而不是不断从新设计分支。
这是建立补丁文件很是方便的地方。实际上,在开发人员可使用以 Git 为基础的服务好比 GitLab 以前,补丁文件一直是开发大型开源项目经过邮件分享代码与合并代码的主要方式。假设你有一个提交量很是巨大的分支(例如;add-page-navigation
),它对于仓库的变动历史表述得不是很清晰。如下是如何为您在此分支中所作的全部更改建立补丁文件:
master
分支的全部更改而且与这些更改没有冲突。add-page-navigation
分支中签出时运行 git rebase master
或 git merge master
,以将全部从 master
进行的更改转移到您的分支上。git diff master add-page-navigation > ~/add_page_navigation.patch
。
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 连接。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、前端、后端、区块链、产品、设计、人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。