Skip to content

Commit 88d6013

Browse files
spacewanderluozexuan
authored andcommitted
update 08-customizing-git policy according to @gisphm's comment
1 parent 6c5ae8a commit 88d6013

File tree

1 file changed

+25
-26
lines changed

1 file changed

+25
-26
lines changed

book/08-customizing-git/sections/policy.asc

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
=== 使用强制策略的一个例子
33

44
(((policy example)))
5-
在本节中,你将应用前面学到的知识建立这样一个 Git 工作流程:检查提交信息的格式,并且指定特定用户只能修改项目中特定的子目录
6-
你将完成一个客户端脚本来提示开发人员他们的推送是否会被拒绝,以及一个服务器端脚本来实际执行这些策略。
5+
在本节中,你将应用前面学到的知识建立这样一个 Git 工作流程:检查提交信息的格式,并且指定只能由特定用户修改项目中特定的子目录
6+
你将编写一个客户端脚本来提示开发人员他们的推送是否会被拒绝,以及一个服务器端脚本来实际执行这些策略。
77

88
我们待会展示的脚本是用 Ruby 写的,部分是由于我习惯用它写脚本,另外也因为 Ruby 简单易懂,即便你没写过它也能看明白。
9-
不过任何其他语言也一样适用。所有 Git 自带的示例脚本都是用 Perl 或 Bash 写的,所以你能从它们中找到相当多的这两种语言的钩子示例。
9+
不过任何其他语言也一样适用。所有 Git 自带的示例钩子脚本都是用 Perl 或 Bash 写的,所以你能从它们中找到相当多的这两种语言的钩子示例。
1010

1111
==== 服务器端钩子
1212

@@ -18,7 +18,7 @@
1818
* 用户准备推送的修订版本(revision)
1919

2020
如果推送是通过 SSH 进行的,还可以获知进行此次推送的用户的信息。
21-
如果你允许所有操作都通过公匙授权的单一帐号(比如“git”)进行,就有必要提供一个 shell 包装脚本,依据公匙判断用户的身份,并且存储到一个环境变量中
21+
如果你允许所有操作都通过公匙授权的单一帐号(比如“git”)进行,就有必要通过一个 shell 包装脚本依据公匙来判断用户的身份,并且相应地设定环境变量来表示该用户的身份
2222
下面就假设 `$USER` 环境变量里存储了当前连接的用户的身份,你的 update 脚本首先搜集一切需要的信息:
2323

2424
[source,ruby]
@@ -40,13 +40,13 @@ puts "(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})"
4040
[[_enforcing_commit_message_format]]
4141
===== 指定特殊的提交信息格式
4242

43-
你的第一项任务是指定每一条提交信息都必须遵循某种特殊的格式
43+
你的第一项任务是要求每一条提交信息都必须遵循某种特殊的格式
4444
作为目标,假定每一条信息必须包含一条形似“ref: 1234”的字符串,因为你想把每一次提交对应到问题追踪系统(ticketing system)中的某个事项。
4545
你要逐一检查每一条推送上来的提交内容,看看提交信息是否包含这么一个字符串,然后,如果某个提交里不包含这个字符串,以非零返回值退出从而拒绝此次推送。
4646

4747
把 `$newrev` 和 `$oldrev` 变量的值传给一个叫做 `git rev-list` 的 Git 底层命令,你可以获取所有提交的 SHA-1 值列表。
4848
`git rev-list` 基本类似 `git log` 命令,但它默认只输出 SHA-1 值而已,没有其他信息。
49-
所以要获取由 SHA 值表示的从一次提交到另一次提交之间的所有 SHA 值,可以运行
49+
所以要获取由一次提交到另一次提交之间的所有 SHA 值,可以像这样运行
5050

5151
[source,console]
5252
----
@@ -58,10 +58,10 @@ dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a
5858
17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475
5959
----
6060

61-
你可以截取这些输出内容,循环遍历其中每一个 SHA 值,找出与之对应的提交信息,然后用正则表达式来测试该信息
61+
你可以截取这些输出内容,循环遍历其中每一个 SHA 值,找出与之对应的提交信息,然后用正则表达式来测试该信息包含的内容
6262

6363
下一步要实现从每个提交中提取出提交信息。
64-
使用另一个叫做 `git cat-file` 的底层命令可以获得原始的提交数据
64+
使用另一个叫做 `git cat-file` 的底层命令来获得原始的提交数据
6565
我们将在 <<_git_internals>> 了解到这些底层命令的细节;现在暂时先看一下这条命令的输出:
6666

