1

几个月前有人犯了罪。之后,已经完成了多个其他提交。是否可以通过修改或变基来查看是否有人更改了该特定提交的内容?如果是,如何?

4

1 回答 1

5

在 Git 中,提交永远不会改变。既不变基也不git commit --amend改变任何提交,因为这是不可能的。1

这里的诀窍在于定义“提交”。你怎么知道哪个提交是哪个?如果我说“在 Git 存储库中提交 Git”,那么那里有超过 40,000 个提交。 我指的是哪一个

我要告诉你的明确而明确的方法是让我给你哈希 ID,例如9b7cbb315923e61bb0c4297c701089f30e116750. 这是一个特定提交的真实名称:

$ git cat-file -p 9b7cbb315923e61bb0c4297c701089f30e116750 | sed 's/@/ /'
tree 4ba58c32960dcecc1fedede9c9362f5c10158f08
parent 77933f4449b8d6aa7529d627f3c7b55336f491db
author Junio C Hamano <gitster pobox.com> 1418845774 -0800
committer Junio C Hamano <gitster pobox.com> 1418845774 -0800

Git 2.2.1

Signed-off-by: Junio C Hamano <gitster pobox.com>

此名称永久附加到此特定提交。不过,这肯定是一个笨拙和丑陋的名字。有一个更短、更漂亮、更实用的名字不是很好吗?还有一个:我可以指出v2.2.1

$ git rev-parse v2.2.1^{commit}
9b7cbb315923e61bb0c4297c701089f30e116750

但实际上,v2.2.1根本不是 commit,它是一个tag。具体来说,它是一个标签名称(在name 下refs/tags/v2.2.1的文件中或文件中找到)指向一个带注释的标签对象,2而不是直接指向一个提交:packed-refsv2.2.1

$ git rev-parse v2.2.1
7c56b20857837de401f79db236651a1bd886fbbb

标签对象里面有提交 ID,加上一大堆额外的 goop,包括“PGP 签名”:

$ git cat-file -p v2.2.1 | sed 's/@/ /'
object 9b7cbb315923e61bb0c4297c701089f30e116750
type commit
tag v2.2.1
tagger Junio C Hamano <gitster pobox.com> 1418851265 -0800

Git 2.2.1
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAABAgAGBQJUkfPBAAoJELC16IaWr+bLjfgP/iA78fk3NkTEROoyIVq6kPDH
pZAlm4ObsKXAdl6sFqWe7xFxGExHYzJ5L3qGXs3VM+9Z3iDe2WZN3WbK3aFtYqfU
AYRSTpnPzDf4L0vfyqiFS7//+LoeM2TogAV7SLdehMlodsL5HR6FiSz1zffSq8D0
Ci4XpGWHkqXLhfvUPC7foCgGpf7l38gsbJPbdkyKLK9/wtLSfkk45vK+wY6o3CCv
JKBFr468958fvw+j73nxiT+Vne7TeL1Bq1kCq9M65dAjOpFjZiD408NaF7jTcNcx
TMjdKoVlDNFHcUPMv9B5C308sRVUylmeUzb8XrQNji0+1NA5ivVgDfZsudWUtlTj
jo9xku0Np4IdXPwxJNlO5tC2rnof4gdD4jWPJj/DvellNKCDXuLuXDZSKZDI9GSr
OzLsad8uFX3MySPe+evIVF6qGS2KzI8PGNrohqWaPkX8cug22EW7lKJFpjYJb5gP
3nJUJvbsrMeyoH/GqxPzA5clqMGtsirnTiapMILNRmlC+3rzc0DkLw90BM6vKNOC
eDTOI9Xj1JS9qbD6fEkxVNrXRDz0TFbtpFbFTtKk4zfAc/jTOqE9fqpV7afoQfON
e1NwrjR5Kcts7ev23Y0G1WH3t2L0N2/q27kcjrulCEH1vtXlmaZFU6o+WKUVV7iH
/YQnjNUOgRxQ1zBGof7h
=yJ4Q
-----END PGP SIGNATURE-----

PGP 签名让我们决定我们是否相信 Junio C Hamano 真的制作并签署了这个标签。它使用比 SHA-1 更强大的加密数字签名形式(这很好,因为 SHA-1 至少在理论上是可破解的),它还支持分布式验证和撤销签名的能力(SHA-1 本身就是这样做的)不是)。

但是,最后,只有我们信任和/或可以验证的人做出了这样的 PGP 签名标签,或者 PGP 签名了提交时,这才会对我们有所帮助。从理论上讲,对每个提交进行签名可能会更强一些,因为那时提交上直接有一个数字签名;但在实践中,签署标签更方便,而且同样好,因为我们不经常破坏 SHA-1(而且,至少使用当前的蛮力方法,如果我们这样做,它会留下明显的痕迹,尽管那是远远超出了这个答案的范围,也有点超出了我的正确描述——密码学不是我的领域)。


1好吧,如果你能破解 SHA-1 哈希,理论上是有可能的。如果您想出一个新的、不同的对象但仍会产生相同的哈希值,Git 的行为方式意味着如果您已经拥有旧对象,您将永远不会拿起这个新对象。此规则适用于所有 Git 对象(提交、树、带注释的标签和 blob),所有这些对象都由它们的哈希命名。

为了使他们看起来git rebase像是更改了提交,要做的事情是制作现有提交的新副本,然后将名称改组。新的提交具有新的、不同的哈希值,并且由于以后(后代)提交实际上包含其直接祖先(父)提交的哈希值,因此“更改”了一个提交的哈希值(即,将提交对象复制到新的不同提交对象) 强制更改在其余提交中冒泡。然后,我们将现有(短、分支或标签)名称重新指向新链的末端。git commit --amend

这就是为什么给定一个我们认为可信的端点,我们可以将该信任扩展到链或树中的每个先前对象。技术术语是Merkle 树

2这使它成为 Git 所称的“带注释的标签”:一个标签名称(它本身就是一个“轻量级标签”)指向一个带注释的标签对象,存储在 Git 存储库中,标签对象指向其他的Git 对象——通常是一个提交,但也可能是另一个标签,甚至是一棵树或一个 blob。然而,即使是“另一个标签”也很少见——在 Git 的 Git 存储库中只有三个标签——而另外两个几乎闻所未闻。

于 2016-11-09T17:42:28.147 回答