用git commit --amend覆盖的信息是否可以通过git push公开?

时间:2018-04-09 20:11:25

标签: git

我调查了一个棘手的问题,最后决定通过逐步减少我的闭源项目来创建一个SSCCE。在每个步骤中,我都验证了问题发生并且gitgit commit --amend一起提交,即只有一个提交。现在,我想在像gitlab.com或github.com这样的FLOSS代码托管平台上发布SSCCE作为公共项目。

我是否有可能暴露任何已被git commit --amend覆盖的文件内容?将推送的当前提交可以视为保存以发布。

我知道我可以删除存储库并在本地重新创建它。这是一个值得学习的问题。

1 个答案:

答案 0 :(得分:1)

(警告:这是一个很长的答案;我没有时间写一个较短的答案。部分是在做其他事情之间写的,文本中可能存在一些语义空白。)

这个答案有很多部分,但简短的版本是git push通常会推送一组最小的提交,这会带来最小的树和文件集。这意味着在正常情况下,您将在这里安全。

可能存在与您有关的异常案例的可能性,这些可能是创建没有其他历史记录的新存储库的充分理由。

让我们先看看git commit --amend真正做了什么,因为它实际上并没有修改任何提交。为实现这一目标,我们必须从git commit如何在低级别工作开始,这意味着查看实际的提交。

这是来自Git的Git存储库中的一个:

$ git rev-parse HEAD
468165c1d8a442994a825f3684528361727cd8c0
$ git cat-file -p 468165c1d8a442994a825f3684528361727cd8c0 | sed 's/@/ /'
tree 6a54cb7c68d97e863a28478d728c58a1e47f0b4f
parent 1614dd0fbc8a14f488016b7855de9f0566706244
author Junio C Hamano <gitster pobox.com> 1522689215 -0700
committer Junio C Hamano <gitster pobox.com> 1522689215 -0700

Git 2.17

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

这是一个典型的正常提交:与所有提交一样,它有一个tree,并且像大多数但不是所有提交一样,它有一个parent行。它有一个作者和提交者 - 每个提供三个信息:名称,电子邮件地址和时间戳 - 它有一条日志消息,它包含第一个空白行之后的所有行。

父母或父母告诉Git在此提交之前提交。其他提交可能有两个或多个父项 - 这些是合并提交 - 并且至少有一个提交,这是您在存储库中创建的第一个提交,其中没有父项,因为没有来到它之前。 parent行允许Git将提交链接在一起。没有父项的提交是 root 提交,其中链结束。

提交的文件存储在tree对象下面,这有点大 - 这里只是其中的一部分:

100644 blob 536e55524db72bd2acf175208aef4f3dfc148d42    COPYING
040000 tree ccab6cfb14e8e198eb4981fbfbee7ac091478119    Documentation
100755 blob 1b4624c876dae8f38f7c9e13f82d11b6ead39c9b    GIT-VERSION-GEN
100644 blob c39006e8e7e5c5be2114b79d50135dc08e3d1aaa    INSTALL
100644 blob d38b1b92bdb2893eb4505667375563f2d6d4086b    LGPL-2.1
100644 blob a1d8775adb4b38a0340cd7d04184915f0ee65d28    Makefile

每个树条目提供模式,对象类型(从模式和底层对象隐式),底层对象的散列ID和路径名组件。对于某个目录中的文件,该组件是文件的名称;对于子树,组件是目录的名称。递归遍历所有tree对象让Git为每个文件构建完整路径名,当检查 out 提交时,Git会执行此递归行程以构建索引。 (我们通常可以忽略索引,但它本质上是递归扩展且因此扁平化的树,Git可以使用它来获取文件的完整路径名。)

实际文件内容存储在 blob 对象中,因此要查看名为COPYING的文件的内容:

