几道题目:Git、Markdown与HTTP消息

之前给前东家的小伙伴们出了两套题,在这里分享一下,并做个简单的解析。这一啪主要包括 git、markdown 与 HTTP 消息相关的内容。

Git 中如何还原代码

题目

特别有逼格的 $天骄 使用 git 管理代码,他在一顿骚操作之后把 @HUGE 的代码改得乱七八糟, @HUGE 很生气,后果不严重,因为 $天骄 后来执行了下述哪种操作把代码又变回去了:

A. git checkout -- .
B. git reset --soft
C. git reset
D. git checkout master

解答

这几个 git 指令都是合法的。一共涉及两种命令,checkoutreset

checkout 的基本功能有两项:

Switch branches or restore working tree files

也就是:

  1. 切换分支
  2. 还原文件

对第一种功能,语法是:

git checkout <branch>

选项 D 就使用了这第一种语法,实现的是「切换到 master 分支」。

题目中涉及的是第二种功能,还原文件。语法是:

git checkout [<tree-ish>] [--] <pathspec>…​

这里涉及两个参数,前一个参数 tree-ish 是可选的,可以填入一个指定的提交,后面 pathspec 是想要还原的文件名,必须提供。中间的 -- 是分隔符,确保无歧义的情况下可省略。

假设现在的分支结构如下:

  • 7edc57a (HEAD -> master) commit 2
  • c293d46 commit 1

那么当对文件进行又一次修改之后,假设文件名为 sanko.c,那么

git checkout c293d46 -- sanko.c

这样的一个完整指令可以令 sanko.c 这个文件还原到「commit 1」的状态。

事实上第二个参数 pathspec 不仅可以跟文件名,还可以跟目录名。因此如果要还原所有文件最近的提交,可以直接给指代「当前目录」的 .

实现题中效果可以用下面几种表达:

git checkout 7edc57a -- sanko.c
git checkout 7edc57a sanko.c
git checkout -- sanko.c
git checkout sanko.c
git checkout 7edc57a -- .
git checkout 7edc57a .
git checkout -- .
git checkout .

题中 A 选项可以使用。

而另一个 reset 顾名思义,也有「重置」的功能。之所以不选择这个命令,是因为题中给出的两个选项恰好都不能完全满足题中要求。

一种可行的选项是:

git reset --hard

无论使用 checkout 还是 reset,对于工作区来说都是比较危险的操作,因为在还原时一旦失误,自上次提交以来的所有更改会永远无法找回。

彩蛋

这题给了 checkout 和 reset 两种命令各两个选项,形成一致的权重,避免选项的倾斜。

Git:一切都在本地

题目

特别粗心的 $天骄 修改了代码并执行了 git 中的 addcommit 命令。这时候他忽然发现这个代码改得不对啊,但是一时半会儿又改不出正确的,可是 @HEG 在嚷着要在这份代码上加新功能了,这时 @HEG :

A. 从服务器上取到的代码是 $天骄 改过的错误代码
B. 可以直接基于服务器上的代码增加新功能
C. git remote reset HEAD~ 命令来重置 $天骄 的最后一次提交
D. git remote revert HEAD~ 命令来重置 $天骄 的最后一次提交

解答

所谓 git,就是每个人都只是对本地的、自己电脑上的仓库进行更改,在手动与服务器同步之前,并不会影响到服务器的分毫。哪怕是删除文件,哪怕是删除提交,哪怕是删除分支,哪怕是删除仓库。

git-scm 上的话来说:

everything-is-local

题中,在执行

git add .
git commit -m "some message"

后,git 事实上仍然只是在对本地仓库进行操作。所以无论本地如何操作,协作者都无需进行额外的操作来还原文件内容。

A 选项中,由于并未进行 push 操作,服务器上显然仍是之前没有修改过的代码;

B 选项是正确答案,基于服务器代码修改后,即使后面 $天骄 提交了正确修改, @HEG 也可以通过简单的 merge 命令完成代码合并;

C 选项和 D 选项是我瞎写的,remote 命令依然是针对本地仓库的,用于操作与远程服务器相关的设置。

彩蛋

由于 C 和 D 选项较为接近,并且与 B 选项冲突,猜答案时容易陷入其中。相比之下,B 选项「无需逼逼直接上」的气质一般是错误答案才有的。

HTTP 应答码

题目

特别爱炫耀的 $天骄 自己写了一段网络请求脚本,向一台服务器发了HTTP请求,收到应答码为 301,这是什么意思:

A. 请求成功
B. 永久移动
C. 临时移动
D. 临时重定向

解答

HTTP 应答消息中的第一行称为「状态行」:

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

对于应答码「Status-Code」而言,第一个数字简单的原则是:

  • 1xx: Informational 消息
  • 2xx: Success 成功
  • 3xx: Redirection 重定向
  • 4xx: Client Error 请求错误
  • 5xx: Server Error 服务器错误

具体到选项中,200 指代「请求成功」,301、308 分别指代「永久移动」和「永久重定向」,302、303、307 可以认为指代「临时移动」或「临时重定向」。

308 的定义中提到,两者的区别在于是否允许请求从 POST 改为 GET,也就是说,307 和 308 对于 POST 请求必须予以 POST 重定向。而 303 与 302 之间的差异是在收到 POST 请求时,302 必须请求用户确认,303 则可以将其重定向给 GET。

不过语义上来说没有必要过于细究选项中「移动」(Moved)和「重定向」(Redirect)的区别。后面两个数字是开发者可以按照实际需求来定义的,规范中给定的只是一种推荐用法。

彩蛋

A 选项 200 应该都知道,但是 301 和 302 不容易分清。尤其当 C 和 D 都指向「临时」的情况下,在这两个之间做出选择似乎是必然。

