7

这是一个系列文章,介绍学习 Git 的一个小游戏 - githug,如果你是第一次看到,请先阅读:
闯过这 54 关,点亮你的 Git 技能树
闯过这 54 关,点亮你的 Git 技能树(一)
闯过这 54 关,点亮你的 Git 技能树(二)
闯过这 54 关,点亮你的 Git 技能树(三)
闯过这 54 关,点亮你的 Git 技能树(四)

没想到第四弹在「开发者头条」上获得了 300 多个赞。
看来大家对这个小游戏挺感兴趣的,而且还有不少朋友在促更,今天就让我们一鼓作气打通最后的 14 关吧。

同样,如对任何命令使用有疑问请看第一篇里的推荐教程,也欢迎在下面留言,我会尽力提供帮助的。

第四十一关


项目时间长了,git 仓库会慢慢变大,如何优化?
这个场景日常很少用到,而且不是必须用的,所以没什么概念。来看一下提示吧!

打开帮助之后输入 /redundant 搜索关键字,一下就找到了一个 -d 的参数。

第四十二关

有一次,我正在一个特性分支上开发一个功能,提交了几次代码,就在准备结束合并代码的时候,然后产品经理说这个需求不用做了。
我强压下心里奔腾的一万只草泥马,准备删除这个分支,但在删除之前想到有一个 commit 是对一个工具类的修改,还是有用的。
这是我就需要从特性分支上把这个 commit 摘出来,合到 master 分支上,再删除特性分支。
这个题目就是类似的场景,先来看看特性分支叫什么,然后找到需要「摘」出来的那个 commit:

查看了一下 log 命令的帮助,发现可以指定分支,这样就省去了 checkout 到 new-feature 分支的步骤。

上图中最后的一次提交就是我们需要「摘」出来的,复制它的 Hash。

顺利过关!

第四十三关

我们在开发的过程中,为了不影响当前正在做的事情,会把一些不那么紧急的任务使用 TODO 注释在代码里,现代的 IDE 都能帮我们识别这些注释并在一个单独的窗口中罗列出来。
当然,不借助 IDE,光凭系统命令或 git 命令也是可以做到的。

第四十四关

查看 log,git log --oneline,可以看到中间的 commit message 有一个拼写错误。

看一下提示,可以在 rebase 的时候指定 -i 参数:

查看一下帮助就知道是 interactive 的意思:


在打开的 Vim 窗口中将第一行的 pick 改为 r,表示:使用 commit,并且修改 commit message。

修正拼写错误的 coommit

第四十五关

当我使用 TDD 方式进行开发,会进行非常频繁小步的提交,这样在其他同事看来就缺乏完整性,也会增加后续维护成本。
所以 git 让我可以在 push 到远程仓库之前,对 commit 历史进行修改合并,把多个 commit 合并成一个。
git log --oneline 看一下提交记录:

从提交记录可以看出,它提示我们将最后三个 commit 都合并到第二个 commit - Adding README 中。
接着执行 git rebase -i HEAD~4

第一个 commit 为 pick,后三个改为 s,意思是使用这个 commit,但将它合并到前一个 commit 中去。
保存退出,会提示我们编辑 commit message,再次保存退出后,查看一下提交记录:

第四十六关

题目要求在 merge 特性分支时,把所有的新提交合并成一个,先来看看 master 分支当成的状态:
git log --oneline

再看一下 git log long-feature-branch --oneline

完整过关命令如下:

最后 master 分支状况如图,只用一个 commit,包含了 long-feature-branch 所有的修改:

第四十七关

提交顺序错乱时,也可以使用 git rebase -i 进行调整。
先看看 Log,最后两个提交颠倒了位置:

执行 git rebase -i HEAD~2,将两行 pick xxx 代码交换位置即可。

第四十八关

看一下历史:

代码中不知道什么时候引入了 bug,不过没关系,我们有自动化测试。
我们可以不断手工 checkout 到某个 commit,结合二分法查找快速定位到引入 bug 的那一个 commit。
不过这种纯手工重复的事情,已经包含在 git 的命令中了,就是 bisect

读一下 git help bisect,可以找到这个例子:

我们知道 HEAD 的代码是有问题的,而第一个 commit 的代码是没问题的。
通过 git log 获得第一个 commit 的 Hash,就可以执行 bisect 命令:

红线部分已经清楚地告诉我们是哪个 commit 引入的 bug 了。

第四十九关

有时开发了一个特性没提交,接着又开发了另一个特性。
作为一个自律的程序员,应该是要分两次提交的,如果修改的是不同的文件,那可以轻松地通过 add 不同的文件进行两次提交。
但这次好巧不巧的是居然修改了同一个文件,怎么办?看看提示:

原来 git add 的最小粒度不是「文件」,而是 hunk(代码块)。
git help add 然后查找 hunk

执行如下命令:

Git 会让我们有机会选择对每一个 hunk 做什么样的操作。这里修改同一个位置,在一个 hunk 里,根据提示我们还要输入 e 手工编辑 hunk。

将第 5 行删除,保存退出,再看当前状态:

git diff --cached

git diff

目的达到了,过关:

第五十关

正在特性分支上开发一个功能,被头儿叫去修了一个紧急的 bug,修完后发现:妈蛋,那个特性分支叫啥?忘记了!
当然,作为一个自律的程序员,一般是不是出现这样的场景的。
这种情况说明分支命名太没有规律,或者分支太多,不然可以通过 git branch 看一下,也能很快找到特性分支。
先看一下提示吧:

哦,原来有个命令叫 git reflog,来看看帮助文档 - git help reflog,看起来这个命令非常强大,不过我们这里只用到简单用法就可以了:

上图中第二行就显示了我们之前工作的特性分支。

第五十一关

有时代码 push 到远程仓库后发现某一块代码有问题,我们可以通过 revert 命令将特定 commit 完全恢复。
首先我们要找到需要 revert 的 commit 的 hash:

完全过程如下:

第五十二关

刚刚把最新的一次提交给毫无保留的扔掉,马上就改了主意,怎么办?世界上有后悔药吗?
有的,只要进行 git 版本控制的一切都能找得回来。看下提示先:

提示说被我们抛弃的那个 commit 像孤魂野鬼一样在外游荡,还没有被鬼差送入地狱,我们还能通过 git reflog 找到它的代号。

找到它的 Hash 后就通过 cherry-pick 将它找回来:

第五十三关

冲突合并是使用版本控制非常常见的了,居然在这么靠后的位置才出来。

编辑冲突的文件 poem.txt,删除 Git 添加的标识冲突的行。

别忘了,还要 git add poem.txt 然后 git commit

第五十四关

submodule 是 Git 组织大型项目的一种方式,通常可把第三方依赖作为 submodule 包含进来,这个 submodule 本身也是一个独立的 Git 项目。

第五十五关

最后这一关并非测试使用 GitHub 的能力,而是期望大家贡献代码,包括增加更多关卡,修复 Bug 或者完善文档。
我当初是准备翻译中文版,结果工作量不小,拖的太久最后不了了之了。
希望你能对开源社区贡献自己的一分力量!哪怕 Star 一下也是对作者莫大的鼓舞!

总结

终于完结了,谢谢你这么耐心一路跟着操练下来,希望你也像我一样从这个游戏里收获很多。
如果你喜欢这个系列文章,将它们分享给你的同事好友,也是对我最大的鼓励!
如果有什么意见反馈,欢迎评论留言,我一定回复。

如果你发现有好的学习某技术的游戏或教程,欢迎来到「软件匠艺社区」 与大家分享!


seabornlee
1.4k 声望124 粉丝

ThoughtWorker 培训师。