$ git cat-file -p 536e55524db72bd2acf175208aef4f3dfc148d42 | head -3

 Note that the only valid version of the GPL as far as this project
 is concerned is _this_ particular version of the license (ie v2, not

所以,总结一下上面的内容:

  • 所有对象都有哈希ID。实际的哈希ID只是对象内容的加密校验和(包括前面的类型说明符,因此如果您从提交中创建一个blob,则blob具有与提交不同的哈希ID-这意味着对象的类型可以存储在对象中。)
  • 分支名称通过其哈希ID识别特定提交:例如,master = 468165c1d8a442994a825f3684528361727cd8c0(目前)。
  • 提交有一个 tree 对象,该对象按哈希ID包含文件和/或子树。递归枚举所有子树并收集所有文件哈希获取快照内容(仅限哈希ID;我们仍然必须提取实际的blob文本以获取真实内容)。
  • 提交有零个或多个提交。

正常提交添加和推送

因此,我们可以看到提交通常如何增长。我们从单个根提交开始,没有父节点,以及标识该提交的名称master

A   <--master

然后我们进行新的提交:在{{1}新的blob到索引之后,我们将Git打包当前索引作为新的树对象,将根提交的哈希ID写为{{ 1}}行,写出自己作为作者和提交者&#34;现在&#34;作为两个时间戳,写出我们的日志消息,并将整个事件转换为新的提交对象,该对象获取新的唯一哈希ID。我们的新提交git add已将parent作为其父级,因此,如果我们将新提交的哈希ID写入B,我们会得到:

A

重复足够长的时间,你有一长串的提交,以提交到master之类的分支名称结束。您现在可以A <-B <--master 这些提交到另一个Git存储库,如果您愿意:您的Git向他们发送所有您不具备的提交,例如,如果他们的{{ 1}}在提交master结束,并且您通过git push添加了master,您的Git会发送这五个提交,以及他们使用的任何树和文件对象在BC中找到。

使用G

A 如果我们已经有了一个链:

B

我们运行--amend,Git像往常一样创建一个新的提交--amend,但有一个例外:新提交的父项是/是父项当前提交。也就是说,新提交A--B--C <-- master 指向git commit --amend使用的相同提交:

D

提交对象D本身,以及树和任何子树以及提交C的文件blob,都仍在存储库中。他们将留在那里,直到有东西来移除它们。 (一旦没有名称,垃圾收集器 C / A--B--D <-- master 最终删除它们。但是我们的Git将有 reflog条目提供隐藏名称,因此保护他们一个月左右,所以他们至少会坚持这么久。)

假设服务器无论身在何处,都会提交CC。如果我们现在git gc,我们的Git将调用服务器,实际上, 1 从中获取其A所代表的哈希ID。这告诉我们的Git什么提交,因此树和blob,他们有,它告诉我们的Git我们的Git应该发送什么。在这种情况下,那只是提交B以及它(我们认为)服务器Git缺乏的任何相关对象。

即使我们正在修改&#34;这仍然适用。根提交。修改只是意味着使用当前提交的父级进行新提交,所以如果我们只有一个提交git push并且我们&#34;修改&#34;它,我们得到:

master

在确定要发送哪些提交以及任何必要的支持对象之后,我们的Git将它们打包成包文件,这会获得额外的压缩 - 这就是所有< em>计算对象和压缩对象输出是关于并发送包文件,接收Git会根据需要将其扩展回来。

这里的关键是包文件必要的对象 - 或者更确切地说,我们的Git 假设是必要的,基于提交和其他对象找到从我们专门告诉我们Git推送的提交中遍历我们的提交图,不包括他们Git告诉我们他们拥有的那些提交。

1 在这个例子中,我们的Git可以真正做到这一点。但是,在更复杂的情况下,我们的Git不一定会拥有他们的分支的提示。在这种情况下,通常的协议使用has / want交换,通过提交哈希ID来确定要发送的提交以及另一端已经拥有的提交。

并非所有传输方法都相同

以上都适用于确定要发送的对象。为了使它工作,我们的Git必须与服务器Git交谈,以找出服务器有什么。这是正常的(基于https或ssh的)推送系统,但并非所有传输都使用这样的系统。 The Pro Git Book has a chapter on the standard "dumb" and "smart" protocols,并提到push始终使用智能协议。因此,只要您的Git使用智能协议并且您不小心要求它发送不在单一提交D分支顶端的对象,您将只发送您关心的对象约。

但是,如果有人自上次进行此分析以来已经优化了什么呢?如果新的协议意识到他们的 Git什么都没有,那么你的 Git已经将所有对象打包成一个好的包文件,并且有大量的网络带宽,所以只是发送那个包文件?他们可能会所有你的对象,包括你(相信你)修改过的对象。它今天不会发生,但明天呢?

你不 担心这一点。它几乎肯定是安全的,甚至未来的优化可能会小心不要交出像这样的延迟对象。但是你愿意依靠它多少钱?