Git 使用中的教训:签名提交确保代码完整可信(1)(2)
大量合并的管理
到此刻为止,我们讨论的都是应用补丁或者合并单个提交。接下来,假设我们接收到一个对有300个提交的我向你保证这么做很正常)某个功能或者漏洞修补的pull请求,我们该怎么做的?这时我们可以选择下面其中的一种方法:
你选择三种方法中的哪一个取决于具体项目中哪个因素最重要且最可行。特别是:
-
如果历史信息对你来说不怎么重要,那么你只要要求压缩所有提交方法1)就可以避免许多麻烦。
-
如果历史信息对你很重要,而且你没有足够的时间审核各个提交:
-
如果你明了方法2的风险,那么就可以采用方法2。
-
否则,采用方法3,但是不要自动进行签名处理,这样你才能查看到每个提交。如果你希望保存历史信息,那么请这么做。
-
上面罗列的方法1可以很容易地解决前一节的所讨论的问题。
方法2)
方法2就像给git merge传递-S参数那样简单。如果合并运行的非常快也就是说,所有的提交都只是对HEAD进行修改,而没有进行任何合并),那么你就必须使用--no-ff选项,强制进行合并提交。
- # set up another branch to merge
- $ git checkout -b bar
- $ echo bar > bar
- $ git add bar
- $ git commit -m 'Added bar'
- $ echo bar2 >> bar
- $ git commit -am 'Modified bar'
- $ git checkout master
- # perform the actual merge (will be a fast-forward, so --no-ff is needed)
- $ git merge -S --no-ff bar
- # ^ GPG-sign merge commit You need a passphrase to unlock the secret key for
- user: "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
- 4096-bit RSA key, ID 8EE30EAB, created 2011-06-16
- Merge made by the 'recursive' strategy.
- bar | 2 ++
- 1 file changed, 2 insertions(+)
- create mode 100644 bar
查看日志,你会看到以下内容:
- $ git log --show-signature
- commit ebadba134bde7ae3d39b173bf8947a69be089cf6
- gpg: Signature made Sun 22 Apr 2012 11:36:17 AM EDT using RSA key ID 8EE30EAB
- gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
- Merge: 652f9ae 031f6ee
- Author: Mike Gerwitz <mike@mikegerwitz.com>
- Date: Sun Apr 22 11:36:15 2012 -0400
- Merge branch 'bar'
- commit 031f6ee20c1fe601d2e808bfb265787d56732974
- Author: Mike Gerwitz <mike@mikegerwitz.com>
- Date: Sat Apr 21 17:35:27 2012 -0400
- Modified bar
- commit ce77088d85dee3d687f1b87d21c7dce29ec2cff1
- Author: Mike Gerwitz <mike@mikegerwitz.com>
- Date: Sat Apr 21 17:35:20 2012 -0400
- Added bar
- # [...]
注意合并提交包含了签名,而合并所涉及的两个提交031f6ee和ce77088)却不包含签名。这就是问题所在---如果提交031f6ee中含有文章一开始所讲述的故事中提到的后门,该怎么做呢?这个提交可以认为是你授权的,然而由于没有签名,所以这样的提交可以由任何人授权。再者,如果提交ce77088里含有已经在031f6ee提交里删除的恶意代码,那么在对两个代码分支进行差异化比较时就不会把恶意代码呈现出来。不过,这是另一个需要安全策略定位的问题。你是否要审核每个提交呢? 如果这么做,那么对提交审核时就会发现任何潜在的问题,同时不需要单独对每个提交进行签名。合并本身就表示"是的,我已经对每个提交单独进行了审核,并没有发现这些修改带了了任何问题。"
如果单独对每个提交进行审核承担的责任太大,那么请考虑使用 方法1。
方法3)
上面所列的方法3很明确也很显然要多每个提交进行审核;而方法2只要求你懒洋洋的瞥一下提交或者根本连瞥一下都不需要。也就是说,你可以在方法3里通过自动对每个提交进行签名做同方法2一样的事情,不过这样就可能认为完全不需要方法3。使用哪一方法,你自己评判。
要使的方法3远端可执行,尤其是在含有大量提交的情况下仍然能够远端可执行方法3的唯一方法是要做到这一点:针对每一次提交,我们都不需要重新输入密钥所对应的密码。要做到这一点,我们需要使用 gpg-agent,它会安全地把密码存储在内存中,以便下一次请求时使用。通过使用gpg-agent,我 们就可以只提示一次输入密码。依据gpg-agent的不同启动方式,你一定要确保在完成工作后以不同的方式杀死该进程!
可以采用许多种方法对每个提交进行签名。总的来说,由于对一个提交进行签名就意味着有一个全新的提交,那么选择哪种签名方法就显得有那么一点重要了。例如,如果你愿意,那么你可以选择每个提交,然后给每个提交加上-S --amedn选项,不过不会把这些提交看作一次合并,而且除非合并运行的非常快,否则)在查看分支的历史信息的时候会非常迷惑。因此,再次强调一下,除非合并提交运行的非常快,否则)我们将确定一个能够生成合并提交的方法。实现这个的一种方法就是交互式地对每个提交进行基线更新,这样你就可以非常容易地查看到代码差异,给提交签名,继续在该提交的基础上进行下一个提交。
- # create a new audit branch off of bar
- $ git checkout -b bar-audit bar
- $ git rebase -i master
- # | ^ the branch that we will be merging into
- # ^ interactive rebase (alternatively: long option --interactive)
首先,我们根据bar代码分支创建一个新的代码分支---bar-audit----可以对其进行基线更新参考说明 方法2中创建的bar代码分支)。然后,为了能够逐个执行合并到master中的每个提交,我们需要执行一个把master当作上级分支的基线更新。这将会显示哪些bar-audit实际上是bar)里有的而master里没有的所有提交,接着用你所选的编辑器打开:
- e ce77088 Added bar
- e 031f6ee Modified bar
- # Rebase 652f9ae..031f6ee onto 652f9ae
- #
- # Commands:
- # p, pick = use commit
- # r, reword = use commit, but edit the commit message
- # e, edit = use commit, but stop for amending
- # s, squash = use commit, but meld into previous commit
- # f, fixup = like "squash", but discard this commit's log message
- # x, exec = run command (the rest of the line) using shell
- #
- # If you remove a line here THAT COMMIT WILL BE LOST.
- # However, if you remove everything, the rebase will be aborted.
- #
修改这些提交,用e(或者edit)来替代所有pick,如上所示。如果你使用的是vim,那么你还可以使用ex命令:%s/^pick/e/;根据所用编辑器,调整正则表达式格式)。保存,然后关闭。这样就会给呈现首次的也就是最早的)提交:
- Stopped at ce77088... Added bar
- You can amend the commit now, with
- git commit --amend
- Once you are satisfied with your changes, run
- git rebase --continue
- # first, review the diff (alternatively, use tig/gitk)
- $ git diff HEAD^
- # if everything looks good, sign it
- $ git commit -S --amend
- # GPG-sign ^ ^ amend commit, preserving author, etc
- You need a passphrase to unlock the secret key for
- user: "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
- 4096-bit RSA key, ID 8EE30EAB, created 2011-06-16
- [detached HEAD 5cd2d91] Added bar
- 1 file changed, 1 insertion(+)
- create mode 100644 bar
- # continue with next commit
- $ git rebase --continue
- # repeat.
- $ ...
- Successfully rebased and updated refs/heads/bar-audit.
浏览一下日志,我们就会看到已经重写了提交,并且包含了签名不过,SHA-1哈希值却不匹配):
- $ git log --show-signature HEAD~2..
- commit afb1e7373ae5e7dae3caab2c64cbb18db3d96fba
- gpg: Signature made Sun 22 Apr 2012 01:37:26 PM EDT using RSA key ID 8EE30EAB
- gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
- Author: Mike Gerwitz <mike@mikegerwitz.com>
- Date: Sat Apr 21 17:35:27 2012 -0400
- Modified bar
- commit f227c90b116cc1d6770988a6ca359a8c92a83ce2
- gpg: Signature made Sun 22 Apr 2012 01:36:44 PM EDT using RSA key ID 8EE30EAB
- gpg: Good signature from "Mike Gerwitz (Free Software Developer) <mike@mikegerwitz.com>"
- Author: Mike Gerwitz <mike@mikegerwitz.com>
- Date: Sat Apr 21 17:35:20 2012 -0400
- Added bar
接下来,我们就可以像往常一样继续把代码合并到master里。下面要考虑的是是否要像方法2那样对合并提交进行签名的问题。在我们所举的例子里,合并是快速运行的,因此就没有必要进行合并提交了由于要进行合并的提交都已经签名了,我们就不需要纯粹为了对其进行签名而使用--no-ff选项创建合并提交了)。不过,想想你亲自执行了检查而其他人进行真正的合并这种情况;也许项目是这样运行的:项目管理者必须对代码进行审核,然后对其签名,而其他开发者则负责合并和管理冲突。在这种情况下,你可能就需要对谁合并了修改有一个清新的记录。
评论暂时关闭