用例-使用Git LFS管理正确存储上的大文件
文摘:
Tim Pettersen, Atlassian高级开发人员/开发倡导者,2016年5月:我是一个敬业、注重细节的软件开发人员,具有出色的沟通技巧,对API设计和产品集成充满热情。我有7年的java工作经验和广泛的相关技术,为世界上首屈一指的软件团队工具供应商之一工作:Atlassian software。
讨论转录:
好了,伙计们。我们可能会有相当多的内容,所以我们会看看我们是否能在结束前全部看完。
所以,你可能想知道为什么我把埃菲尔铁塔的大图作为背景。像许多伟大的故事一样,今天我要告诉你们的故事始于巴黎。那是2015年4月8日,一年多一点以前,一群工程师,就像你们一样,坐在Git贡献者峰会上。这是一年一度的Git合并会议前一天举行的大型峰会。所有的——好吧,不是全部——但是大多数的Git贡献者聚在一个房间里,讨论他们明年要做些什么来推动Git这个大家最喜欢的分布式版本控制系统向前发展。
在这次会议上,发生了一些非常有趣的事情。有两家公司之间的对话,这两家公司通常是相当坚定的竞争对手。他们是Bitbucket团队的Atlassian的Nicola Paolucci和John Garcia,以及GitHub的Rick Olson。
他们的谈话是这样的。Nick说:嘿,Rick, Atlassian的我们一直在研究一项非常有趣的新技术,来解决Git存储大型二进制文件的问题。所以我们为Git构建了这个新的扩展,用Go语言编写,因为我们想让它成为一个跨平台的,我们计划在明天的会议上的Git合并会议上宣布它。GitHub的Rick说,这很有趣,因为在GitHub,我们也一直在研究解决Git的大二进制文件问题。你知道吗,我们在Go中构建了一个新工具,它扩展了Git,以便更好地跟踪这些二进制文件。我们将在Git Merge会议上宣布它。
妮可拉说,什么。顺便说一下,这是詹姆斯·瓦特的照片。瑞克就像手提袋一样。这不是很疯狂吗?你的工具叫什么?这才是真正奇怪的地方。Atlassian的Nick说,我们称之为Git LOB。代表长对象就像你在数据库中看到的那样因为我们需要跟踪这些大的二进制数据块。Rick说,啊,真奇怪,我们把我们的Git叫做LFS,另一个三个字母的首字母缩略词,代表大文件存储。现在,在两家公司之间进行了一些反复之后,Atlassian决定开源并存档Git LOB,并开始将我们构建的一些特性移植到Git LFS项目中。
我们这么做有几个原因。首先,我们不想分裂社区。我们希望构建一个开源工具,为Git的每个用户解决跟踪大型二进制文件的问题。第二个原因是它们都是用Go编写的,都使用相同的扩展点和钩子扩展Git,而且设计都相当相似。所以移植这些功能很容易。
这就是为什么我来到Atlassian,我之前在Bitbucket服务器项目和JIRA工作过,来谈谈Atlassian和GitHub之间的这个联合项目。如何使用Git LFS跟踪正确存储上的大文件。
这真的很令人兴奋。在过去,我做了很多关于Git的宣传,讨论了分支工作流程和重基,以及如何不强迫和破坏团队的其他成员。有时在一个演示之后,我遇到了一个非常尴尬的对话,我将与某人交谈,无论出于何种原因,就是不会使用Git。现在有一些工程师在使用原生形式的Git时遇到了困难,因为它——跟踪大型二进制内容的问题。
如果你是一名游戏开发者,并且你想要追踪游戏纹理资产或音频文件或全动态视频,那么在存储库中就很难做到这一点。同样,如果你是一名研究人员,你想追踪大型数据集。也许,您知道,您正在编写的脚本和其他编程建模部分旁边有gb或tb的数据,这在您的Git存储库中很方便,但您不能这样做,因为您在使用大型二进制文件时会遇到性能问题。
所以今天我将首先讨论一下为什么Git很难跟踪二进制内容。然后我将讨论一下Git LFS是如何解决这个问题的,我们将深入了解Git LFS是如何扩展Git的。因为看到Git本身是如何以这种可扩展的方式构建的是一件很有趣的事情。然后,如果您已经在跟踪现有存储库中的二进制内容,我将提供一些技巧,帮助您将现有存储库转换为使用Git LFS。然后,我们将了解如何使用现有的Git托管提供商和Artifactory来有效地将大型二进制文件存储在一个地方。最后,我将为您提供一些在团队上下文中使用Git LFS的技巧,以确保您在处理团队的其他大型二进制文件时不会弄脏它们。
因此,首先要理解为什么Git在处理大型二进制文件时如此困难,您需要了解一些Git数据模型。现在,当您考虑随着时间推移对代码库的更改时,因为它与版本控制有关,您可能会考虑一组修订或提交。在Git中,这些修订,实际上它们在Git中被称为提交,这些提交不会在空间中浮动。他们通过祖先相互联系。具体来说,在合并提交的情况下,每个提交都有对其直接父节点或父节点的引用。现在,如果我们放入分支或标签,在Git术语中更常见的是refs,您将开始了解Git数据模型的样子。现在这个数据结构被称为DAG,或者有向无环图。基本上,每个节点代表一个提交,或者我们马上就会看到,它代表Git数据存储中的另一个对象。它是定向的,因为每个对象都引用了在它之前某个时间点创建的另一个对象。DAG中的A代表无循环,因为这些对象中的每一个都是不可变的。 When you create a new object, it refers to an object that already exists. So you can never create a cycle inside this data structure.
现在,为了理解为什么Git很难跟踪二进制内容,我们需要更深入地研究一下。看看这些提交对象的结构是什么。所以Git附带了一个叫cat-file的命令,你可以用它来检查Git仓库里的任何对象。如果你传递一个破折号p标志,它会以一种人类可读的格式打印出来。
提交其实很简单。它们只是几个字节。首先,您有对提交的直接父节点或父节点的引用。当你第一次从集中式版本控制系统转移到Git时,你看到的十六进制SHA-1地址看起来有点可怕,实际上是Git对象内容的SHA-1哈希。因此,您可能听说过Git被引用到一个内容可寻址的文件系统,这是因为每个Git对象都由这些SHA-1散列之一引用。关于Git如何存储这些数据,这里有一些非常重要的属性。最有价值的属性之一是它可以很容易地检测重复对象。你马上就会明白为什么这很重要。
这个提交对象的下一个元素是树。这是另一个SHA-1哈希值。这是树的地址和内容。这个树类似于这个Git存储库所跟踪的根目录。我们马上就会看到,这个树实际上包含了对Git仓库中被跟踪的每个对象或文件的引用。然后我们有一点提交元数据。提交者,创建提交的人,作者,最初编写代码的人,通常是同一个人,这取决于你的工作流程,然后你也有一个提交消息。但对于大多数提交,这基本上是你将看到的全部。
现在,如果我们再次打开cat文件命令,我们可以指向那个树对象并查看它的结构。您将看到它看起来很像文件系统上的目录。我们有文件模式,我们有嵌套树,基本上是Git存储库根级的子目录,然后我们还有blob。这些blob还是SHA-1散列,指向磁盘上这个文件的实际内容。最后是路径。repo中所有文件和目录的名称都存储在这些树对象中。
如果我们继续递归到Git树中,我们可以看到存储库的全部内容。如果我们再加入一个refs,或者分支,或者标签,我们这里就非常接近完整的Git数据模型了。所以当你看它的时候,它实际上是非常简单的。说实话,理解这个是我了解Git工作原理的最好方法之一。
Scott Chacon写了一本非常好的书叫做Pro Git。它很早就介绍了这个概念,然后开始讨论你在工作流中使用的所有不同的Git命令,作为Git数据模型的转换。如果你遇到了困难,或者你正在学习,开始学习Git,阅读那本书,这是理解底层原理的最好方法之一。
现在,Git在处理大型二进制内容时遇到困难的原因是,每次创建一个提交时,我们实际上都要创建一个新的这些树。所以每次我们在存储库中修改一个文件,添加并提交它时,我们都会创建一个新的blob,这意味着blob的所有树,无论是直接父树还是祖父树,都必须重写。幸运的是,由于Git是内容可寻址的,因此Git很容易不创建未更改对象的副本。但是如果对象发生变化,Git必须创建一个全新的blob。Git最终会对这些blob进行增量编码。如果你有,但取决于二进制格式,它可能压缩得很好,也可能不压缩得很好。
让我们举一个非常简单的例子,我们有一个存储库,它实际上是一个目录,里面有一个文件,比如一个高分辨率的大象文件,以某种原始文件格式存储。现在因为它是原始的,每个像素都将被编码为一组字节。所以如果我们改变大象的颜色。抱歉,这里的颜色区分不是很好,但大象应该是粉红色的。然后,当我们添加并提交到仓库时,它将创建一个全新的blob,并且它将使仓库的大小增加一倍。当我们对这个图像做更多的改变时,等等。
因此,当您有大型二进制文件时,存储库就会不断膨胀。现在使用传统的集中式版本控制系统,这并不是一个大问题,因为你的回购的整个历史记录都存储在一个中央服务器上,每个开发人员通常一次只检索一个提交并使用它,所以你只有最新版本的快照。有妈妈纹身的大象。但是Git是一个分布式版本控制系统。因此,每次你需要进行推、拉或克隆时,你实际上是在复制存储库的整个历史记录。所以这意味着我要把我修改过的文件的每个版本都推送到服务器上,而我团队的其他成员必须把文件的每个版本都拉下来。
同样,如果我有剧本或持续集成构建,它们有时可以根据它们的确切用例进行浅层克隆。但通常情况下,你最终不得不复制这段丰富的历史,这段历史非常沉重。这不仅扩大了回购的规模,还减缓了那些推动和拉升——推动和拉升。这意味着Git服务器上的负载会不断增长,直到一切都停止。
现在Git LFS是这个问题的解决方案。现在,正如我所提到的,它是Git的扩展。这并不是第一个尝试解决大文件问题的Git扩展。有Git Annex, Git Media, Git BigFiles这样的工具。所有这些- Git Fat是另一个,所有这些都试图解决这个问题。但是Git LFS采用了一种稍微新一点的方法,并试图使它与现有的Git工作流尽可能透明。因此,您马上就会看到,一旦安装了Git LFS,就可以像往常一样使用现有的存储库了。
现在Git确实有一个相当陡峭的学习曲线。因此,我认为Git LFS比其前身更成功的原因之一是它没有增加学习曲线。它实际上就像使用原始Git一样简单。
所以在高层次上,基本上Git LFS所做的不是把所有这些大的二进制文件存储在Git对象目录中,作为你的repo的一部分,而是用轻量级的指针文件代替它们,这些指针文件包含了对这些大对象的引用。它们实际上是我们所看到的DAG的一部分。这些大型对象完全脱离DAG存储在完全独立的存储中。
所以当你运行git push时,这些大文件会被转移到一个单独的存储中,而你的git DAG会像往常一样转移到你的git存储库中。然后,这就是奇迹发生的地方,当开发人员进行克隆,或获取,或拉取时,DAG被传输回开发人员的计算机。然后,只有开发人员想要处理的那些大文件的版本,通常是他们刚刚签出的分支的尖端,才能从大文件存储中检索。因此,您不会获得历史记录中这些大文件的每个版本。
现在让我们稍微看一下其中一个指针文件的结构。它实际上只有几个字节。因此,如果您再次使用cat文件命令,您可以看到它有三个字段。我们有一个版本架构,它是版本LFS指针格式,我们有一个对象ID,它是对象内容的SHA-256哈希,然后我们有这个对象的大小,以字节为单位。因此,在我们的Git仓库中,我们有几个字节的文件,而不是一个接近几兆字节或几千兆字节的文件,这会减慢所有的速度。
现在您可能注意到这是SHA-256哈希而不是SHA-1哈希。这有几个原因。首先,Git刚刚在4月庆祝了它的11岁生日。而Git,最初设计的时候,SHA-1没有任何已知的理论上的弱点。如今,SHA-1可能比最初的设计约束稍弱一些。所以SHA-256是一个更现代的标准,我们认为它更安全。
SHA-256还有几个有趣的属性。其中一个重要的优点是S3内置了对大文件的SHA-256验证的支持。因此,如果您要使用S3作为Git LFS后端,那么它可以自动验证对象的内容。所以从这个角度来看,这也是一种实用的选择。
所以安装Git LFS非常简单。它是用Go语言编写的,所以每个平台上都有Git可用的二进制文件。它就像使用您最喜欢的平台管理器安装它一样简单。我喜欢OSX上的Homebrew。一旦你在本地安装了这个包,你可以简单地运行git lfs install,它就会为你安装好。
它在底层所做的是将这个名为过滤器配置的新东西添加到全局Git配置中。它所做的是将一个新的清洁和涂抹过滤器映射到正在使用LFS跟踪的文件。现在,clean和smudge过滤器是一个原生的Git概念,它允许你拦截Git add和Git checkout命令。我们马上就会看到它是如何工作的。
一旦设置好Git LFS,就可以运行Git LFS track命令,告诉LFS要在LFS中跟踪哪些文件模式或文件名,而不是直接添加到Git对象目录中。现在它所做的是在git属性文件中添加一个新条目。这也是另一个原生Git概念,您可以使用它来扩展Git。它将这种模式绑定到LFS涂抹和清洁过滤器上。
那么这些过滤器是如何工作的。让我们先来看看清洁过滤器。当开发人员运行git add命令并将文件名传递给它时,而不是直接将其添加到git索引中,并在git objects目录中创建一个对象,而是将其交给git lfs clean命令。它获取该对象内容的SHA-256哈希并将其添加到位于git / lfs / objects下的特殊对象缓存中。所以它看起来非常类似于git objects目录,但是它的命名空间位于lfs下面。因此,Git LFS再次尝试遵循现有的Git模式,以使其尽可能透明。
一旦它将内容存储在那里,在SHA-256哈希下,作为文件名所以它的内容是可寻址的,它会添加一个新的指针文件,其中包含对象大小的SHA-256哈希到Git对象目录中。而不是增加,你知道,兆字节或千兆字节,它只是几个字节被添加到你的回购的大小。
然后,当开发人员进行获取、克隆或拉取操作,并且实际上想要处理这些大文件时,Git涂抹过滤器就会发挥作用。因此,当开发人员运行checkout时,该文件(指针文件)将被传递给Git涂抹过滤器。它会在本地Git LFS对象缓存中查找,并尝试找到与SHA-256哈希值匹配的文件。如果它在那里找不到它,它实际上会读取到你的后端LFS存储,该存储将托管在Git版本控制提供商(如Bitbucket)或潜在的独立存储(如Artifactory)上。然后,一旦它找到了对象的内容,它就会把它写到本地——在原始文件名称下的本地工作副本中。
虽然这很有趣,但我在浪费你们的时间因为你们不需要了解指针文件格式。作为一名开发人员,当你运行git add时,你运行的是你刚刚完成编辑或创建的原始文件,当你运行git checkout时,当这个命令退出时,你的本地磁盘上就会有那个大文件的新版本。你永远不会看到这些指针文件。它们是Git LFS的实现细节。因此,当您使用Git LFS作为工作流程的一部分时,一切都是透明的。
以上就是使用LFS创建和检索大型对象的方法,现在我想谈谈如何将这些大型对象从服务器传输到服务器。因此,Git LFS拦截推送的方式是使用Git钩子将这些对象上传到服务器。这里有人以前用过Git钩子吗?有几个人。好酷。对于那些没有的人,看看你在本地创建的Git目录或Git存储库。在。git dir (git存储与repo相关的所有数据的地方)中,你会看到一个hooks目录,在那里,会有一大堆示例脚本,展示了当你拦截git调用时可以做的很酷的事情。
为了方便起见,您可以执行预填充提交消息之类的操作。因此,作为一名开发人员,我使用的其中一个方法是,我们用陪审员问题来命名我们所有的Git分支。所以我得到了这个预提交消息,预提交消息钩子,它从分支名称中提取issue键然后插入到提交消息的开头这样我就不用每次都手动输入了。
你也可以创建像预提交钩子这样的东西,它可以在你创建提交之前运行单元测试。这是一个非常强大的想法,因为这意味着你默认创建的每个提交都已经通过了测试。这有点像前ci阶段。现在,Git LFS可预见地使用的预推送钩子允许您拦截Git的推送操作。所以当你运行git push时,你在本地创建了一些新的大型对象,需要传输到服务器上,你会看到这样的输出,嘿,我正在将一些文件传输到你的git LFS仓库,这是它被上传时的状态。
这里真正好的是,您不会得到任何身份验证提示。无论您使用的是HTTP还是SSH, Git LFS实际上都依赖于现有的Git LFS凭证。Git LFS OS服务器将处理这两种用例。这样你就不用再去输入额外的命令或者把它加到你的钥匙链上了。它只是与您现有的身份验证模型透明地工作。实际上,在最后我有一些幻灯片是关于这个验证过程是如何工作的,所以如果我有时间,我会跳到那一步,因为这是一个非常非常酷的使用[…],实际上。
类似地,当您运行git pull时,您将看到smudge filter读取到后台LFS存储时的一些输出,说明它正在下载这些大文件。正如我之前提到的,它也可以透明地与SSH一起工作。与Git Media等早期竞争对手相比,这是Git LFS的杀手级特性之一。
这就是Git LFS的工作原理,我想谈谈如何将现有的存储库转换为使用Git LFS。我之前在讲Git LFS跟踪命令的时候可能误导了你们。因为如果你在已经存在的存储库中使用它,它会把这些大文件转换成指针,这很好。但不幸的是,它不能为已经膨胀的存储库做任何事情,因为在您的回购历史记录中仍然有这些大团。
现在,如果你是相当专业的,好吧,不是专业的,但是如果你有很多Git的经验,特别是在重写历史记录方面,这时你可能会用到Git过滤器分支命令。以前有人用过过滤器分支吗?是的。有点,有点恐怖和痛苦,不是吗。我做了这张幻灯片,大概花了十分钟才忘记它到底在做什么。它在这里做的实际上是返回并从你的存储库历史中删除所有大的blobs。这不是个好主意。这将大大减少你的回购规模,但不幸的是,这意味着那些实际上被从你的历史中抹去了。所以如果你确实需要回去查找其中一个大团,它就会消失。这对于审计目的或需要回滚时不是很好。
现在,Git LFS的核心贡献者之一Andy Neff提出了这个真正天才的Git过滤器分支命令,它实际上会返回并将所有这些blob重写为Git LFS指针。这确实令人印象深刻,但事实证明,现在有一种更简单的方法来做到这一点。
有一个很棒的工具叫做BFG Repo-Cleaner。它是由《卫报》的一位名叫罗伯托·泰利的开发者开发的。罗伯托在最初制作这个工具的时候,遇到了一个问题。一个开发人员不小心提交了一些敏感的东西到他的仓库中的属性文件的早期版本。这是一个问题,因为要删除它,他必须回去,基本上,你知道,运行过滤器分支,从历史中剔除它。现在过滤器分支非常棒,但它有点像重写存储库历史的瑞士军刀。但它使用起来也很吓人,而且速度极慢。现在,关于Git的一件事是,在一天结束时,它是bash脚本和用c编写的其他底层命令的集合,但是它没有真正的系统进程。所以过滤器分支通常会遍历整个DAG,一遍又一遍地重新处理相同的对象和树。
现在,BFG的Repo-Cleaner是一个专门用来清除历史记录的工具,它建立在JGit之上,JGit是Git在纯Java中的完全重新实现。它确实有一个系统过程。所以当它遍历树和对象的时候,它会返回并记住处理过的每一个树和对象因为它是内容可寻址的,所以它知道它不需要再去重新处理那些。所以它实际上比过滤器分支快10到720倍。
如果你去BFG Repo-Cleaner的主页,他们有这些过程的电子表格——这些开源项目,他们在上面运行它来重写历史,他们得到的数据非常令人印象深刻,表明它有多快。
现在,它最初的构建是为了杀死历史记录,所以它实际上可以删除文件,比如从您的历史记录或整个文件夹甚至文件中的字符串中删除文件。如果你提交了凭证,密码,AWS密钥之类的东西到属性文件中,你可以回去用散列标记之类的东西替换它。但是从版本1点12点5开始,Roberto内置了对Git LFS的支持。因此,你可以简单地安装BFG,而不是这个天才的斜线疯狂的过滤器分支命令,它是用Java编写的,非常容易移植,可以在Git的任何平台上工作,然后运行方便的convert to Git lfs命令,并将你想要用lfs跟踪的文件的模式或名称传递给它。
现在有一个稍微神秘的标志,你必须通过称为无斑点保护。这意味着它将重写分支的提示提交以及整个历史记录。默认情况下,BFG假定您的存储库现在处于良好状态,因此出于安全原因,它不会触及提示提交,但是当您使用LFS重写历史记录时,您通常也希望重写提示提交。这里的提示是指您当前签出的分支上的最新提交。
这就是你如何用BFG改写你的历史。但这类问题,特别是对于大型存储库或具有很长历史的存储库,就是我应该用LFS跟踪哪些文件。在Git Merge上,今年早些时候在纽约,我听了一个叫Charles Bailey的人的演讲他在Bloomberg工作他刚刚开源了一套叫做Repofactor的工具。Repofactor的作用是帮助您识别存储库中的大型blob链。当我说链的时候,是一团的链。基本上,它会查看为特定文件创建的第一个blob,然后它会找到存储库中存储的所有其他blob,这些blob也是为该文件的新版本创建的。然后计算出该斑点随时间的平均大小。这真的很好,因为大小是文件压缩效果的函数。所以如果它不能很好地压缩,使用zlib压缩,这是Git在底层使用的,那么它就成为LFS的一个很好的候选者,因为当你转换到LFS时,你将节省大量的文件空间或磁盘空间。
现在它是一组命令行工具,而不仅仅是你插入Git存储库的应用程序。经过一番折腾,这是我发现的最有效的使用方法。首先,你想要使用generate bigger than命令,然后传递给它一个整数,表示这是我认为大文件的字节数的阈值。然后它会输出一个对象的SHA-1哈希值。每一团的大小都跟随着这一团在圆盘上的大小然后它就会给出这一团的平均大小这一团的链不好意思,是这一团的链。一旦获得了这些信息,就可以将其管道到add file info命令,该命令使用bash文件命令嗅探出每个blob的内容类型。然后你就能看到更多的信息了。现在我们知道这些blobs表示合理分辨率的PNG文件。然后你可以通过管道进行排序,并开始按平均团大小排序。所以那些更适合LFS的候选点会浮到顶部。 And then if you write that out to a file, you can use the report on large objects command to generate the actual file names of each ones — of each of these blobs. And from there we can use that as input into our BFG invocation to start tracking some of these large files using LFS.
这就是将现有存储库转换为使用Git LFS的方法。但现在你需要考虑将这些东西存储在服务器上的什么地方。现在,如果你正在使用Bitbucket服务器,启用Git LFS真的很容易。在存储库设置中选中允许LFS复选框并保存它。Bitbucket还可以透明地读取到底层的Git LFS存储库,所以所有很酷的图像区分和二进制文件预览都会像魔法一样工作——好吧,不是魔法——它会在你的存储库中自动工作。
但是,如果您正在使用JFrog Artifactory(很有可能您正在参加这次会议),那么您可能希望开始使用Artifactory来管理二进制文件,因为它具有处理二进制文件的所有令人敬畏的特性。实际上,您可以建立一个新的本地存储库来跟踪您的Git LFS对象,然后您可以浏览您的LFS库,并使用树形浏览器查看Artifactory中的所有这些大blobs。你也可以用AQL来查询那些大的对象,这很简洁。你可以做其他的事情,比如固定手表之类的。因此,如果您想将所有二进制文件存储在Artifactory中,您完全可以这样做。
现在,它的工作方式是,您的开发人员,或者首先为您的存储库初始化LFS的创建人员,将需要配置该repo,以便为您的大文件指向Artifactory。实现这一点的方法是在repo的根目录下创建一个lfs配置文件。它可以像存储库中的任何其他文件一样起作用。你可以检查它,提交它,然后把它推送到服务器它会开始为所有其他开发者工作。
现在你不需要记住它的格式,因为很棒的Artifactory设置按钮也适用于LFS。它实际上会根据Artifactory实例的位置为您生成该配置。它所做的是覆盖LFS API的位置。因此,它不是指向桶服务器,而是指向Artifactory。
现在,使用本地Artifactory存储库有一个主要缺点。那就是Bitbucket不会知道这些LFS文件被跟踪的位置。这意味着UI中不再有漂亮的图像差异,你会看到这些小指针文件的差异。这并不是一种最佳体验。因此,从Artifactory 4.07开始,他们发布了对远程LFS存储库的支持。这意味着你可以设置Artifactory来作为这些LFS文件的代理或缓存,这些LFS文件在Bitbucket服务器中被跟踪。这意味着你的Bitbucket服务器实例仍然在为你跟踪这些大型对象,但是Artifactory将会意识到它们,这样你就可以做一些事情,比如设置手表,并使用AQL查询它们。这真的很强大。
你还可以做的另一件事是,在4点7中,他们还发布了对虚拟仓库的支持。所以你可以创建一个虚拟的Artifactory仓库,在Bitbucket和Artifactory上聚合一组这些LFS存储的仓库。是的,就像我提到的,你也可以设置虚拟仓库如果你想要一个,虚拟的LFS仓库的视图。我认为你也可以直接推送到虚拟仓库,然后它会有一个默认的LFS存储,它会推送到。
这就是如何将Artifactory与Bitbucket服务器或其他Git托管服务器一起使用。现在我想谈谈如何在团队环境中使用Git LFS。到目前为止,我主要讲的是单个开发人员如何与repo交互。首先要记住的是你必须非常小心处理合并冲突。现在Git非常、非常、非常擅长处理与文本文件的合并,但不幸的是,它对你在存储库中跟踪的二进制文件一无所知,也没有很好的方法来执行语义合并。没有什么比在一个大的二进制文件上工作一整天,却发现团队中的其他人也在另一个分支上修改了这个文件更令人沮丧的了。因为这意味着,比如一个大的视频文件,你可能花了一整天渲染这个东西,然后发现别人也在做同样的事情你根本没有办法解决这些冲突。你必须回去把你所有的工作重新应用到他们的工作上,或者让他们做同样的事情。
目前,Git LFS还没有锁的概念。实际上,有一个Google代码之夏的申请者已经成功通过了审核,并且正在为Git LFS开发一个锁规范。所以祈祷在接下来的几个月里会有一些结果。但与此同时,你能做的最好的事情就是轻拍你团队的其他成员或者,任何可能在修改同一个文件的人,传递互斥锁告诉他们,他们应该推迟修改那个文件,直到你完成。
现在我主要谈论的是Git LFS是如何出色的,因为它只检索你的内容的最新版本,这可能是你想要使用的。但在某些情况下,您可能实际上想要获取的不仅仅是被您签出的提交所引用的大型二进制文件。
这里有一个叫git lfs fetch的命令默认情况下,它会从你的tip commit中获取这些指针文件。但你可以传递破折号,破折号,最近标志,这意味着它会关闭并检索与最近更新的分支相关的内容。它是如何定义最近的是任何分支上有一个提交超过7天。这很方便。如果你喜欢这种行为,你可以通过设置fetchrecent always标志为true来设置它为默认值。这很方便,特别是当你要跳飞机之类的需要处理多个分支时你可以运行git lfs fetch dash dash recent它会帮你把这些都拉下来。
现在您也可以调整这种行为。你可以设置一些属性标志。第一个是最近的反弹。这基本上改变了滑动窗口的长度根据它对最近分支的考虑。您还可以设置fetch最近提交日期属性。这个默认为零,原因是这意味着它实际上会为提交检索大量内容,而不是分支提示。所以如果我有一个分支,在最后一天有10个提交,它实际上会启动并为每个提交检索所有的大文件。这是一个非常不寻常的情况。你知道,我能想到的唯一合理的用例是,如果你要跳上飞机或失去互联网连接,你需要做一些回购手术。就像,你知道,也许做一个二分搜索,回顾你的历史,或者你打算重新定位,或者做一些挑选,或者类似的事情。
如果您愿意,还可以设置lfs获取最近的远程refs命令。现在,这只在非常小的团队或移动非常缓慢的存储库中才有意义,因为它所做的是检索与存储库中的任何分支或标记相关的大文件内容。所以,你知道,如果你有一个10人的团队,那么你知道,30个分支,它将启动并检索30个提交的大文件。这将是非常昂贵的。所以我只会在你在一个很小的团队中工作时才会启用这个功能,而且你真的需要在本地获得所有的历史记录。
您还可以使用git lfs prune命令,这与此相反,它会在本地lfs缓存中为您回收磁盘空间。它也有几个不同的设置。默认情况下,它只会删除它认为陈旧的东西。这基本上是7或最近提交标记的值,加上这个偏移量默认是3。因此,这将删除任何与超过10天的提交相关的大文件。现在它比那聪明了一点。它不会删除任何东西——任何没有被引用的东西——任何没有被提交引用的东西,还没有被推送到服务器。我还建议启用这个prune verify remote always标志。这意味着它会检查LFS存储,以确保它将要清理的LFS对象实际上已在某个时刻被推送到该服务器,并且仍然存在。这是一种很好的安全措施。 You might want to unset that if you are actually trying to prune large files from commits that you are genuinely wanting to delete. So, you know, if you create a bunch of different, like, little, interstitial versions of a keynote file or an image then, you know, you might want to actually prune those without actually pushing them to the server.
这就是获取更大对象的方法。在某些情况下,比你可能想要的还要多。现在我要讲一下如何获取更少的对象并将指针文件保留在磁盘上而不是获取所有大的内容。你为什么要这么做?在某些情况下,你可能会有一些东西,比如持续集成构建,不需要拉下所有这些大型资产。假设我们有一个Unity电脑游戏我们有一些单元测试来测试我们的物理引擎,或者类似的东西,我们不想拉下所有那些沉重的纹理和全动态视频和声音文件。所以我们可能只是排除我们的整个资产目录,让它构建。另外,如果我们是专业人士,比如音频工程师,我们只想处理声音文件,我们可以通过使用这些包含标志之一,将项目的音频资产包括进来,让一切变得更有效率,这样我们就可以把它们拉下来。您还可以使用LFS的fetch exclude和fetch include标志将这些配置为永久设置。
关于这件事,我还有一件事想说。噢,是的。这些图案就像规则的[…]。如果你习惯使用Ant或者它也匹配。git ignore语法,非常容易使用。
现在,如果您是一名不喜欢使用命令行Git的开发人员,那么也有一组ide和GUI工具支持Git LFS。目前还没有看到JetBrains的官方声明,但看起来IntelliJ和AppCode以及JetBrains家族的其他成员似乎确实可以与Git LFS一起工作,只要你有二进制文件就在你的路径上。我在今年早些时候的Eclipse大会上与Matthias Sohn进行了交谈,他是EGit项目的维护者之一,如果您使用的是Eclipse,那么它的版本4点2加就是开箱即装的。您只需要确保Eclipse正在使用的路径上有Git LFS。因此,这意味着您应该在正确设置path变量的情况下从命令行启动Eclipse,或者正确配置路径。
因此,EGit是基于JGit项目的,JGit也是Git的Java重新实现,但它暂时仍然是Git LFS的本地版本。虽然我认为他们计划在某个时候做一个Java重新实现。NetBeans在理论上也是可行的。我和[…]谈过,他是这个项目的核心维护者之一。他计划举办一个关于如何使用它的网络研讨会,但是如果Git LFS在你的路径上,它应该可以直接为你工作。因为NetBeans的所有Git集成都是在底层向Git提供的。
不幸的是,坏消息是Xcode似乎还不支持Git LFS。实际上,苹果也有自己的Git分支,它基于一个相当老的版本,还不支持Git LFS。或者不支持Git LFS使用的一些扩展点。所以不幸的是,如果你使用的是Xcode,或者你是iOS开发者,暂时你可能需要使用命令行或者Atlassian维护一个开源软件——不是开源,而是维护一个名为SourceTree的免费Git GUI,它有完整的LFS支持。所以你可以添加、存放和提交文件,它实际上会为你完成所有的Git LFS调用。它还内置了一些显式命令和其他一些很好的东西,比如它会修复损坏的Git LFS repos,所以如果它检测到预推送钩子由于某种原因没有安装,它会关闭并为你修复它。它也像二进制预览一样,像我们之前在Bitbucket中看到的图像差异,并自动读取到后端Git LFS存储。
这就是关于Git LFS的所有内容了。正如我之前提到的,这是Atlassian和GitHub之间的一个联合项目,我们非常高兴能在这样一个重要的项目上与他们合作。Bitbucket服务器在版本4.3中完全支持它,我们在Bitbucket Cloud中有一个内部alpha版本。所以它也将很快向公众开放。
如果你愿意,你可以在Twitter上关注我,看我关于Git奥秘、Bitbucket和陪审员琐事的偶尔更新和推文。非常感谢您的宝贵时间。
