几个月前有人做过一些事情。之后,已经完成了多个其他提交。是否可以通过修改或重新定位来查看某人是否更改了某个提交的内容?如果是,怎么样?
答案 0 :(得分:3)
Git中的提交永远不会更改。 rebase和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>
此名称永久附加到此特定提交。不过,这肯定是一个笨拙而丑陋的名字。拥有一个更短,更漂亮的wieldy名字会不会很好?还有一个:我可以指向v2.2.1
:
$ git rev-parse v2.2.1^{commit}
9b7cbb315923e61bb0c4297c701089f30e116750
但事实上,v2.2.1
根本不是提交,它是标记。具体来说,它是一个标记名称(位于refs/tags/v2.2.1
或名称为packed-refs
的{{1}}文件中),指向带注释的标记对象, 2 而不是直接提交:
v2.2.1
标签对象里面有提交ID,加上一大堆额外的goop,包括&#34; PGP签名&#34;:
$ git rev-parse v2.2.1
7c56b20857837de401f79db236651a1bd886fbbb
PGP签名让我们决定是否相信Junio C Hamano真的制作并签署了这个标签。它使用比SHA-1更强的加密数字签名形式(这是好的,因为SHA-1至少在理论上是易碎的),它同时支持分布式验证和撤销签名的能力(SHA-1本身没有)。
最后,这只会帮助我们如果我们信任的人和/或可以验证已经制作了这样一个PGP签名的标签,或者PGP签名提交。理论上,签署每个提交可能会更强一些,因为那时直接在提交上有一个数字签名;但在实践中,签署标签要方便得多,同样好,因为我们不经常破坏SHA-1(至少用现有的蛮力方法,如果我们这样做,它会留下明显的标记,虽然这超出了这个答案的范围,并且在某种程度上超出了我的描述 - 密码学不是我的领域。)
1 好吧,如果你能break the SHA-1 hash,理论上是可行的。如果你想出一个新的,不同的对象,然而产生相同的 hash ,Git的行为方式意味着如果你已经拥有旧的对象,你就不会选择这个新对象。此规则适用于所有Git对象(提交,树,注释标记和blob),所有这些对象都以其哈希命名。
$ 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-----
和git rebase
做什么,使似乎就像更改了提交一样,是为了制作现有提交的新副本,然后随机播放名称围绕。新的提交有新的,不同的哈希,并且因为以后(后代)提交字面上包含其直接祖先(父)提交的哈希,&#34;更改&#34;一个提交的散列(即,将提交对象复制到新的,不同的提交对象)迫使更改在其余的提交中向下冒泡。然后,我们将现有的(短的,分支的或标记的)名称重新指向新链的顶端。
这就是为什么,鉴于我们认为可信任的终点,我们可以将该信任扩展到链或树中的每个先前对象。技术术语是Merkle tree。
2 这使得Git称之为&#34;带注释的标签&#34;:标签名称(它本身就是一个&#34;轻量级标签&#34;)指向一个带注释标记的对象,存储在Git存储库中,标记对象指向其他一些Git对象 - 通常是提交,但可能是另一个标记,甚至是树或blob。然而,甚至&#34;另一个标签&#34;有点罕见 - 在Git的Git存储库中只有三个 - 而其他两个几乎闻所未闻。