首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Git使用相同的文件推送新分支,再次上载所有文件。

Git使用相同的文件推送新分支,再次上载所有文件。
EN

Stack Overflow用户
提问于 2018-01-12 14:37:36
回答 5查看 4.4K关注 0票数 11

给出了以下情况。

  1. 创建新分支
  2. 提交10文件
  3. Git推送(上传10 Git文件)
  4. 创建一个新分支(孤儿)
  5. 提交相同的10 no文件(不做任何更改,相同的对象沙哈希)
  6. Git推送再次上载10 Git文件。

我的期望是,已经上传的文件不会再使用git push上传。但是实际发生的情况是,当创建一个新分支时,所有文件(即使是数千个较小的源文件,而不是一个10 is文件)都会被一次又一次地上传。

我的问题是:如何让Git检测到10 My文件已经上传了?您知道如何解决/修复Git在推送提交时检测服务器上已经存在的对象吗?Git通过它的sha检测文件,因此它应该能够检测到提交树中的某些文件已经存在于服务器上。

可能的用例:我有两个完全不同的分支,但是在这两个分支中共享了一些常见的文件。当我推动一个分支,我不想再上传普通文件时,我推动第二个分支。

实际用例:我使用Python脚本和一些较小的数据集(1MB -10 1MB)做了很多机器学习实验。每次我开始一个实验时,我都会将所有必要的实验文件添加到一个新的Git树中,并在没有分支的新提交中使用该树。该提交将完全免费挂起,然后使用一个新的Git引用(例如,推荐/作业/我的-实验名称)。现在,当我对几乎相同的文件(以及两个引用)进行两次实验时,当我推送这些引用时,Git再次推送所有对象。我的带宽很低,这真的减慢了我的工作速度。

代码语言:javascript
运行
复制
$ mkdir git-test && cd git-test
$ git init
$ git remote add origin git@gitlab.com:username/projectname.git

# create dummy 10MB file
$ head -c 10000000 /dev/urandom > dummy

$ git add dummy
$ git commit -m 'init'

# first push, uploads everything - makes sense
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 9.54 MiB | 1.13 MiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)

# create new empty branch, not based from master
$ git checkout --orphan branch2

# add same files again
$ git add dummy
$ git commit -m 'init on branch2'

# this uploads now again the dummy file (10MB), although the server
# has that object alread
$ git push origin branch3
Counting objects: 3, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 9.54 MiB | 838.00 KiB/s, done.

在技术方面,我们有:

  1. 两个不共享相同父母的提交(有完全不同的历史)
  2. 这两个提交具有完全相同的树sha (因此引用相同的对象文件)
  3. 两次推送都会导致在同一棵树中传输所有对象两次。尽管我希望Git检测到第二次提交中的树已经存在,或者该树中的文件对象已经在服务器上。

回答(我不能再回答了,因为有人把这个标记为副本)。

不幸的是,解决办法并不那么简单。

每次Git想同步两个存储库时,它都会构建一个包文件,其中包含所有必需的对象(比如文件、提交、树)。执行git push时,远程将所有现有引用(分支)及其头提交SHA发送到客户端。这就是问题所在:包协议不是用于每个对象,而是用于每个提交。因此,根据协议本身,上述解释的行为是正确的。为了解决这个问题,我构建了一个简单的脚本,每个脚本都可以用于基于对象执行git push,而不是提交。

你可以在这里找到它:https://github.com/marcj/git-objects-sync

它所做的:

  1. 接受一个提交(只有一个,您也需要在每个未同步的父提交上执行它),并构建属于该提交的对象SHAs (文件、树、提交)的列表(父提交除外)。
  2. 将此列表发送到服务器,服务器将返回它尚未拥有的对象的SHAs。
  3. 客户端基于缺少的对象SHAs构建一个包文件,并将其发送到服务器,其中包含需要更新哪些ref的信息。
  4. 服务器接收包文件,解压缩它并使用给定的提交SHA更新引用。

当然,这也有一些缺点,但我在链接的Github存储库中对它们进行了描述。

有了上面的脚本,您现在可以看到以下内容:

代码语言:javascript
运行
复制
marc@osx ~/git-test (branch11*) $ # added new branch11 as explained at the very top
marc@osx ~/git-test (branch11*) $ python git-sync.py refs/heads/branch11
Counting objects: 1, done.
Writing objects: 100% (1/1), 158 bytes | 158.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
marc@osx ~/git-test (branch11*) $ git push origin branch11
Everything up-to-date

因此,正如您所看到的,它只同步一个对象(提交对象),而不是再次同步dummy文件及其树对象。

EN

回答 5

Stack Overflow用户

发布于 2018-01-12 15:22:01

Git只使用引用的交换来开发它的清单并封装对象。如果您正在推送的分支与遥控器没有共同的祖先,它将打包并重新上传所有可从该分支访问的对象。

序列是这样的

  • 您:将当前远程推荐的列表发送到remote
  • 远程:将无法从该列表中到达的所有对象发送到客户端和一个新参考文献列表。
  • 您:将对象添加到本地数据库并更新远程参考
  • 您:发现您的分支上的所有提交都无法从任何远程引用(没有共同的祖先,所有提交的分支将被发送)。
  • You:根据这些提交的差异构建一个清单(查找10 of文件)
  • 你:打包送到遥控器

远程将识别其数据库中已经存在的对象并使用现有对象。

逻辑是,不时发送一些不必要的文件比每次访问和比较整个历史记录(可能有数万个或数十万个对象)要高效得多。

票数 1
EN

Stack Overflow用户

发布于 2018-01-17 17:27:26

我认为你只需要停止使用--orphan来创建新的实验分支。

工作流

  1. 创建您的初始项目。
  2. 向主分支添加和提交核心/公共文件
  3. 为每个实验创建您想要的所有非孤立分支。根据主分支创建它们。

就这样。

,怎么回事?

您坚持不使用分支,而只使用引用。然而,分支是一种参考.此外,git checkout --orphan <newthing> 是否真的创建了一个分支.问题在于,它是一个分支,它不知道以前添加到存储库中的任何内容,因为它没有父级。这与创建一个全新的存储库本质上是一样的。

如果您使用git checkout -b <newthing> master创建新分支,那么git将不会麻烦已经在主服务器中的上传文件。

现在如何管理新的公共文件?

假设有一天你有了一个新的文件,你希望将来的所有实验都能利用它--一个新的共享/通用文件。您所需要做的就是将该文件添加到master中,并根据更新的主分支创建您的下一个实验分支。如果希望该文件对现有/先前创建的实验可用,则只需签出这些分支并运行git pull --rebase origin master即可。这将引入添加到master的提交,后者将包含新添加的文件。

安装复杂性

当你开始拉,事情可能会变得复杂。对于如何更新分支有几种不同的策略,使用--rebase就是其中之一。这不是必需的,但这可能是更好的方法。还有其他需要考虑的事情,比如如何管理冲突的更改,但这些似乎超出了这个问题的范围。有大量的资源可用于解释重基/合并等。

TR;博士

不要尝试手动管理提交树和父/子关系。让git做它的事吧。

票数 1
EN

Stack Overflow用户

发布于 2018-01-14 21:17:50

实际用例:我使用Python脚本和一些较小的数据集(1MB -10 1MB)做了很多机器学习实验。每次我开始实验时,我都会将所有必要的实验文件添加到一个新的Git树中。

这似乎不是一个与Git相关的问题,而是一个内容管理问题:如果您有一组公共的静态文件,您希望从一个Git回购分支重用到另一个分支,那么这组文件(它永远不会改变)一开始就不必在Git回购中。

您可以考虑将其上传到服务器中的静态路径中,并确保您的ML脚本( Git中的版本)通过从所述静态路径获取和复制初始数据集来开始其学习过程。

或者他们可能在自己的Git中,您的脚本将从克隆/更新那些数据的子文件夹开始,方法是从外部回购中克隆/提取这些数据。

这样,您就完全绕过了版本控制问题,只有版本(在您的多分支回购中专门用于您的实验)实际上可以从提交更改为提交:您的ML脚本,可能还有一些特定的(或更小的)数据集,为新的实验量身定做。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48228425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档