“git push”和“git exile push”有什么区别?

3
我有一个git仓库,并被指示执行以下操作序列:
1.将一组给定的文件从文件夹复制到上述git存储库中(“源文件夹”不是存储库的一部分)。 2.执行git add . 3.执行git exile push folder_name/ 4.执行git commit -m 'Commit message' 现在我想了解我实际要做什么。更具体地说,前两个步骤对我来说很清楚(我更改了存储库中的内容,然后将这些更改添加到“暂存区”,以便进行 git commit )。但是,最后两个步骤( 3 和< strong>4 )令人困惑,我对它们有以下疑问:
1.通常我们首先提交,然后推送。为什么我们在此处执行不同的操作(推送,然后提交)? 2.我们使用git exile push而不是git push。这两者之间有什么区别?它推到哪里?它推什么?
我听说这与大型文件有关。我们不直接使用它们,而是使用它们的“引用”(或指向它们的“链接”)。但这意味着什么? 添加 我假设git exile push会将大文件的内容复制到适合容纳较大文件的位置,然后用指向其副本的链接替换原始文件的内容。因此,换句话说,文件的内容将被其内容的副本的链接所取代。之后, git exile push 执行 git add 。因此,它更改了文件,将其添加到暂存区,我需要做的就是 git commit
我的解释正确和完整吗?

1
https://github.com/patstam/git-exile#how-it-works - ElpieKay
请参考此链接此链接 - amanb
@ElpieKay,链接的文档假定读者具有相当高的水平并且了解所有术语。我希望能够用简单的术语表达基本理解(与我在ADDED后面提供的解释同样简单)。 - Roman
1个回答

2
git exile不是Git的一部分。从ElpieKay的链接可以清楚地看出,它在某些方面类似于Git-LFS(也不是Git的一部分),而你在“添加”部分中描述的内容正是Git-LFS所做的事情:
假设git exile push会将大文件复制到适合存储大文件的位置,然后用其副本的链接替换原始文件的内容。换句话说,文件的内容将被其内容的副本的链接替换。
这在目标上是正确的,但在底层机制上则不然。
对于Git-LFS,目标基于文件大小,并且Git-LFS具有使其工作的许多代码。对于Git-Exile(我没有使用过,也没有仔细研究——我只是快速扫了一眼代码),目标基于“二进制性”,而不是大小,并且您必须通过名称模式选择要声明为二进制的文件。也就是说,您可能会说*.jpg和/或*.exe应视为二进制文件。
现在让我们详细了解一下。
您的工作树、提交和分支名称
您已经知道Git的提交存储文件(“快照”)。如果您还不知道这一点,请阅读一些描述它的工作原理的内容。为了保持相对较小,Git将文件存储在一种特殊的、仅供Git处理的形式中。您需要以非Git方式拥有这些文件,以便可以使用它们。因此,Git将文件从快照中复制到工作树中,该区域是您进行工作的地方。
但现在请考虑这个相当严峻的事实:提交完全是只读的。您永远无法更改任何现有提交的内容。您可以随时读取它们。您可以创建一个新的(并不同的)提交,而不影响现有的提交。您永远不能更改提交。
每个提交都有一个大而丑陋的、看似随机的哈希 ID,例如 Git 存储库 Git 本身中的提交 e3a80781f5932f5fea12a49eb06f3ade4ed8945c。这些 ID 基本上无法被人类使用,因此我们选择一些重要的提交,比如分支上最近的提交,并给它一个名称,如 master。名称对应的提交哈希 ID 会随着时间而改变:每当我们向存储库添加一个新提交时,Git 就会为其分配一个新的唯一哈希 ID。如果我们将这个新提交添加到了 master 分支中,Git 将把新的 ID 存储到名称 master 中,以便名称始终标识最新的提交!
每个提交一旦完成,就永远固定下来了。它还存储了前一个提交的哈希 ID(并且由于没有任何东西可以更改提交,因此永远存储)。因此,使用我们通过名称 master 找到的最新提交,我们可以向后查找以找到更早的提交:
      <-C   <--master

我们只需跟随从提交C出来的箭头(哈希ID)即可找到更早的提交:
  <-B <-C   <--master

现在,B也有一个箭头(实际上是一个父哈希ID),因此我们可以找到早期的提交:
A <-B <-C   <--master

在我们这个简单的仓库中,只有三个提交记录:A是第一个提交,所以它没有父级箭头/哈希-ID,我们知道可以停止追溯父链接。
工作树很简单,但它不是提交,提交也不是工作树。Git可以将提交 提取到 工作树中,并且 - 最终,有点 - 将工作树保存到新提交中,但要做到这一点,Git 坚持通过其 索引 进行操作。其他版本控制系统没有索引,或者如果它们确实有类似于索引的东西,它们会完全隐藏它,您不必知道它。Git则相反。

索引