修改 git 远程仓库地址

题目

公司最近又迁移了 git 服务器,特别热心的 $天骄 想帮助大家修改电脑上的 git 仓库地址,新地址是 https://dev.sunyard.xyz:3000/foo/bar.git,那么他使用的指令是:

A. git remote --set url origin https://dev.sunyard.xyz:3000/foo/bar.git
B. git remote --set-url origin https://dev.sunyard.xyz:3000/foo/bar.git
C. git set --remote origin https://dev.sunyard.xyz:3000/foo/bar.git
D. git remote set-url origin https://dev.sunyard.xyz:3000/foo/bar.git

解答

使用 remote 命令设置远程仓库地址的语法是:

git remote set-url [--push] <name> <newurl> [<oldurl>]

很多时候,git 的命令是一层套一层的,非常具有可读性。

需要查询 git 命令语法时,除了直接用搜索引擎或者使用可视化工具来完成操作之外,一般下面几种比较直接的方式:

  1. 在命令行中执行 git help -a 会列出所有子命令
  2. 在命令行中执行 git help remoteman git-remotegit remote --help 这样的指令可以查阅对应命令(此处是 remote)的详细用法
  3. 在命令行中执行 git remote -h 这样的指令可以查阅对应指令(此处是 remote)的语法
  4. 文档页面中选择对应的子命令进行查阅,如 git-remote 命令
  5. 指南页面中选择相应的模块进行学习,如Git 基础 - 远程仓库的使用

一般也建议对常用的 git 指令设置终端别名,这样可以快速执行,也方便记忆。

彩蛋

本想坚持让每个选项都保持合法可执行,以避免给初学者留下错误印象,而造成误导。但是 Unix 命令中参数是否加 -- 实在有趣,「设置远程仓库」到底属于「设置」子命令还是属于「远程」子命令也是傻傻分不清。

RESTful API 的方法

题目

特别爱学习的 $天骄 最近在研究 RESTful API,在帮助 @HUGE 设计交易后台时, $天骄 使用了 RESTful API,但是其中有一个是浑水摸鱼、滥竽充数,你能一下子把它挑出来吗?

A. GET /transactions/TID 获取交易TID的信息
B. PUT /transactions/TID 更新交易TID的信息
C. REMOVE /transactions/TID 移除交易TID的信息
D. PATCH /transactions/TID 调整交易TID的信息

解答

即使在常规的 HTTP 请求方法中,也只有 DELETE 而不使用 REMOVE 来指代「移除」。一般用于 RESTful API 中的方法包括:

  • POST
  • GET
  • PUT
  • PATCH
  • DELETE

对应于「增删改查」,POST 用于「增」,GET 用于「查」,DELETE 用于「删」,PUT 和 PATCH 用于「改」。

其中 PUT 是「更新」,是整体「替换」,而 PATCH 是「调整」,是局部「修改」。

彩蛋

对于不熟悉 HTTP 方法(method)的人来说,PUT 和 PATCH 中总觉得有一个是混进来的,而 REMOVE 却看起来如何合理。

Markdown 中的标题

题目

特别爱折腾的 @HUGE 最近爱上了 Markdown 语法,他让 $天骄 写了四种标题样式,其中有一种是不会构成「标题」的,它是:

A. 内容下面一行写 ——--—
B. 内容下面一行写 ======
C. 内容前面写 ##
D. 内容前面写 **

解答

Markdown 中的标题有两种写法,一种是在文本下面一行加横线

title 1: sanko
====
标题 2: 撒肯
----

其中,等号 = 会构成一级标题,减号 - 会构成二级标题。

另一种是在文本前面加星号

# 标题1 s
## 标题2 a
### 标题3 n
#### 标题4 k
##### 标题5 o
###### 标题6 !

最多支持 6 个星号,依次表示 1-6 级标题。

彩蛋

依然是同样权重的四个选项,毫无倾斜性。星号 * 在 md 语法中出现较多,却偏偏不能构成标题。

Markdown 中的无序列表

题目

特别爱折腾的 @HUGE 最近爱上了 Markdown 语法,他让 $天骄 写了四种无序列表样式,其中有一种是不会构成「无序列表」的,它是:

A. 星号 *
B. 加号 +
C. 大于号 >
D. 减号 -

解答

在 Markdown 中,无序列表可以使用下面三种符号来触发:减号 -、加号 + 以及星号 *

每一种符号只有在连续使用时才构成一个列表:

- s
- a
- n
- k
- o

彩蛋

如果存有一些(错误的)印象,大于号也是合法的语法,作用是「引用」。

Markdown 中的有序列表

题目

特别爱折腾的 @HUGE 最近爱上了 Markdown 语法,他让 $天骄 写个「有序列表」,可是 $天骄 剑走偏锋,让 @HUGE 非常为难。 $天骄 写道:

3. item 1
3. item 2
3. item 3
4. item 4

解答

那么最后解析出来的序号应该是:

A. 1 2 3 4
B. 3 4 5 6
C. 3 3 3 4
D. 3 3 3 3

在 Markdown 中,有序列表的构成方式是数字 1-9 后面加上小数点 . 或者右括号 )

编号的起始数字是由列表中第一项的数字决定的,而之后其他列表项前使用任何数字都不影响列表编号递增。

因此这题的起始编号是 3,随后依次递增,最终形成:

3. item 1
4. item 2
5. item 3
6. item 4

彩蛋

A 选项:有序列表从 1 开始呀!
B 选项:有序列表从第一个数字开始吧?
C 选项:前面写了几就是几。
D 选项:根据前两个序号构成等差数列……