6767
[source,console]
@@ -85,7 +85,7 @@ changed the version number
8585
----
8686

8787
你可以用这条咒语从每一个待推送的提交里提取提交信息,然后在提取的内容不符合要求时退出。
88-
为了退出脚本和拒绝此次推送,这里需要以非零值退出
88+
为了退出脚本和拒绝此次推送,返回非零值
8989
整个脚本大致如下:
9090

9191
[source,ruby]
@@ -112,12 +112,12 @@ check_message_format
112112

113113
假设你需要添加一个使用访问权限控制列表的机制,来指定哪些用户对项目的哪些部分有推送权限。
114114
某些用户具有全部的访问权,其他人只对某些子目录或者特定的文件具有推送权限。
115-
为了实现这一点,你要把相关的规则写入一个名为 `acl` 的文件里,并把它放到服务器上的 Git 裸仓库中,
115+
为了实现这一点,你要把相关的规则写入位于服务器原始 Git 仓库的 acl 文件中
116116
你还需要让 `update` 钩子检阅这些规则,审视推送的提交内容中被修改的所有文件,然后决定执行推送的用户是否对所有这些文件都有权限。
117117

118118
先从写一个 ACL 文件开始吧。
119119
这里使用的格式和 CVS 的 ACL 机制十分类似:它由若干行构成,第一项内容是 `avail` 或者 `unavail`,接着是逗号分隔的适用该规则的用户列表,最后一项是适用该规则的路径(该项空缺表示没有路径限制)。
120-
各项由 `|` 字符隔开
120+
各项由管道符 `|` 隔开
121121

122122
在本例中,你会有几个管理员,一些对 `doc` 目录具有权限的文档作者,以及一位仅对 `lib` 和 `tests` 目录具有权限的开发人员,相应的 ACL 文件如下:
123123

@@ -130,7 +130,7 @@ avail|schacon|tests
130130
----
131131

132132
首先把这些数据读入你要用到的数据结构里。
133-
在本例中,为简明扼要起见,我们暂时只实现 `avail` 的规则。
133+
在本例中,为保持简洁,我们暂时只实现 `avail` 的规则。
134134
下面这个方法生成一个关联数组,它的键是用户名,值是一个由该用户有写权限的所有目录组成的数组:
135135

136136
[source,ruby]
@@ -165,7 +165,7 @@ end
165165
"ebronte"=>["doc"]}
166166
----
167167

168-
既然拿到了用户权限的数据,接下来你需要找出提交都涉及了哪些路径,从而才能保证推送者对所有这些路径都有权限。
168+
既然拿到了用户权限的数据,接下来你需要找出提交都修改了哪些路径,从而才能保证推送者对所有这些路径都有权限。
169169

170170
使用 `git log` 的 `--name-only` 选项(在第二章里简单地提过),我们可以轻而易举的找出一次提交里修改的文件:
171171

@@ -210,7 +210,7 @@ check_directory_perms
210210
----
211211

212212
通过 `git rev-list` 获取推送到服务器的所有提交。
213-
然后,对于每一个提交,找出它修改的文件,然后确保推送者对这些文件都具有权限
213+
接着,对于每一个提交,找出它修改的文件,然后确保推送者具有这些文件的推送权限
214214

215215
现在你的用户没法推送带有不正确的提交信息的内容,也不能在准许他们访问范围之外的位置做出修改。
216216

@@ -257,7 +257,7 @@ error: hooks/update exited with error code 1
257257
error: hook declined to update refs/heads/master
258258
----
259259

260-
第一行是我们的脚本输出的,再往下是 Git 在告诉我们 update 脚本退出时返回了非零值因而推送遭到了拒绝。
260+
第一行是我们的脚本输出的,剩下两行是 Git 在告诉我们 update 脚本退出时返回了非零值因而推送遭到了拒绝。
261261
最后一点:
262262

263263
[source]
@@ -281,17 +281,17 @@ error: failed to push some refs to 'git@gitserver:project.git'
281281

282282
==== 客户端钩子
283283

