【问题标题】:How do I keep png files in git without tracking them?如何将 png 文件保存在 git 中而不跟踪它们?
【发布时间】:2020-12-16 12:44:30
【问题描述】:

我的 bitbucket 存储库中有我的自述文件所需的 png 文件。但由于这些是二进制文件,所以当 sonar bitbucket 插件在它们上运行 diff 时出现错误。

如何在不被跟踪的情况下保留文件?

我运行git update-index --skip-worktree filename,然后运行git status,但标志没有反映。它说——

Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

不确定我是否需要从存储库中删除文件,然后添加跳过工作树标志。有人可以告诉我我做错了什么,或者是否有更好的方法来保存图像文件而不对它们运行 diff?谢谢。

【问题讨论】:

标签: git version-control bitbucket


【解决方案1】:

在主题行中对您的问题的字面回答:

如何在不跟踪的情况下将 png 文件保存在 git 中?

只是“你不知道”。这是因为在 Git 中,tracked file 是存在于 Git 的 index 中的文件。

Git 的索引是您必须了解的关键数据结构(否则 Git 的行为是莫名其妙的)。它的名字太笼统,也太糟糕了,以至于它还有两个名字:它也被称为暂存区,或者有时——现在很少见——缓存。这些天来,您主要在某些命令的某些标志中看到术语“缓存”,例如git rm --cachedgit diff --cached。但是这三个术语实际上都指的是同一件事。

索引的功能复杂而繁多,但实际上您需要了解的只是其中的一小部分。主要的——这也是人们称它为 staging area 的原因——它始终保存将进入您的 next 提交的文件的副本。

“副本”一词可能应该在此处用引号引起来,因为索引中的内容确实将进入下一次提交的内容。提交确实存储文件,但它们以冻结、压缩、Git 化和重复内容删除的形式存储它们。这允许 Git 将 每个 文件存储在 每个提交 中。事实上,一个新的提交主要存储与前一个提交相同的文件,并且 Git 对每个文件的内容进行重复数据删除,这意味着文件的新“副本”不占用空间。对于索引中的“副本”也是如此:它们是预先去重的,因此只要它们与 当前 提交匹配,它们就不会占用空间。1 不过,除此之外,它们确实就像每个文件的副本一样。

换句话说,Git 在任何时候都有三个您正在处理或使用的每个(已提交)文件的副本:

  • 当前提交中有一个冻结的,永久保存。您无法更改此格式,并且它不是您可以用于任何内容的格式,但 Git 可以读取它。

  • Git 的索引中有一个“副本”,准备进入 next 提交。这个副本开始匹配提交的副本(好吧,通常无论如何)。

    此索引副本是冻结的格式,但实际上并未冻结。如果您修改工作树副本,则必须运行 git add 来更新 index 副本。2

  • 最后,当然还有文件的普通读/写副本。此副本位于您的工作树工作树中。这是您可以看到、使用和更改的版本,但它实际上 根本不在 Git 中。这不是提交中的副本,也不是准备进入 next 提交的副本 - 这就是为什么如果您更改此工作树副本必须git add 文件.

当您运行 git commit 时,Git 从索引中的任何内容创建 new 快照。在您运行git checkout 和运行git commit 之间, 可以使用git add 和/或git rm 控制Git 索引中的内容。因此,Git 索引中的文件副本可以更改,甚至完全删除。一旦你真正开始运行git commit,这会影响 next 提交。在那之前,它只是“暂存”更新的文件。

git status 命令通过运行两个比较来工作:

  • 第一个比较告诉您当前提交和索引之间的不同。任何不同的地方都准备提交
  • 第二个比较告诉您索引和工作树之间的不同。任何不同之处都不会为提交上演

由于存在三个副本,这就是文件可以同时被暂存和未暂存的方式:提交版本、索引版本和工作树版本都是不同的版本。)

无论如何,我们回到跟踪文件的定义:跟踪文件是您工作树中的任何文件 Git的索引现在。 未跟踪的文件是一个文件,它现在在你的工作树中,但现在不在 Git 的索引中。它进入 Git 的索引是因为 (a) 它来自提交, 和/或 (b) 你在上面运行了git add。如果要在新提交中,它必须 在 Git 的索引中。如果它现在不在 Git 的索引中,例如,因为你在上面使用了 git rm,它就不会在 next 提交中。如果您不想在该提交中使用它,那很好;但如果您确实希望在该提交中使用它,则需要将其放回 Git 的索引中。

我跑了git update-index --skip-worktree filename ...

这个,以及它相关的--assume-unchanged 变体,只是在文件的索引条目中设置一个特殊位(必须是 Git 的索引中,以便有空间放置该位放)。当该位被设置时,Git 会经常——不总是,但经常——假装文件的工作树副本与文件的索引副本匹配。然后它将不理会索引副本。因此,如果索引副本当前与当前提交副本匹配,则设置该位可确保未来的git add 使用工作树副本(或缺少工作树副本)来更新索引副本.索引副本仅保留在索引中,仍然与当前提交匹配。

(当你使用git checkoutgit switch 切换到一个新的不同的提交时,Git 不得不更新各种文件的索引副本,Git 不会遵守假设不变或跳过工作树位,如果更改索引副本会破坏工作树中任何未提交的工作,通常会抱怨并停止提交更改。但这至少有点危险,因为在.gitignore中列出文件可以让Git有权销毁工作树副本。)


1它们需要一点空间来保存文件名称、缓存数据以及 Git 认为有助于 Git 工作和快速运行的任何其他内容。它们还占用一些字节(目前每个文件 20 个字节)来保存内容哈希 ID,这与 Git 的内部存储格式有关。这意味着列出几千个文件的索引需要几千 KiB 来存储。例如,在 Git 的 Git 存储库中,我们发现:

$ git ls-files | wc -l

表示索引中有 3865 个文件,ls -l on .git/index 的索引大小为 366964(字节)。该索引还存储标头和尾标以及其他项目,因此这里不能保证直接相关,但它通常平均起来很像这样。

2从技术上讲,这个git add 会立即压缩和去重文件的内容,然后更新索引中的blob 哈希ID。如果内容已经在其他地方的存储库中,则对新的准备提交文件进行重复数据删除。如果内容是新的,它现在是第一次在存储库中,可以提交。

请注意,如果您在将文件从工作树中删除之后git add,Git 将在此时删除索引副本。 git add 命令实际上意味着使索引副本与工作树副本匹配,如果工作树副本消失,这意味着 Git 应该删除索引副本以进行匹配。

当然,如果根本没有索引副本,Git 将创建一个新的索引条目,像往常一样压缩和删除工作树内容。索引现在保存文件名、blob 哈希 ID 和缓存数据,并且索引副本现在与工作树副本匹配。

【讨论】:

  • 非常感谢@torek 的详尽回答,现在它更有意义了。那么您是否建议将 png(和其他二进制文件)存储在 git 之外,比如存储在 S3 存储桶中?
  • 如果它们变化很大,将 large 二进制对象存储在 Git 之外通常是明智的。 (PNG 是预压缩的,并且在 Git 中不能很好地压缩,这打败了压缩技巧。)如果它们是静态的(一直重复使用)或很小,存储它们不会伤害 Git 本身,但是也许您的情况表明这种外部存储。
猜你喜欢
  • 1970-01-01
  • 2014-07-20
  • 2018-02-18
  • 2022-01-26
  • 2018-09-08
  • 2022-11-12
  • 1970-01-01
  • 2011-08-26
  • 2017-12-30
相关资源
最近更新 更多