这意味着无论何时使用 Git,都必须了解并使用 Git 所谓的 索引,或者 - 根据叫什么人和他们想强调什么 - 暂存区缓存。这些是一个单一的东西的三个名称。那个东西非常重要,以至于最终得到了这三个名字!好吧,或者第一个名字“索引”太糟糕了... :-) 但是说真的,索引不断在你面前出现,让你明白它站在你和你的提交之间。
简单地说,Git 的索引包含将进入 下一个 提交中的文件。这意味着索引开始持有所有在 当前提交 中的文件。
当您运行 git commit 时,Git 将打包以任何时候在索引中出现的内容,并从这些文件中制作一个新的提交。索引以后可能会有不同的东西,但是 在您运行 git commit,Git 接受其中的内容,将其打包并制作一个新的提交。
新提交指向当前提交。因此,如果我们有上面简单的三个提交记录:
A--B--C   <-- master (HEAD)

当我们的HEAD附加到分支master时,我们创建一个新的提交D,因此当前提交是提交C,新的提交将指向C,Git将使名称master指向D

A--B--C--D   <-- master (HEAD)

这就是分支的生长过程。

那么,如何将文件添加到索引中呢?

由于索引(也称为暂存区)非常重要,您需要知道如何将文件添加到索引中。当然,它会通过git checkout从当前提交中开始,但接下来呢?

大部分情况下使用git add命令完成“接下来”的工作。

git add README.txt

告诉Git将你的工作树中README.txt的内容打包成特殊的Git-only格式,并将其放入索引中,以README.txt命名。
这意味着在Git中,文件流程如下:
提交  —>  索引  <—>  工作树
使用git checkout,您可以将文件从某个提交(通常是当前提交)复制到索引中,在那里它们保留其特殊的Git-only格式但现在变得可写;然后从索引到工作树,其中它们变为正常格式。使用git add,您可以将文件从工作树复制到索引中,覆盖之前存在的副本并将文件转换回特殊的Git-only格式。
最终,您运行git commit将索引打包为提交。提交保存索引中的任何内容,已经转换为Git-only格式,因此这部分非常容易。Git只需确保该文件永远作为提交的一部分保留下来,即未来的git add不会覆盖或丢弃已提交的版本。用于Git-only格式的底层机制(哈希与“垃圾收集”)使这变得微不足道。
Smudge和clean过滤器
以上所有内容都隐藏着一个有趣的点:Git必须将文件从索引复制到工作树中,将Git-only格式扩展为正常格式。而且,Git必须将文件从工作树复制到索引中,将它们压缩成Git-only格式。如果我们在复制过程中做了一些狡猾的事情怎么办?
Git在此处提供了自己的内部过滤器,例如使用CR-LF行尾而不是LF-only行尾,或者扩展$Id$以包含哈希ID。这些过滤器意味着索引中的内容与工作树中的内容实际上不再匹配。文件的索引版本并不仅仅是工作树文件的压缩版本。它是一个修改过的版本,或者是一个替换版本。
这就是Git-LFS和Git-Exile的工作原理。它们添加在“从索引提取到工作树”步骤中运行的过滤器,并在“从工作树压缩到索引”步骤中运行。这些过滤器不仅仅交换CRLF和LF-only结束符或扩展或压缩掉$Id$字符串,它们实际上交换整个文件内容。
在执行git add时,大型或二进制文件根本不会进入索引。LFS或Exile过滤器将实际的文件保存在其他地方,并在Git中放置一个链接。Git称之为清理过滤器:它将令人困惑的工作树文件清理成漂亮干净的索引版本。
在执行git checkout时,大型或二进制过滤器不在索引中,但是LFS或Exile过滤器获取链接并从其他地方找到实际的文件,并将该文件放入工作树中供您使用。Git称之为弄脏过滤器:它从索引中取出漂亮干净的提交版本,并使其变得令人讨厌的工作树文件。
调用smudge和clean过滤器的机制是将文件名glob模式放入.gitattributes文件中,并使用filter=指令。这在gitattributes文档下的filter部分中有描述。Git-LFS通过过滤每个文件来工作,检查文件大小,使用Git的长时间运行过滤器进程技巧来减少开销。Git-Exile通过匹配感兴趣的文件来工作,使用了更简单的每个文件过滤器方法。
移动的文件应该何时(以及在哪里)保存?
使用Git-LFS,不在索引中的大文件会立即发送到大型文件服务器上。使用Git-Exile,大文件会被塞入一个次要存储库中(如果我正确地阅读了代码和描述)。 git exile push步骤将移动的文件推送到相关联的次要存储库中。您不一定需要首先这样做,但是这是一个好主意,以防某人在您有机会这样做之前抓取您的链接对象。 (甚至可能是你自己。工作树文件仍然存在,但是如果在只有链接的索引条目上调用弄脏过滤器,则会查找移动的文件。)
现在我们可以看到这在想法上是正确的,但在执行上是错误的:
我假设git exile push获取大文件,将它们的内容复制到适合容纳较大文件的位置,然后将原始文件的内容替换为其副本的链接。因此,换句话说,文件的内容将由指向其内容副本的链接替换。
替换实际上是在git add时发生的! 另一方向上仅链接版本的替换发生在git checkout期间。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接