用例-用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会议上宣布这个消息。
Nicola说,什么。顺便说一下,这是詹姆斯·瓦特的照片。里克就像totes一样。是不是很疯狂?你管你的工具叫什么?这就是奇怪的地方。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的原生形式,因为它在跟踪大量二进制内容时存在这个问题。
如果你是一名游戏开发者,你想要追踪游戏纹理资产或音频文件或全动态视频,这在存储库中是很难做到的。同样,如果你是一名研究人员,你想跟踪大型数据集。也许,你知道,除了你正在编写的脚本和其他编程建模之外,还有千兆字节或兆兆字节,这在你的Git存储库中会很方便,但你不能这样做,因为大二进制文件会遇到性能问题。
因此,今天我将首先讨论一下为什么Git在跟踪二进制内容时如此困难。然后,我将简要介绍一下Git LFS如何解决这个问题,并深入了解Git LFS实际上是如何扩展Git的。看看Git本身是如何以这种可扩展的方式构建的,这很有趣。然后,如果您已经在跟踪现有存储库中的二进制内容,我将为您提供一些将现有存储库转换为使用Git LFS的技巧。然后,我们将了解如何使用现有的Git托管提供商和Artifactory来有效地将大型二进制文件存储在一个地方。最后,我将为您提供一些在团队上下文中使用Git LFS的技巧,以确保您在处理团队的其他大型二进制文件时不会破坏它们。
所以,首先要理解为什么Git在处理大型二进制文件时如此困难,你需要了解一点Git数据模型。现在,当您考虑随着时间对代码库的更改时,因为它与版本控制有关,您可能会考虑一组修订或提交。在Git中,这些修订,实际上它们在Git中被称为提交,这些提交不只是漂浮在空间中。他们之间有血缘关系。具体来说,在合并提交的情况下,每个提交都有对其直接父级或父级的引用。现在,如果我们放入分支或标记(在Git术语中通常称为ref),您就开始了解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 repo中的任何对象。如果你传递它是破折号p标志,它将以一种人类可读的漂亮格式打印出来。
提交其实很简单。它们只是几个字节。首先,您有一个对提交的直接父级或多个父级的引用。你看到的十六进制SHA-1地址,当你第一次从集中式版本控制系统转移到Git时,看起来有点可怕,实际上是Git对象内容的SHA-1哈希。你可能听说过Git被引用到一个内容可寻址的文件系统,这是因为每个Git对象都被这些SHA-1散列之一引用。这对于Git如何存储这些数据有一些非常重要的属性。最有价值的属性之一是可以很容易地检测重复的对象。你们马上就会明白为什么这很重要。
这个commit对象的下一个东西是树。这是另一个SHA-1哈希。也就是树的地址和内容。该树类似于Git存储库所跟踪的根目录。我们马上就会看到那个树实际上包含了Git repo中被跟踪的每个对象或文件的引用。然后我们有一些提交元数据。创建提交的提交者,最初编写代码的作者,这些通常是同一个人,这取决于你的工作流,然后你也有一个提交消息。但对于大多数提交,这基本上是您将看到的全部内容。
现在,如果我们再次弹出cat文件命令,我们可以指向那个树对象,并查看它的结构。你会发现它很像文件系统上的目录。我们有文件模式,有嵌套树,基本上是Git存储库根级的子目录,还有blob。这些斑点同样是SHA-1散列指向磁盘上该文件的实际内容。最后是路径。repo中所有文件和目录的名称都存储在这些树对象中。
如果我们继续向下递归到Git树中,我们可以看到存储库的全部内容。如果我们再加入另一个引用、分支或标签,我们得到的就非常接近完整的Git数据模型了。所以实际上,当你看它的时候,它实际上是非常简单的。说实话,理解这一点是我了解Git如何工作的最好方式之一。
Scott Chacon写了一本很好的书叫做Pro Git。它很早就介绍了这个概念,然后开始讨论在工作流中作为Git数据模型转换使用的所有不同的Git命令。所以,如果你遇到了困难,或者你正在学习Git,阅读这本书,这是了解Git底层的最好方法之一。
Git在处理大型二进制内容时之所以如此困难,是因为每次创建提交时,我们最终都会创建一个新的这些树。所以每次我们在存储库中修改一个文件,添加它并提交它,我们就创建了一个新的blob,这意味着每个树无论是直接父树还是blob的祖父树,都必须重写。幸运的是,因为Git是内容可寻址的,所以Git很容易不创建未更改对象的副本。但是如果对象发生了变化,Git必须创建一个全新的blob。Git最终会对这些blob进行delta编码。如果你有,但取决于二进制格式,它可能压缩得很好,也可能压缩得不好。
让我们举一个非常简单的例子,我们有一个存储库,它实际上是一个目录,里面有一个文件,比如说一个高分辨率的大象文件,以某种原始文件格式存储。因为它是原始的,每个像素都将被编码为一组字节。如果我们改变大象的颜色。对不起,这里的颜色区分不是很好,但那头大象应该是粉红色的。然后当我们将它添加并提交到我们的存储库时,它会创建一个全新的blob它会将repo的大小增加一倍。等等,我们对这个图像做更多的改变。
因此,当你有大型二进制文件时,存储库就会膨胀、膨胀、膨胀。现在使用传统的集中式版本控制系统,这不是一个大问题,因为回购的整个历史都存储在一个中央服务器上,每个开发人员通常一次只检索一个提交并使用它,所以你只有最新版本的快照。有妈妈纹身的大象。但是对于Git,它是一个分布式版本控制系统。所以你实际上是在复制存储库的整个历史每次你需要做推,拉或克隆。这意味着我要把我修改过的这个文件的每一个版本都推到服务器上,而我的团队的其他成员必须把这个文件的每一个版本都拉下来。
类似地,如果我有游戏脚本或持续整合构建,他们有时可以根据具体用例进行浅层克隆。但通常情况下,你最终不得不复制这段丰富的历史,这是非常沉重的。这不仅扩大了回购的规模,还减缓了推拉的速度。这意味着Git服务器上的负载会不断增加,直到一切都停止。
现在Git LFS是这个问题的解决方案。正如我所提到的,它是Git的扩展。这并不是Git的第一个试图解决大文件问题的扩展。比如Git附件,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 repo中,我们没有一个接近几兆或几吉字节的文件,从而减慢了一切,我们只有几个字节。
现在你可能注意到这是一个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添加和Git签出命令。我们马上就会看到它是如何工作的。
一旦你设置了Git LFS,你可以运行Git LFS track命令,告诉LFS你想在LFS中跟踪哪些文件模式或文件名,而不是直接添加到你的Git对象目录中。现在它所做的是向git属性文件中添加一个新条目。这也是另一个原生Git概念,可以用于扩展Git。它将该图案绑定到LFS涂抹和清除过滤器。
那么这些过滤器是如何工作的呢?让我们先来看看清洁过滤器。当开发人员运行git add命令并将文件名传递给它时,它不会直接将其添加到git索引中,并在git对象目录中创建一个对象,而是将其交给git lfs clean命令。它接受该对象内容的SHA-256哈希,并将其添加到位于git / lfs /斜杠对象下的特殊对象缓存中。所以它看起来非常类似于git objects目录,但是它的命名空间在lfs下面。因此,Git LFS再次尝试遵循现有的Git模式,使其尽可能透明。
一旦它将内容存储在那里,在SHA-256哈希下,作为文件名所以它也是内容可寻址的,它会添加一个新的指针文件,具有对象大小的SHA-256哈希到Git对象目录中。所以不是增加兆字节或千兆字节,它只是增加了几个字节到你的回购的大小。
然后,当开发人员进行取回、克隆或拉取,并实际想要使用这些大文件时,Git涂抹过滤器就会启动。因此,当开发人员运行签出时,该文件,即指针文件,将移交给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存储库。在。git目录中,也就是git存储与repo相关的所有数据的地方,你会看到一个hooks目录,在那里,有一大堆示例脚本,展示了拦截git调用时可以做的很酷的事情。
为了方便,您可以做一些事情,比如预先填充提交消息。因此,作为一个开发人员,我使用的一个方法是,我们用陪审员问题来命名我们所有的Git分支。我得到了这个pre-commit消息,pre-commit消息钩子,它从分支名称中取出问题键然后插入到我的提交消息的开头这样我就不用每次都手动输入了。
你也可以创建像预提交钩子这样的东西,它可以在你创建提交之前运行单元测试。这是一个非常强大的想法,因为这意味着您默认创建的每个提交都已经通过了测试。这有点像前ci阶段。现在,Git LFS使用的预推送钩子允许您拦截Git推送操作。当你运行git push时,你在本地创建了一些需要传输到服务器的大对象,你会看到这个输出说,嘿,我正在传输一些文件到你的git LFS repo,这是它被上传时的状态。
这里真正的好处是您不会得到任何身份验证提示。不管你使用的是HTTP还是SSH, Git LFS实际上都依赖于你现有的Git LFS凭证。Git LFS OS服务器将处理这两种用例。所以你不需要离开,你知道,输入额外的命令或添加到你的钥匙链。它只是透明地与您现有的身份验证模型一起工作。实际上,我在最后有一些幻灯片是关于这个认证过程是如何工作的,所以如果我有时间,我就会跳到这一点,因为它实际上是[…]的一个非常非常酷的使用。
类似地,当你运行git pull时,你会看到smudge过滤器的一些输出,因为它读取了备份LFS存储,说它正在下载这些大文件。正如我之前提到的,它也可以透明地与SSH一起工作。这是Git LFS相对于早期竞争对手(如Git Media)的杀手级特性之一。
这就是Git LFS的工作原理,我想谈谈如何将现有的存储库转换为Git LFS。我之前讲Git LFS跟踪命令时可能误导了你们。因为如果你在已有的存储库上使用它,它会把这些大文件转换成指针,这很好。但不幸的是,它对已经膨胀的存储库没有任何帮助,因为在回购历史记录中仍然有这些大的blobs。
现在,如果您相当专业,好吧,不是专业人士,但如果您有很多Git经验,特别是重写历史,那么此时您可能会使用Git过滤器分支命令。有人用过过滤器分支吗?是的。有点,有点可怕和痛苦,不是吗。花了我——我做了这张幻灯片,我花了大约10分钟才忘记它到底在做什么。它在这里做的实际上是返回并从存储库历史中重新删除所有这些大的blob。这不是个好主意。这将极大地减少你的回购规模,但不幸的是,这意味着这些实际上已经从你的历史中消失了。所以如果你需要回去查看那些大的斑点,它会消失。这对于审计目的或需要回滚来说不是很好。
现在,Git LFS的核心贡献者之一Andy Neff提出了这个真正天才的/疯狂的Git filter分支命令,它实际上会返回并将所有这些blobs重写为Git LFS指针。这真的令人印象深刻,但事实证明,现在有一种更简单的方法来做到这一点。
有个很棒的工具叫好心眼巨人回收清理器。这是一个在《卫报》工作的开发者罗伯特·泰利的作品。罗伯托刚开始做这个工具时,遇到了一个问题。一个开发人员意外地提交了一些敏感的内容到他的回购中的一个属性文件的早期版本。这是一个问题,因为要删除它,他必须回去,基本上,你知道,运行过滤器分支,从历史中删除它。现在过滤器分支很棒,但它有点像重写存储库历史的瑞士军刀。但它使用起来也很吓人,而且速度非常慢。关于Git的一件事是,归根结底,它是一个bash脚本的集合,以及其他用c编写的底层命令,但它并没有真正的系统进程。过滤器分支通常会遍历你的整个DAG并一遍又一遍地重新处理相同的对象和树。
现在,BFG Repo-Cleaner是一个专门用来删除历史记录的工具,它建立在JGit之上,这是一个用纯Java完全重新实现的Git。它有一个系统过程。所以它实际上会回去记住每棵树和每一个被处理过的对象因为它的内容是可寻址的,它知道不需要再去重新处理它们。所以它实际上比过滤器分支快10到720倍。
如果你去BFG的Repo-Cleaner主页,他们有这些过程的电子表格-这些开源项目,他们运行它来重写历史,他们得到的数据令人印象深刻,速度有多快。
它最初是用来消除历史记录的,所以它可以删除文件,比如从你的历史记录中删除整个文件夹,甚至文件中的字符串。如果你提交了一个证书,密码,AWS密钥之类的东西到属性文件中,你可以用散列符号替换它。但是从版本1点12点5开始,Roberto内置了对Git LFS的支持。因此,您可以简单地安装BFG,而不是这个神奇的斜线疯狂的过滤器分支命令,它是用Java编写的,因此难以置信的可移植性,并且可以在几乎任何Git平台上运行,然后运行方便的convert to Git lfs命令,并将您想要用lfs跟踪的文件的模式或名称传递给它。
现在有一个有点神秘的标志,你必须通过称为无斑点保护。这意味着它将重写分支的tip提交以及整个历史记录。默认情况下,BFG假设您的存储库现在处于良好状态,因此出于安全考虑,它不会触及提示提交,但当您使用LFS重写历史记录时,通常也会重写提示提交。所谓提示,我指的是您当前签出的分支上的最新提交。
这就是你如何利用好心眼巨人重写你的历史。但是你会遇到这样的问题,特别是对于大型存储库或具有很长历史的存储库,那就是我应该用LFS跟踪哪些文件。今年早些时候在纽约的Git Merge上,我听了一个叫Charles Bailey的家伙的演讲,他在彭博社工作,他刚刚开源了一套叫做Repofactor的工具。Repofactor的作用是帮助您识别存储库中的大型blob链。我说的链,是一团链。基本上它会查看为特定文件创建的第一个blob,然后它会找到存储在存储库中的所有其他blob,这些blob也是为该文件的新版本创建的。然后,它会计算该斑点随时间的平均大小。这很好,因为大小是文件压缩效果的函数。如果它压缩得不好,使用zlib压缩,这是Git在底层使用的,这使它成为LFS的一个很好的候选,因为当你转换到LFS时,你会节省大量的文件空间或磁盘空间。
现在,它是一组命令行工具,而不仅仅是将Git存储库插入其中的应用程序。经过一番折腾,这是我发现的最有效的方法。首先,你要使用generate bigger than命令你给它一个整数这是我认为一个大文件的字节数的阈值。然后它会输出对象的SHA-1哈希值。每个blob后面都跟着这个blob在磁盘上的大小然后它就会给出那个特定的blob链的平均blob大小抱歉,是blob链。一旦您获得了这些信息,您就可以将其输送到add file info命令,该命令使用bash file命令嗅出每个blob的内容类型。然后你就可以看到更多关于它的信息了。现在我们知道这些斑点代表了一个合理分辨率的PNG文件。然后,您可以将其输送到排序,并根据平均blob大小开始排序。所以那些,比较适合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),那么您可能希望开始使用Artifactory来管理您的二进制文件,因为它为整理二进制文件提供了所有出色的功能。您实际上可以设置一个新的本地存储库来跟踪Git LFS对象,然后您可以浏览您的LFS回购,并使用树浏览器实际查看Artifactory中的所有这些大blobs。你也可以使用AQL来查询那些大的对象,这是非常简洁的。你可以做其他的事情,比如手表之类的。如果你想把所有二进制文件都存储在Artifactory中,你完全可以这么做。
现在,它的工作方式是,您的开发人员,或为您的存储库创建LFS的第一个初始化的人,将需要配置该repo,以指向您的大文件的Artifactory。这样做的方法是创建一个lfs配置文件,它位于repo的根目录中。这可以像存储库中的任何其他文件一样。所以你可以检查它,提交它,然后把它推到服务器上,它就会开始为你的所有其他开发人员工作。
现在你不需要记住它的格式,因为很棒的Artifactory set me up按钮也适用于LFS。它实际上会根据Artifactory实例的位置为您生成配置。它所做的是覆盖LFS API的位置。因此,它不是指向桶服务器,而是指向Artifactory。
现在使用本地Artifactory存储库有一个主要缺点。那就是Bitbucket不会知道这些LFS文件被跟踪的位置。这意味着UI中不再有漂亮的图像差异,你会看到这些小指针文件的差异。这并不是一种最佳体验。因此,从Artifactory four。7开始,他们发布了对远程LFS存储库的支持。所以这意味着你可以设置Artifactory来启动-作为这些在Bitbucket服务器中跟踪的LFS文件的代理或缓存。所以这意味着LF -你的Bitbucket服务器实例仍然在为你跟踪这些大对象,但Artifactory会意识到它们,所以你可以做一些事情,比如设置手表和使用AQL查询它们。这真的很强大。
你可以做的另一件事,4。7他们还发布了对虚拟回购的支持。所以你可以创建一个虚拟的Artifactory回购,它可以在Bitbucket和Artifactory上聚合一组这些LFS存储的回购。是的,就像我提到的,你也可以设置虚拟回购如果你想要一组LFS回购的虚拟视图。我认为你也可以直接推到虚拟回购然后它会有一个默认的LFS存储。
这就是你如何使用Artifactory和Bitbucket服务器或任何你用于Git托管的服务器一起使用。现在我想谈谈如何在团队上下文中使用Git LFS。因为到目前为止,我主要讲的是单个开发者如何与你的回购交互。首先要记住的是你必须非常小心合并冲突。Git非常非常擅长处理文本文件的合并,但不幸的是,它不知道你在存储库中跟踪的二进制文件,也没有很好的方法来执行语义合并。没有什么比在一个大型二进制文件上工作一整天,却发现团队中的其他人也在另一个分支上修改该文件更令人沮丧的了。因为这意味着,你知道,以一个大的视频文件为例,你可能会花一整天渲染这个东西,然后发现其他人已经在做同样的事情,实际上你没有办法解决这些冲突。你必须回去,在他们的工作之上重新应用你的所有工作,或者让他们做同样的事情。
所以目前,Git LFS还没有锁定的概念。实际上,有一个谷歌的暑期代码申请者成功获得了批准,并正在为Git LFS编写锁定规范。所以祈祷在接下来的几个月里会有一些事情发生。但与此同时,你能做的最好的事情就是告诉你团队的其他成员,或者其他任何可能修改同一个文件的人,传递互斥量,告诉他们,他们应该推迟移动,修改那个文件,直到你完成。
现在我主要谈论的是如何——Git LFS有多棒,因为它只检索您想要使用的内容的最新版本。但在某些情况下,你可能想要获取的不仅仅是你签出的提交所引用的大型二进制文件。
这里有个命令叫git lfs fetch默认情况下,它会放大tip commit中的指针文件。但你可以传递dash recent标志,那意味着它会离开并检索与最近更新的分支相关的内容。它最近定义的是任何分支上有一个更新超过7天的提交。这很方便。如果你喜欢这个行为,你可以设置它为默认值通过设置fetchedrecent always标志为true。这很方便,特别是当你要跳上飞机或类似的东西你需要使用多个分支你可以运行git lfs fetchdash recent它会帮你拉下来。
现在您也可以调整这个行为。你可以设置一些属性标志。第一个是最近的refts天。这基本上改变了滑动窗口的长度因为它认为是最近的分支。你也可以设置fetch recent commits days属性。这个默认为0,原因是这意味着它会为非分支提示的提交检索大内容。如果我有一个分支在昨天有10次提交,它就会去检索每一个的所有大文件。这是一个非常不寻常的情况。我能想到的唯一合理的用例是,如果你要跳上飞机或失去网络连接,你需要做一些回购手术。比如,你知道,也许做一个二分搜索,回顾你的历史,或者你计划重新建立基地,或者做一些樱桃采摘之类的事情。
如果你愿意,你也可以设置lfs fetch recent remote 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电脑游戏,我们有一些单元测试来测试我们的物理引擎,或类似的东西,我们不想删除所有那些沉重的纹理和全动态视频和声音文件。我们可以排除整个资产目录,让它构建。或者,如果我们是音频工程师之类的专家,我们只想处理声音文件,我们可以通过使用其中一个include标志来提高效率,并为我们的项目包含音频资产,这样我们就可以把它们拉下来。您还可以使用fetch exclude和fetch include标志为LFS将这些设置配置为永久设置。
关于这件事,我还有一件事想说。噢,是的。而这些图案就像普通的[…]。如果你习惯使用Ant或者它也匹配。git ignore语法,很容易使用。
现在,如果你是一个不喜欢使用命令行Git的开发人员,那么也有一组ide和GUI工具支持Git LFS。目前还没有看到来自JetBrains的官方声明,但似乎IntelliJ和AppCode以及JetBrains家族的其他成员确实可以使用Git LFS,前提是你有二进制文件在你的路径上。我在今年早些时候的Eclipse Con上和Matthias Sohn交谈过,他是EGit项目的维护者之一,如果你正在使用Eclipse,它就可以使用版本4。2 +。您只需要确保Eclipse正在使用的路径上有Git LFS。因此,这意味着您应该通过正确设置路径变量从命令行启动Eclipse,或者正确配置路径。
所以EGit是基于JGit项目的,这也是Git的Java重新实现,但它仍然是Git LFS的本地版本。不过我认为他们计划在某个时候重新实现Java。NetBeans在理论上也是可行的。我和[…]谈过,他是这个项目的核心维护者之一。他计划举办一个关于使用Git LFS的网络研讨会,但是如果Git LFS在你的道路上,它应该可以直接为你工作。因为NetBeans在底层为Git提供了所有的Git集成。
不幸的是,坏消息是Xcode似乎还不支持Git LFS。苹果实际上有他们自己维护的Git分支,它是基于一个还不支持Git LFS的相当旧的版本。或者不支持Git LFS使用的某些扩展点。不幸的是,如果你在使用Xcode,或者你是iOS开发者,暂时你可能需要使用命令行,或者Atlassian维护了一个开源,不是开源,而是维护了一个免费的Git GUI,叫做SourceTree,它完全支持LFS。你可以添加、提交文件,它会在底层为你执行所有Git LFS调用。它还内置了一些显式命令和其他一些不错的东西,比如它会修复损坏的Git LFS repos,所以如果它检测到pre-push钩子由于某种原因没有安装,它会为你修复它。还有二进制预览,就像我们之前在Bitbucket中看到的图像差异,自动读取到你的后端Git LFS存储。
这就是我所有的关于Git LFS的东西了。正如我之前提到的,这是Atlassian和GitHub之间的一个联合项目,我们非常高兴能在这样一个重要的项目上与他们合作。它在比特桶服务器上得到了完全的支持,我们有一个内部alpha在比特桶云上运行。所以它也将很快向公众开放。
如果你愿意,你可以在Twitter上关注我偶尔的更新和关于Git奥秘、Bitbucket和陪审员琐事的推文。非常感谢你的时间。
