前言
现在的软件开发,代码通常都是用 Git 仓库储存的。当软件上线以后,我们时常需要回到 Git 仓库里面排查异常情况。在这篇文章,我想跟大家分享一下排除故障用到的一些 Git 命令。之前在 GitHub 上面接触过一个比较热门的项目,我打算用它作为本文的例子跟大家分享。它是有 15.9k 个赞的 linlinjava/litemall 又一个小商城。使用它的原因是它的项目架构比较接近在公司使用的真实代码,举起例子来比较好理解。
阅读本文后,你会明白:
- 如何使用 git-log 查看历史
- 如何使用 git-diff 比较代码区别
- 如何使用 git-revert 撤销变化
事不宜迟,让我们马上开始吧!
查看历史
使用 git-log 可以查看历史
查看全部历史
查看 v1.7.0 跟 v1.8.0 之间的所有历史:
$ git log v1.7.0..v1.8.0
commit 97338d20928527485650def8e7681816cc7e19f4 (tag: v1.8.0)
Author: linlinjava <linlinjavaer@gmail.com>
Date: Sun Jan 10 18:04:52 2021 +0800
[release]: v1.8.0
commit 18510318a16d95a9806b9de793d85f3bd012d280
Author: linlinjava <linlinjavaer@gmail.com>
Date: Sun Jan 10 18:01:46 2021 +0800
chore
...
Commit 信息太啰嗦,信息量太大?试试 --oneline
用让每个 commit 只用一行显示:
$ git log v1.7.0..v1.8.0 --oneline
97338d20 (tag: v1.8.0) [release]: v1.8.0
18510318 chore
c733a28a chore
5f054220 build(deps): bump axios from 0.19.2 to 0.21.1 in /litemall-vue (#452)
...
历史太多?试试只取最近 10 个:
$ git log v1.7.0..v1.8.0 --oneline -10
97338d20 (tag: v1.8.0) [release]: v1.8.0
18510318 chore
c733a28a chore
5f054220 build(deps): bump axios from 0.19.2 to 0.21.1 in /litemall-vue (#452)
d9070cba chore[litemall-admin]: revert update
17b4d280 chore[litemall-admin]: update
cd32740e Merge branch 'master' of https://gitee.com/linlinjava/litemall
679117d5 feat: 支持验证码
d2c79cee !54 修复编辑优惠券看不到 商品或类目列表的问题 Merge pull request !54 from 滑稽刘/N/A
747a3e7f 修复编辑优惠券看不到 商品或类目列表的问题
另外可以只取最近的历史。比如说,
只取昨天以后的历史(不含昨天):
$ git log v1.7.0..v1.8.0 --since yesterday
$ git log v1.7.0..v1.8.0 --after yesterday
只取某个日期以后:
$ git log v1.7.0..v1.8.0 --since 2021-05-31
$ git log v1.7.0..v1.8.0 --after 2021-05-31
过滤掉 merge commits,因为通常问题都不在这里:
$ git log v1.7.0..v1.8.0 --oneline --no-merges
不比较两个标签,比较两个 commits 也非常有用。因为通常 SaaS 服务都是持续集成,不会每次都生成新标签的:
$ git log 519d7b15..cd32740e --oneline
cd32740e Merge branch 'master' of https://gitee.com/linlinjava/litemall
679117d5 feat: 支持验证码
d2c79cee !54 修复编辑优惠券看不到 商品或类目列表的问题 Merge pull request !54 from 滑稽刘/N/A
747a3e7f 修复编辑优惠券看不到 商品或类目列表的问题
查看特定模块历史
有时候我们并不想知道所有的 Git 历史,因为一个 Git 仓库里面有很多的模块。如果每个文件夹对应一个模块的话,可以只关注现在生产线出问题的模块,比如 litemall-core 这个模块:
$ git log v1.7.0..v1.8.0 --oneline -- litemall-core
679117d5 feat: 支持验证码
2b69527d 阿里云发送短信优化,在返回错误后记录日志以及返回发送失败状态 (#429)
e1dfa1e4 chore
也可以选择多个模块。因为可能好几个模块同时出问题,或者是一个服务依赖几个代码模块:
$ git log v1.7.0..v1.8.0 --oneline -- litemall-core litemall-admin
c733a28a chore
cd32740e Merge branch 'master' of https://gitee.com/linlinjava/litemall
679117d5 feat: 支持验证码
747a3e7f 修复编辑优惠券看不到 商品或类目列表的问题
35bf2e54 feat[litemall-admin,litemall-admin-api]:订单收款
c0541fde chore
d4dde95b fix[litemall-admin]: gitee #I1X232
d8f59965 fix[litemall-admin]: gitee #I1X21W
...
搜索 commit message 带有某个关键词的所有历史,比如某个 JIRA 的 ID 号:
git log --oneline --grep JIRA-123
fb67d981 JIRA-123 Update README
查看某个文件的历史
知道文件路径的话,可以查询某个文件的历史,比如说 Maven 项目的打包文件 pom.xml
:
$ git log v1.7.0..v1.8.0 --oneline -- litemall-core/pom.xml
e1dfa1e4 chore
查询支持 glob 表达式,比如各个模块的 pom.xml
文件:
$ git log v1.7.0..v1.8.0 --oneline -- **/pom.xml
679117d5 feat: 支持验证码
c4da8fb5 chore: druid升级1.2.1
aabc2617 chore: shiro升级版本1.6.0
fa189cdc build(deps): bump mysql-connector-java from 5.1.46 to 8.0.16 (#410)
25518ade build(deps): bump mysql-connector-java in /litemall-db (#411)
...
有些时候你可能找不到你想要的文件,因为文件的路径修改了、重命名了或者是删除了。比如说下面这个例子,我在 test 分支加了一个新的文件叫做 important.txt,然后又把它移到了 doc 文件夹。整个历史长成下面这样:
$ git log -5 --graph --oneline --decorate
* ed098e37 (HEAD -> master) Merge branch 'test'
|\
| * 5719e55f (test) Move to doc
| * 76a6c164 Add important note
* | 3821fb3f Update README.md
|/
* ce2720b5 (linlinjava/master, linlinjava/HEAD) fix[litemall-wx]: #473
这个时候搜索 important.txt 就找不到了:
$ git log -- important.txt
(结果为空)
如果加入 --full-history
会找到,因为 Git 会从 merge commit 所有的 parents 分支中寻找这个路径的修改记录:
$ git log --full-history --oneline -- important.txt
5719e55f Move to doc
76a6c164 Add important note
那么到底是什么文件这么重要呢??打开看看:
git show 76a6c164:important.txt
关注微信号:码农小黄!
好了,我想你们知道要怎么做了(微笑脸)
比较代码区别
使用 git-diff 命令可以比较代码区别。
比较在 v1.7.0 与 v1.8.0 之间所有的变化:
$ git diff v1.7.0..v1.8.0
比较在 v1.7.0 跟 v1.8.0 中,一个文件的变化:
$ git diff v1.7.0..v1.8.0 -- litemall-core/pom.xml
diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml
index 9062827c..b0e51ad2 100644
--- a/litemall-core/pom.xml
+++ b/litemall-core/pom.xml
@@ -19,7 +19,6 @@
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
- <version>4.0.3</version>
</dependency>
<dependency>
查看一个分支从 master 出来以后跟 master 所有的变化:
$ git diff master...test
diff --git a/doc/important.txt b/doc/important.txt
new file mode 100644
index 00000000..6a19c964
--- /dev/null
+++ b/doc/important.txt
@@ -0,0 +1 @@
+关注微信号:码农小黄!
相比于 master..test
,使用 master...test
只显示分支 test 单边出现的变动,忽略另一边分支 master 出现的变动。如果没有听懂的话也没有关系,就打开 GitHub 或者 GitLab,通过 pull-request 或者 merge-request 看代码变化吧,可能更好用。
撤销变更
使用 git-revert 可以撤销变更。这一个段落主要讨论对于 GitHub 下三种不同的 merge 选项合并代码后的撤销。这三个选项是:create-a-merge-commit / squash-and-merge / rebase-and-merge。
撤销单一 commit
撤销单一 commit。适合 GitHub 中通过 squash-and-merge 选项合并的撤销。
$ git revert fb67d981
[master be5a0576] Revert "JIRA-123 Update README"
1 file changed, 1 insertion(+), 2 deletions(-)
撤销多个 commits
撤销多个 commits,从新到旧、倒序地把 commits 逐一撤销。适合 GitHub 中通过 rebase-and-merge 选项合并的撤销:
$ git revert <commit3>
$ git revert <commit2>
$ git revert <commit1>
撤销一个 merge commit
撤销一个 merge commit。这个时候要选择回到哪个父分支(parent branch),比如之前把 test 分支的代码合并到了 master:这个时候 parent 1 是 master,parent 2 是 test。撤销时不明确父分支会报错。这个方法适合 GitHub 中通过 create-a-merge-commit 选项合并的撤销:
error: commit 20245201b27dcb2d1001dd21b35a95c76c7b2e0c is a merge but no -m option was given.
fatal: revert failed
从 commit message 观察有哪些 parents:
$ git show 20245201
commit 20245201b27dcb2d1001dd21b35a95c76c7b2e0c
Merge: 76a5d305 5719e55f // <- CHECK HERE
Author: Mincong HUANG <mincong.h@gmail.com>
Date: Sat Jun 5 13:54:10 2021 +0200
Merge branch 'test'
明确想要回到的父分支,通常是第 1 分支(最小从 1 开始,不是从 0 开始):
$ git revert 20245201 -m 1
Removing doc/important.txt
[master 4c75c129] Revert "Merge branch 'test'"
1 file changed, 1 deletion(-)
delete mode 100644 doc/important.txt
扩展
如果不记得这些 Git 命令,不要怕,通过 -h,--help
可以看看命令的说明:
git <cmd> -h
# 举例:
git log -h
git diff -h
git revert -h
阅读官网 git-scm.com
的文档也是很好的解决方法。
结论
在本文中,我们看到了如何使用 git-log 来浏览两个版本代码中的全部历史、模块历史、文件历史;看到了如何使用 git-diff 比较同一文件不同版本的区别、不同分支的所有区别;最后,看到了如何使用 git-revert 来取消变更。希望这篇文章能够给你带来一些思考,让你的排除故障更加顺利。如果你们感兴趣的话,还可以访问浏览我的博客的其他 Git 的文章,以前写过 17 篇这方面的英语文章。谢谢大家!
参考文献
- https://github.com/linlinjava/litemall/
- https://git-scm.com/docs/git-log
- https://git-scm.com/docs/git-diff
写作不易,希望大家点个赞、点个在看支持一下,谢谢(花)