Git命令行实战:谁动了我的奶酪

题图

工作中遇到了这样一个场景:突然发现自己写的一段代码被人改过,想看看到底是谁改的,改了啥。

本文就基于以上这样一个场景预设介绍一系列相关的Git命令。

首先,需要确认一下代码是真的被同事改动了,还是自己脑子瓦特了。

1
$ git blame -L start,end filename
  • start: 代码片段起始行号
  • end: 代码片段结尾行号
  • filename: 文件路径

该命令会显示代码段中每一行的最后一次提交信息,包括提交的SHA1、时间、作者。

输出示例:

1
2
3
4
9366598e (nelson 2018-12-26 15:34:54 +0800 48)   componentDidMount() {
f07595e2 (kenny 2019-01-04 12:41:28 +0800 49) const { schema, params } = this.props;
febe3a3b (kenny 2019-01-04 16:50:46 +0800 50) AppActions.getGeneralOptions(schema, params);
9366598e (nelson 2018-12-26 15:34:54 +0800 51) }

仔细一看,果然有猫腻,中间有两行在1月4日被人改过。

git blame 只能看到谁在什么时间做了改动,至于具体每次提交改了啥,还得求助于 git log 命令来查看:

1
$ git log -L start,end:filename
  • start: 代码片段起始行号
  • end: 代码片段结尾行号
  • filename: 文件路径

该命令会输出代码段中最近几次改动的diff详情。

输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
commit febe3a3b52f1603e176eca0392a7c90df781d41e                                
Author: kenny <example@gmail.com>
Date: Fri Jan 4 16:50:46 2019 +0800

commit message

diff --git a/src/components/Select/GeneralSelect.jsx b/src/components/Select/GeneralSelect.jsx
--- a/src/components/Select/GeneralSelect.jsx
+++ b/src/components/Select/GeneralSelect.jsx
@@ -48,10 +48,4 @@
componentDidMount() {
const { schema, params } = this.props;
-
- if( !this.state.Options?.[schema] ) {
- AppActions.getGeneralOptions(schema, params);
- } else {
- this.getOptionCallback(this.state.Options[schema])
- }
-
+ AppActions.getGeneralOptions(schema, params);
}

一波分析,没能猜透同事的改动意图,然后就需要跟同事正面沟通一下了。沟通结果无非就两种,要么你被他说服了,这事儿就算过了,要么他被你说服了,然后你就会遇到一个新的问题:怎么回滚历史提交中更改的代码块。我们接着往下看。

1
$ git reset  (--patch | -p) tree-ish filename
  • tree-ish: 提交的SHA1标识
  • filename: 文件路径

关于该命令,官方文档 Git Documentation: Git Reset 中描述如下:

Interactively select hunks in the difference between the index and (defaults to HEAD). The chosen hunks are applied in reverse to the index.

也即,该命令会比较缓存区(Index)和所指定提交(此处手动埋伏笔)之间的差异,并交互式的让用户选择代码区块并应用到缓存区(Index)中。

这里要注意两点:

  1. 什么叫交互式的?
  2. 应用到 缓存区(Index)

首先来看第一点,什么叫交互式的?

我们来看以上命令的输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
diff --git b/src/components/Select/GeneralSelect.jsx a/src/components/Select/GeneralSelect.jsx
index b1bf5ca..73cd634 100644
--- b/src/components/Select/GeneralSelect.jsx
+++ a/src/components/Select/GeneralSelect.jsx
@@ -47,7 +47,13 @@ class GeneralSelect extends Reflux.Component {

componentDidMount() {
const { schema, params } = this.props;
- AppActions.getGeneralOptions(schema, params);
+
+ if( !this.state.Options?.[schema] ) {
+ AppActions.getGeneralOptions(schema, params);
+ } else {
+ this.getOptionCallback(this.state.Options[schema])
+ }
+
}

Apply this hunk to index [y,n,q,a,d,/,e,?]?

注意最后一行,命令并没有直接结束执行,而是等待用户的输入指示。此处提供了一堆可选项的缩写,如果看不懂直接输入 ? 将会输出命令提示:

1
2
3
4
<