文章转发自专业的Laravel开发者社区,原始连接:learnku.com/laravel/t/1…css
提交是 Git 仓库的重要组成部分之一,不只于此,提交信息 贯穿于 Git 仓库的整个生命周期。随着项目/仓库的发展(新特性的增长、Bugs 的修复、架构的重构),提交信息可让咱们看到改了什么地方以及是如何改动的。所以,这些信息以一种简短、精确的方式反映着潜在的变化是很是重要的。html
Git 提交消息就像是你在你接触过的代码上面留下的指纹。任何你今天提交的代码,一年之后当你看到这段代码的变化时,你将感谢本身当时留下的清晰、有意义的提交信息,同时它还将使你的开发变得更为容易。当提交被基于上下文独立时,由某个提交引入的 Bug 将会更快被找到,而且更容易恢复到致使错误提交前的代码。前端
当你工做在一个大的项目中时,咱们常常更新、新增或者移动文件。确保在这种状况下维持提交消息将很棘手,尤为是在开发周期跨越数天,数周甚至数月的状况下。所以,为了简化维护简洁提交历史记录的工做,这篇文章将使用开发人员在处理 Git 仓库时可能遇到的一些常见状况。laravel
在咱们深刻讨论以前让咱们快速的了解一下,在咱们假设的 Ruby 应用程序中,典型的开发工做流是什么样子的。git
注意: 这篇文章假定您了解基本的 Git 知识 、分支的工做方式、如何在阶段中添加未提交的分支更改以及如何提交更改。若是你不了解这些流程, 咱们的文档 是一个很好的起点。shell
如今,咱们正在开发一个小型的 Ruby on Rails 项目。咱们须要在首页添加一个导航视图,这涉及到更新和添加几个文件。下面是整个流程的逐步细分:后端
application_controller.rb
index.html.haml
_navigation.html.haml
styles.css.scss
application_controller_spec.rb
navigation_spec.rb
由于全部的文件分属于架构的不一样区域,因此咱们对这些更改彼此隔离进行提交,确保每次提交表明一个特定的上下文,并按顺序提交。我一般喜欢从后端 -> 前段
的顺序。首先提交大多数之后端为中心的更改,接着是中间层,最后是在提交列表中之前端为中心的更改。安全
application_controller.rb
& application_controller_spec.rb
;Add routes for navigation。_navigation.html.haml
& navigation_spec.rb
;Page Navigation View。index.html.haml
;Render navigation partial。styles.css.scss
;Add styles for navigation。如今咱们已经提交了更改,咱们使用分支来建立 merge 请求。一旦建立了 merge 请求,一般会在更改合并进 master
分支以前由原仓库的拥有者进行审核。如今咱们来了解一下,在代码审核期间咱们可能会面临的不一样状况。bash
想象一下,审阅者查看了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>
将这些更改 强制推送 到你的远程仓库。这个命令将会使用咱们在本次仓库更新后的提交,覆盖远程仓库上消息为Add styles for navigation
的那次提交。
在强制推送分支时须要注意的一件事是,若是你和其余同事工做于同一分支,当其余人尝试向一个刚被强制推送过的远程分支正常推送他们的更改时,可能遇到一些麻烦。因此,请明智地使用强制推送。你能够在 这里 了解有关 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
Add styles for navigation
commit c22a3fa0c5cdc175f2b8232b9704079d27c619d0
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:52 2018 +0000
Render navigation partial
commit 4155df1cdc7be01c98b0773497ff65c22ba1549f
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:42:51 2018 +0000
Page Navigation View
commit 8d74af102941aa0b51e1a35b8ad731284e4b5a20
Author: Kushal Pandya <kushal@gitlab.com>
Date: Wed May 2 08:12:20 2018 +0000
Add routes for navigation
复制代码
这就是 Git ReBase
命令发挥做用的地方。每当咱们但愿编辑 git ReBase
的特定提交时,咱们须要先将咱们的分支从新定位为在咱们但愿编辑的提交以前,将头移到右边。在咱们用例中,咱们须要更改读取的提交 Page Navigation View
。
这里请注意,正确的提交哈希是咱们想要修改提交的前一个提交哈希;拷贝那个哈希,而后执行下面的步骤:
git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20
rebase
命令的 交互 模式,并提供了要变基的提交哈希。pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
pick aa0a35a867e Add styles for navigation
# 在 8d74af10294 上变基 8d74af10294..aa0a35a867e 范围(3次提交)
#
# 命令:
# p, pick = 保留本次提交
# r, reword = 保留本次提交,但要修改提交消息
# e, edit = 保留本次提交,但暂停下来进行修改(不仅修改提交消息)
# s, squash = 保留本次提交,但合并到前一次提交
# f, fixup = 与“squash”相似,但丢弃本次提交消息
# x, exec = 运行 shell 命令(本行的剩余内容)
# d, drop = 删除本次提交
#
# 这些行能够重排顺序,并自顶向底依次执行。
#
# 若是你删除一行,那次提交将会丢失。
#
# 若是你删除全部行,本次变基(rebase)将会停止。
#
# 注意空提交已注释掉。
复制代码
注意每一个提交前面都有一个单词pick
,下面的注释是咱们可能用到的关键字。由于咱们想要 编辑 某此提交(4155df),因此须要把pick 4155df1cdc7 Page Navigation View
改为edit 4155df1cdc7 Page Navigation View
。保存修改,而后退出编辑器。
如今你的分支就重置到了所作的修改包含_navigation.html.haml
的时刻。打开文件根据审核反馈执行须要的修改。一旦修改完毕,经过运行git add _navigation.html.haml
命令进行暂存。
既然咱们暂存了这些改变,如今是时候把 HEAD 分支移回咱们的原始提交了(包含咱们添加的最新修改),运行git rebase --continue
,这将会在终端打开你的默认编辑器而后显示在变基(rebase)期间的提交消息;Page Navigation View
。若是但愿的话,你能够改变这个提交消息,可是咱们如今让它保持现状,保存并退出编辑器。此刻,Git 会从新播放你所编辑的提交以后的全部提交,而且如今的HEAD
分支回溯到了咱们原始的顶部提交。
因为咱们再次修改了远程仓库中已存在的一次提交,因此须要使用git push --force-with-lease <remote_name> <branch_name>
强制推送分支。
一个很常见的场景就是为了修复以前提交的内容,你已经 commit 了几回。如今咱们来尽量地减小 commit 的次数并把它们和原来的提交合并起来。
你须要作的就是就像你在其余场景同样启动交互式 rebase。
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
pick aa0a35a867e Add styles for navigation
pick 62e858a322 Fix a typo
pick 5c25eb48c8 Ops another fix
pick 7f0718efe9 Fix 2
pick f0ffc19ef7 Argh Another fix!
复制代码
假设你如今想要把这些提交记录都合并到 c22a3fa0c5c Render navigation partial
。你只须要作到:
pick
改成 squash
或者 fixup
。注意: squash
保留了描述中的提交注释。 fixup
不会保留提交的注释而只保留原始注释。
你会获得这样的结果:
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e Add styles for navigation
复制代码
保存更改,退出编辑,你就完成了!这是产生的历史:
pick 4155df1cdc7 Page Navigation View
pick 96373c0bcf Render navigation partial
pick aa0a35a867e Add styles for navigation
复制代码
和之前同样,你要作的就是 git push --force-with-lease <remote_name> <branch_name>
,改变就生效了。
若是你想要彻底地删除一个提交,把 squash
或者 fixup
换成 drop
或者干脆删掉那一行。
为了不冲突,请确保你移动到的目标没有编辑到同一个文件。
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
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 Add styles for navigation # this changes index.html (no conflict)
复制代码
fixup
若是你清楚知道你将 fixup 哪个提交,你不须要浪费时间构思一个临时的名称,如: "Fix 1", "Fix 2", ..., "Fix 42"。你可使用如下的方法:
第一步:开始使用 --fixup
在你 stage
而且修复了你想要的内容时,使用如下命令:
git commit --fixup c22a3fa0c5c
复制代码
(注意这个 hash 信息对应 c22a3fa0c5c Render navigation partial
)
以上命令会生成一个 commit:: fixup! Render navigation partial
.
第二步:召唤你的好朋友 --autosquash
简单的交互性 rebase,如下命令会让 git
在正确的位置里设置 fixup
:
git rebase -i 4155df1cdc7 --autosquash
如今你的历史是:
pick 4155df1cdc7 Page Navigation View
pick c22a3fa0c5c Render navigation partial
fixup 62e858a322 Fix a typo
fixup 5c25eb48c8 Ops another fix
fixup 7f0718efe9 Fix 2
fixup f0ffc19ef7 Argh Another fix!
pick aa0a35a867e Add styles for navigation
复制代码
你还可使用 git rebase --autosquash
命令来直接跳过 review 阶段,可是通常建议除非你感受特别安全,不然仍是少用为妙,由于你没机会 review 到具体变动。
若是你在开发一个大功能,有时候你在分支里(如:add-page-navigation
)留下不少 commit ,而你不喜欢让这些 commit 进入主分支,接下来我教你一个方法:
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
分支作了一个 diff 操做,而且将结果输出到 ~/add_page_navigation.patch
文件中。git checkout master
切换到 master
分支上;git branch -D add-page-navigation
删除本地分支 add-page-navigation
(咱们已经有补丁文件了,不要惧怕);git checkout -b add-page-navigation
建立一个新的分支;add-page-navigation
分支上,此分支没有任何更改;git apply ~/add_page_navigation.patch
来应用补丁里的修改;未提交
的状态显示着;就跟以前遇到的场景同样,咱们修改了整个分支,你须要作一个 force push 了。
尽管咱们已经介绍了使用 Git 进行平常工做流程中出现的大多数常见的状况,但重写 Git 历史是一个巨大的话题,而且当你在熟悉上述提示时,你能够在 Git 官方文档 学习围绕该主题的更高级概念。祝你愉快的学习 Git。