284-
这种方法的缺点在于,用户发现自己推送的提交遭到拒绝后,往往就会向你抱怨
285-
辛辛苦苦写成的代码在最后时刻惨遭拒绝是十分让人沮丧且具有迷惑性的;更可怜的是他们不得不修改提交历史来解决问题,这可不是一个让人心安的方法
284+
这种方法的缺点在于,用户推送的提交遭到拒绝后无法避免的抱怨
285+
辛辛苦苦写成的代码在最后时刻惨遭拒绝是十分让人沮丧且具有迷惑性的;更可怜的是他们不得不修改提交历史来解决问题,这个方法并不能让每一个人满意
286286

287-
逃离这种两难境地的法宝是给用户一些客户端的钩子,在他们犯错的事情的时候给以警告
288-
然后呢,用户们就能在提交之前亡羊补牢
287+
逃离这种两难境地的法宝是给用户一些客户端的钩子,在他们犯错的时候给以警告
288+
然后呢,用户们就能趁问题尚未变得更难修复,在提交前消除这个隐患
289289
由于钩子本身不跟随克隆的项目副本分发,所以你必须通过其他途径把这些钩子分发到用户的 `.git/hooks` 目录并设为可执行文件。
290290
虽然你可以在相同或单独的项目里加入并分发这些钩子,但是 Git 不会自动替你设置它。
291291

292292
首先,你应该在每次提交前核查你的提交信息,这样才能确保服务器不会因为不合条件的提交信息而拒绝你的更改。
293293
为了达到这个目的,你可以增加 `commit-msg` 钩子。
294-
如果你使用该钩子来读取作为第一个参数传递的提交信息,然后与规定的格式作比较,你就可以使 Git 在提交信息格式不对的情况下,拒绝提交
294+
如果你使用该钩子来读取作为第一个参数传递的提交信息,然后与规定的格式作比较,你就可以使 Git 在提交信息格式不对的情况下拒绝提交
295295

296296
[source,ruby]
297297
----
@@ -307,7 +307,7 @@ if !$regex.match(message)
307307
end
308308
----
309309

310-
如果这个脚本位于正确的位置 (`.git/hooks/commit-msg`) 并且是可执行的, 并且你的提交信息格式不对,你会看到:
310+
如果这个脚本位于正确的位置 (`.git/hooks/commit-msg`) 并且是可执行的,你提交信息的格式又是不正确的,你会看到:
311311

312312
[source,console]
313313
----
@@ -359,7 +359,7 @@ check_directory_perms
359359
----
360360

361361
这和服务器端的脚本几乎一样,除了两个重要区别。
362-
第一,ACL 文件的位置不同,因为这个脚本在当前工作目录运行,而非 Git 目录。
362+
第一,ACL 文件的位置不同,因为这个脚本在当前工作目录运行,而非 `.git` 目录。
363363
ACL 文件的路径必须从
364364

365365
[source,ruby]
@@ -401,7 +401,7 @@ files_modified = `git diff-index --cached --name-only HEAD`
401401

402402
下面是一个检查这个问题的 `pre-rebase` 脚本示例。
403403
它获取所有待重写的提交的列表,然后检查它们是否存在于远程引用中。
404-
一旦它发现其中一个提交是在某个远程引用中可达的(reachable),它就放弃此次变基
404+
一旦发现其中一个提交是在某个远程引用中可达的(reachable),它就终止此次变基
405405

406406
[source,ruby]
407407
----
@@ -427,8 +427,7 @@ target_shas.each do |sha|
427427
end
428428
end
429429
----
430-
这个脚本利用了一个第六章“修订版本选择”一节中不曾提到的语法。
431-
通过运行这个命令可以获得一系列之前推送过的提交:
430+
这个脚本利用了一个第六章“修订版本选择”一节中不曾提到的语法。通过运行这个命令可以获得一系列之前推送过的提交:
432431

433432
[source,ruby]
434433
----
@@ -437,7 +436,7 @@ end
437436
----
438437

439438
`SHA^@` 语法会被解析成该提交的所有父提交。
440-
该命令会列出远程分支最新的提交可达的,但在所有我们尝试推送的提交的 SHA 值的所有父提交中不可达的提交——也就是快进的提交。
439+
该命令会列出在远程分支最新的提交中可达的,却在所有我们尝试推送的提交的 SHA 值的所有父提交中不可达的提交——也就是快进的提交。
441440

442441
这个解决方案主要的问题在于它有可能很慢而且常常没有必要——只要你不用 `-f` 来强制推送,服务器就会自动给出警告并且拒绝接受推送。
443442
然而,这是个不错的练习,而且理论上能帮助你避免一次以后可能不得不回头修补的变基。

0 commit comments

Comments
 (0)