我有一个应用程序需要在我想要推送的每个文件上运行// git add,以便在每个文件上触发 Gitlab 作业。commitpush
我的问题是 git 实际上需要很多时间来执行命令git push。
这是我正在使用的命令:
git add myFile.json
git commit myFile.json -m "commitMessage"
variable1 = git rev-parse HEAD # Storing last commit hash into a variable
# Pushing only one specific commit to (maybe) make it faster
git push $variable1:master
Run Code Online (Sandbox Code Playgroud)
我想做的是让整个过程“更快”。我的想法是:
git push(也许通过在每次提交而不是每次推送时运行管道),但这似乎不可能。git push,因此不必git push在推送每个文件之前重新加载一些初始化操作(我不知道在此git push过程中发生了什么,所以这个想法可能是错误的)有谁知道如何通过使用我的想法之一,甚至是您的全新想法来加快此过程!
注意:我使用的是 HTTPS,因此 SSH 解决方案可能不适合这里。
推送命令的输出:
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 521 bytes | 521.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://gitlab/root/xxx.git
bd0a7c1..9671b26 master -> master
Run Code Online (Sandbox Code Playgroud)
提前致谢 !
编辑1:
这是输出GIT_TRACE=true GIT_TRACE_PACKET=true git push
12:47:38.387505 git.c:418 trace: built-in: git push https://root:password@gitlab/root/xxx.git
12:47:38.405394 run-command.c:643 trace: run_command: GIT_DIR=.git git-remote-https https://root:password@gitlab/root/xxx.git https://root:password@gitlab/root/xxx.git
12:47:39.926614 pkt-line.c:80 packet: git< # service=git-receive-pack
12:47:39.926654 pkt-line.c:80 packet: git< 0000
12:47:39.926664 pkt-line.c:80 packet: git< 4a902e3cdd3c06ba7fe9aa0345e510ce7c7ebb73 refs/heads/master\0report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta push-options object-format=sha1 agent=git/2.33.1.gl3
12:47:39.926678 pkt-line.c:80 packet: git< 0000
12:47:39.931365 pkt-line.c:80 packet: git> refs/heads/master:refs/heads/master
12:47:39.934089 pkt-line.c:80 packet: git> 0000
12:47:39.934131 run-command.c:643 trace: run_command: git send-pack --stateless-rpc --helper-status --thin --progress https://root:password@gitlab/root/xxx.git/ --stdin
12:47:39.954005 git.c:418 trace: built-in: git send-pack --stateless-rpc --helper-status --thin --progress https://root:password@gitlab/root/xxx.git/ --stdin
12:47:39.962814 pkt-line.c:80 packet: git< refs/heads/master:refs/heads/master
12:47:39.962841 pkt-line.c:80 packet: git< 0000
12:47:39.965723 pkt-line.c:80 packet: git< 4a902e3cdd3c06ba7fe9aa0345e510ce7c7ebb73 refs/heads/master\0report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta push-options object-format=sha1 agent=git/2.33.1.gl3
12:47:39.965792 pkt-line.c:80 packet: git< 0000
12:47:39.998180 pkt-line.c:80 packet: git> shallow 67769ed9405583783a372dc7731d5c1be8801a63
12:47:39.998324 pkt-line.c:80 packet: git> 4a902e3cdd3c06ba7fe9aa0345e510ce7c7ebb73 4f72bdb2e340f297c5c88a3433bf1700a010f721 refs/heads/master\0 report-status side-band-64k agent=git/2.20.1
12:47:39.998420 pkt-line.c:80 packet: git> 0000
12:47:39.998841 pkt-line.c:80 packet: git< 0035shallow 67769ed9405583783a372dc7731d5c1be8801a6300954a902e3cdd3c06ba7fe9aa0345e510ce7c7ebb73 4f72bdb2e340f297c5c88a3433bf1700a010f721 refs/heads/master\0 report-status side-band-64k agent=git/2.20.10000
12:47:39.998986 run-command.c:643 trace: run_command: git pack-objects --all-progress-implied --revs --stdout --thin --delta-base-offset --progress --shallow
12:47:40.007547 git.c:418 trace: built-in: git pack-objects --all-progress-implied --revs --stdout --thin --delta-base-offset --progress --shallow
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 530 bytes | 530.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
12:47:40.202197 pkt-line.c:80 packet: git> 0000
12:47:40.202196 pkt-line.c:80 packet: git< PACK ...
12:47:41.680994 pkt-line.c:80 packet: sideband< \1000eunpack ok0019ok refs/heads/master0000
12:47:41.681027 pkt-line.c:80 packet: sideband< 0000
12:47:41.681108 pkt-line.c:80 packet: git< unpack ok
12:47:41.681132 pkt-line.c:80 packet: git< ok refs/heads/master
12:47:41.681148 pkt-line.c:80 packet: git< 0000
12:47:41.681153 pkt-line.c:80 packet: git> 0000
To https://gitlab/root/xxx.git
4a902e3..4f72bdb master -> master
Run Code Online (Sandbox Code Playgroud)
长的部分似乎是run_command: GIT_DIR=.git git-remote-https和git<PACK ...。
该命令在depth=2 git clone.
注意:第一个push总是很快(似乎在 1 或 2 秒之间),后续的大多在 3 到 4 秒之间。我尝试在推送之间添加一个sleep间隔,但持续时间没有改变,所以我想这不是我的代码的问题。
这是我第一次推送的输出:
12:46:16.834461 git.c:418 trace: built-in: git push https://root:password@gitlab/root/xxx.git
12:46:16.836817 run-command.c:643 trace: run_command: GIT_DIR=.git git-remote-https https://root:password@gitlab/root/xxx.git https://root:password@gitlab/root/xxx.git
12:46:17.307690 pkt-line.c:80 packet: git< # service=git-receive-pack
12:46:17.307951 pkt-line.c:80 packet: git< 0000
12:46:17.308003 pkt-line.c:80 packet: git< 6725c964319de48c963746e976a97634f0ee0e7c refs/heads/master\0report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta push-options object-format=sha1 agent=git/2.33.1.gl3
12:46:17.308024 pkt-line.c:80 packet: git< 0000
12:46:17.309205 pkt-line.c:80 packet: git> refs/heads/master:refs/heads/master
12:46:17.309223 pkt-line.c:80 packet: git> 0000
12:46:17.309271 run-command.c:643 trace: run_command: git send-pack --stateless-rpc --helper-status --thin --progress https://root:password@gitlab/root/xxx.git/ --stdin
12:46:17.312085 git.c:418 trace: built-in: git send-pack --stateless-rpc --helper-status --thin --progress https://root:password@gitlab/root/xxx.git/ --stdin
12:46:17.313673 pkt-line.c:80 packet: git< refs/heads/master:refs/heads/master
12:46:17.313707 pkt-line.c:80 packet: git< 0000
12:46:17.313722 pkt-line.c:80 packet: git< 6725c964319de48c963746e976a97634f0ee0e7c refs/heads/master\0report-status report-status-v2 delete-refs side-band-64k quiet atomic ofs-delta push-options object-format=sha1 agent=git/2.33.1.gl3
12:46:17.314002 pkt-line.c:80 packet: git< 0000
12:46:17.316186 pkt-line.c:80 packet: git> shallow 67769ed9405583783a372dc7731d5c1be8801a63
12:46:17.316209 pkt-line.c:80 packet: git> 6725c964319de48c963746e976a97634f0ee0e7c 6665f070f909ed946bf8223516f69691c15e9c29 refs/heads/master\0 report-status side-band-64k agent=git/2.20.1
12:46:17.316316 pkt-line.c:80 packet: git> 0000
12:46:17.316423 pkt-line.c:80 packet: git< 0035shallow 67769ed9405583783a372dc7731d5c1be8801a6300956725c964319de48c963746e976a97634f0ee0e7c 6665f070f909ed946bf8223516f69691c15e9c29 refs/heads/master\0 report-status side-band-64k agent=git/2.20.10000
12:46:17.316509 run-command.c:643 trace: run_command: git pack-objects --all-progress-implied --revs --stdout --thin --delta-base-offset --progress --shallow
12:46:17.318598 git.c:418 trace: built-in: git pack-objects --all-progress-implied --revs --stdout --thin --delta-base-offset --progress --shallow
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 521 bytes | 173.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0)
12:46:17.339570 pkt-line.c:80 packet: git< PACK ...
12:46:17.339830 pkt-line.c:80 packet: git> 0000
[03/May/2022 12:46:17] "POST /api/getStatus/ HTTP/1.1" 200 854
12:46:18.029134 pkt-line.c:80 packet: sideband< \1000eunpack ok0019ok refs/heads/master0000
12:46:18.029164 pkt-line.c:80 packet: sideband< 0000
12:46:18.029277 pkt-line.c:80 packet: git< unpack ok
12:46:18.029285 pkt-line.c:80 packet: git< ok refs/heads/master
12:46:18.029293 pkt-line.c:80 packet: git< 0000
12:46:18.029297 pkt-line.c:80 packet: git> 0000
To https://gitlab/root/xxx.git
6725c96..6665f07 master -> master
Run Code Online (Sandbox Code Playgroud)
这部分的持续时间GIT_DIR似乎更快了,git< PACK ...几乎是瞬间的。
编辑2:
看来这只是我的服务器的性能问题,但我认为@torek 答案可以帮助人们搜索这个主题,所以我将其标记为已接受。
编辑:这个答案适用于ssh连接。由于问题讨论的是https, @torek 的答案更合适。
提高速度的一种方法是使用 sshControlMaster选项。它避免了 ssh 每次重新打开连接。
手册页中的ControlMaster选项ssh_config:
允许通过单个网络连接共享多个会话。当设置为 yes 时,ssh(1) 将侦听使用 ControlPath 参数指定的控制套接字上的连接。其他会话可以使用相同的 ControlPath 连接到此套接字,并将 ControlMaster 设置为 no(默认值)。这些会话将尝试重用主实例的网络连接,而不是启动新的网络连接,但如果控制套接字不存在或未侦听,则将回退到正常连接。
例如在我的 ~/.ssh/config 中我有:
ControlMaster auto
ControlPath ~/.ssh/mux-%r@%h_%p
ControlPersist 15m
Run Code Online (Sandbox Code Playgroud)
我的猜测是,您让 GitLab 使用浅克隆,这通常会使速度更快,但在这种情况下,它会使速度慢得多。
\n这可能是关键评论:
\n\n\n长的部分似乎是在枚举对象之前和写入对象期间。剩下的几乎是即时的。
\n
其中很多内容都存在于 Git 内部的杂草中,这些内部结构可能会在没有警告的情况下随时发生变化。因此,过度依赖这些是不明智的。尽管如此,这就是发生的事情:
\nGit存储库主要由两个数据库组成。一个数据库保存 Git对象,另一个数据库保存名称:refs或references。对象被编号(通过哈希 ID 或对象 ID、OID)。refs 将人类可用的名称(例如refs/heads/main分支名称)转换main为 OID,每个名称仅存储一个 OID。
OID 是通用的:每个对象都有一个唯一的 OID,并且所有 Git 都对相同的对象进行相同的编号。这意味着任何两个 Git 存储库都可以满足\xe2\x80\x94,无论是第一次,还是第 n 个具有较大值n \xe2\x80\x94 的存储库,而且几乎可以立即找出是否其他存储库有一些对象,只需交出对象的 ID 即可。发送的 Git 列出了某些关键的 OID,接收的 Git 则以“我有那个”或“我想要那个”响应进行响应。
\n接下来我们需要的事情在技术上是复杂的,但可能足够容易可视化或理解。提交对象包含已知的元数据值,包括父提交列表和一个(单个)树对象。树对象由给出组件名称、对象类型(或“模式”)和对象 ID 的重复元组组成。树中列出的对象通常是另一棵树或blob对象。Blob 对象表示文件的内容:该文件的名称是通过将提交到该 Blob 的树对象的名称串在一起生成的。
\n任何给定提交的父提交都是在提交本身进行时存在的提交。一次提交一项。这意味着从 commit 到 commit 的连接中不能存在循环:如果 commitH向后链接到 commit G,则 commitG无法向前链接到 commit H,因为在创建 H时不存在。可以链接回更早的提交,但不能转发到或。GGGH
类似地,树对象不能引用自身,树对象内的任何子树也不能引用回树对象或正在执行引用的子树“之上”的任何子树。也就是说,如果树 OID9876543存在,则它的任何条目都不能引用 object 9876543,并且它的子树\xe2\x80\x94(例如,5566778\xe2\x80\x94)都不能引用其中9876543任何一个。因此,从提交开始发现的任何树集中都不可能存在循环。这些规则意味着树实际上就是一棵树,它是 DAG 的子集:请参阅数据结构树和图之间有什么区别?
(Blob 对象代表文件内容,在这个级别上对 Git 来说是不透明的:Git 不必检查它们,也不会这样做。)
\n所有这一切的最终结果是提交本身形成有向无环图或 DAG。同时,每个提交中的顶级树对象形成树对象树。所以我们有一个树的 DAG,或者 DAG 的 DAG,无论你想如何引用它;这样的组合本身就是一个 DAG。(请注意,提交可以重用早期提交中的顶级或子级树:这在这里完全没问题,因为它不会违反 DAG 规则。)
\n(最重要的是,我们可以有带注释的标签对象,它存储一个目标对象的哈希ID 。因为它们仅限于单个目标,并且Git的哈希ID计算规则禁止循环,所以这些只是添加一个很少有引导到对象节点到整个 DAG-of-DAG。它们给可视化增加了一点复杂性,但不会扰乱整体 DAGginess。)
\n最终,所有这一切都归结为我们的整体图结构带有约束:方向性和缺乏循环。任何这样的DAG都具有可达性:即从图中的某个节点开始,图中可能存在我们可以到达的其他节点,也可能存在图中我们无法到达的其他节点,通过以下方式-way 连接:提交b789abc有父级a123456,因此a123456可以从 到达 b789abc。由于没有循环,根据定义这意味着b789abc无法从到达a123456。(但是,您不能推断相反的情况:如果节点 X 无法从节点 Y 到达,这并不意味着 Y 可以从 X 到达。也许 W 或 Z 可以同时到达 X 和 Y,但 X 和 Y 只是某个节点中的兄弟节点)以树为例。)
为此,我们通常会添加一个约束:Git 存储库中永远不会有“漏洞”。我的意思是,如果我们在图中有某个节点,那么我们必须始终让每个节点都可以从该节点访问。如果a123456是父级b789abc,并且我们有b789abc,那么我们也必须有a123456。这反过来意味着我们必须拥有的整个快照 a123456。如果a123456有父提交,我们也必须拥有该提交的整个快照,依此类推。
请注意上面对“通常”一词的强调。在这种情况下,如果我们是发送者并且正在执行 a git push,我们通常只需知道哪些提交是接收Git 存储库中的最新提交,就可以知道有关这些提交的所有信息。也就是说,如果我们有新的提交b789abc并且它们有其父级a123456,那么我们就已经有了a123456自己。我们还拥有从 可以到达的一切 a123456。所以我们知道他们拥有的每个文件的一切,至少就a123456 其所有祖先而言。
这给发送的 Git 带来了巨大的帮助:它告诉接收的 Git我可以向你发送 commit b789abc,你喜欢吗? 接收的 Git 可能会回答“我已经有了”b789abc,在这种情况下,我们知道有关接收的 Git 需要知道的一切,或者可能会说“是的,我喜欢那样”。如果它说的是后者,我们作为发送的 Git,现在必须提供父级a123456. 他们会回复“我已经拥有它”或“请发送它”,然后我们将提供其父级,依此类推。
在某些时候,我们要么用完要发送的提交\xe2\x80\x94,他们什么都没有,我们必须发送每个对象\xe2\x80\x94,或者我们命中他们拥有的一些提交,这意味着他们拥有该提交和每个更早的提交提交,我们,发送者,现在也确切地知道他们拥有哪些文件。因此,我们可以很好地向他们发送他们需要的提交以及这些提交所需的文件,并且压缩这些文件,知道他们已经拥有这些文件的早期版本。
\n请注意,这里有一个很大的总体假设,即 CPU 时间很便宜,但网络带宽很昂贵。我们使用这个 OID 交换过程来查找它们已经拥有的内容,然后准备新对象并将它们与已知的旧对象进行压缩。这个(“压缩对象”)部分可能需要很多时间,具体取决于我们自己的计算速度。但它通常很快,因为通常我们只发送一个或几个提交,每个提交只有一个或几个新的或修改的文件,因此没有太多需要压缩的内容。然后我们发送这些对象,这部分与网络一样慢,但是如果我们压缩得很好,我们就不必发送许多对象,并且我们已经将它们与其他对象相比压缩得很好已经有。
\n但请注意,如果我们git push当前 ( HEAD) 提交,则必须将所有父提交发送回我们的历史记录和它们的历史记录连接的点。这保持了“完整性”或“无洞”属性。所以你的代码在这里:
\n\nRun Code Online (Sandbox Code Playgroud)\nvariable1 = git rev-parse HEAD # Storing last commit hash into a variable\n# Pushing only one specific commit to (maybe) make it faster\ngit push $variable1:master\n
没有什么好处;您可以只是git push HEAD:master,或者如果您当前的分支名称位于 master您(发件人)的“一侧”,您可以只是git push master。
我上面提到存储库由两个数据库组成。到目前为止我所描述的过程都是关于更新对象数据库的。这是真正重要的一点,因为名称数据库主要是为了帮助弱小的人类:机器需要的只是原始哈希 ID。 Git不会像人类那样疯狂地试图区分 和 之间的区别720100ac47678fa31f0844a413f05bd0305d179f(720100ac47678fae1f0844a413f05bd0305d179f我在这里做了一个微小的改变:你能发现它吗?)。但我们也需要更新名称数据库,因此按照上述内容,发送的Git 将发送一个礼貌的请求或一个强制的命令(或者可能不止一个或两个,在空白处使用不同的名称):
(还有第三种,有条件的强制更新,发件人说我认为你的名字 _______ 包含 _______。如果是这样,请将其设置为 _______! 这是--force-with-lease选项,它只是提供了一种更安全的方法来执行命令。)
接收的 Git 会根据各种规则随意遵守或不遵守(托管服务器通常会在开箱即用的 Git 提供的超级简单的规则之上添加一堆控制规则)。发送者的工作只是提供名称和哈希 ID,以及礼貌的请求或强制的命令,并从接收的 Git 收回回复:“确定”或“拒绝”,以及任何可能的附带消息。来自托管服务器,例如,告诉用户他没有设置该名称的访问权限。然后,发送者将结果报告给运行的人员或进程,并更新实际成功的操作git push的任何远程跟踪名称。git push
因此,如果您有几件东西要发送,您可以将它们一起发送:
\ngit push origin master mybranch:theirbranch\nRun Code Online (Sandbox Code Playgroud)\n例如。master这会让您的发送 Git 收集您这边的OID mybranch,发送其 Git 所需的任何提交和支持对象,然后(礼貌地)要求他们将您的master和设置为您的 Git 为您的和theirbranch找到的 OID 。masteryourbranch
这是正常的过程。现在让我们看看怎样才能混淆它。
\n首先,一些(不是全部)现有的发送和接收进程有时会遍历其名称数据库中的每个名称。例如,对于具有数万个标签名称的存储库,这可能需要大量时间。这发生在“计算对象”阶段甚至开始之前。如果您有网络监视器或跟踪器,您将看到来自接收方的大量数据,列出它们的所有分支和标签名称以及相应的哈希 ID,即使发送方并不真正需要所有这些。这里有一些技术改进正在 Git 的 C 版本中进行,但它们已经进行了很长时间(我想现在已经好几年了),但还没有实现。如果这是一个问题,最简单的解决方案是删除大量名称,但这通常需要存档或至少重命名现有存储库并创建一个新存储库(因为某些哈希 ID 只能通过旧存储库找到)名称,您可能不想永远失去它们)。
\n更重要的是,回到我上面通常用粗体斜体字表示的那个词。我们可以制作一种 Git 克隆,Git 将其称为浅克隆,其中刻意违反通常的约束 \xe2\x80\x94,即图中没有“洞”\xe2\x80\x94。为了实现这一点,Git 将某些提交哈希 ID 写入文件中,表示假定该提交存在,但我们没有它,所以我们对此一无所知。
\n当接收的Git 很浅时,发送的Git 有问题,而当发送的Git 很浅时,发送的Git 也有问题。这意味着浅克隆可以作为一次性的事情,但对于正在进行的工作来说是一个坏主意,您将在其中运行git fetch(“从其他存储库获取更多对象”)或git push(“将对象发送到其他存储库”) 。特别是,正常的假设是,如果某人提交了b789abc其父级为 的提交a123456,那么他们不仅拥有了a123456每个较早的提交,因此到那时为止每个文件的每个版本都完全崩溃了。
不过,由于发送方在发送给接收方时使用的“拥有/想要”协议,深度二git push浅克隆比深度一克隆更适合完整(非浅层)克隆。“更深”克隆中的额外提交使发送者可以更好地了解接收者拥有的内容,即使发送者没有进行最佳压缩所需的一切。
当您首先拥有完整克隆时,可以获得最佳发送结果,但如果您要进行浅克隆,然后提交并推送,请至少从深度 2 克隆开始。CI 系统经常故意使用深度 1 的浅克隆,但通常有旋钮来调整深度,或创建完整(非浅)克隆。一些深度妥协(除了 2)可能最适合您的情况;没有实际测试很难说。
\n| 归档时间: |
|
| 查看次数: |
489 次 |
| 最近记录: |