gpt4 book ai didi

git - Git Filter-Branch All命令

转载 作者:行者123 更新时间:2023-12-01 08:22:33 27 4
gpt4 key购买 nike

此刻,我当前正在使用命令“git filter-branch --subdirectory-filter MY_DIRECTORY---all”从此git repo的所有30个分支中获取某个目录。在执行此filter branch命令之前,请确保签出每个分支以确保--all命令正常运行。

我的问题是,在执行git-filter all之前我是否必须检出每个分支?还是git-filter all仍然可以工作而不必检出我正在查看的所有30个分支?目前,每个分支几乎都为3GB,因此整个结帐过程将花费很长时间。任何澄清将是巨大的!

最佳答案

开始之前

在深入探讨答案本身之前,请注意,如果您想为每个远程跟踪名称都拥有一个本地分支名称,则可以简单地创建该本地分支名称,而无需使用git checkout:

git branch -t develop origin/develop
git branch -t feature/X origin/feature/X
git branch -t foo origin/foo

等等。这是 git checkout的子集,并且非常快,因为创建新的分支名称仅意味着写入一个文件。

(如果愿意,可以使用此技术并在此处停止,但是此答案的其余部分应该非常有用。)

简短的回答

简短的答案是您不必签出(或创建新的)分支名称。但是,您将需要更好地理解Git(包括此特定的 git filter-branch操作)。

让我们从这里开始: --all在这里表示所有引用。但是,什么是“参考”呢?

好吧,任何分支名称都是参考。但是任何标签名称也是如此。 refs/stash使用的特殊名称 git stash是参考。远程跟踪名称是参考。注意refs(来自 git notes)是引用。有关此术语和其他Git术语的更多信息,请参见 the gitglossary(请注意,此特定条目位于 ref之下,而不是 reference之下)。

当您首次使用 git clone克隆存储库时,您是在告诉自己的Git:在我给您的URL上创建一些现有存储库的新的独立副本,这样我就可以做自己的工作,然后共享或不共享它。我请求。但是它们的存储库(无论位于“URL”中的URL)都有其自己的分支名称。他们有自己的 master,但不一定总是与您的 master相同。因此,您的Git重命名了他们的名字:他们的 master成为您的 origin/master,依此类推。这些远程跟踪名称是参考。
git clone完成将所有提交复制到您的存储库,并将所有名称重命名为远程跟踪名称之后, git clone的最后一步是签出一个分支。但是您还没有任何分支机构。这是 git checkout做的一个特殊技巧:如果您要求Git通过名称检出不存在的分支,则Git会遍历所有远程跟踪名称。如果其中之一匹配,Git将创建一个本地分支名称(一个新引用),该名称指向与此远程跟踪名称相同的提交。

因此,您的存储库具有一系列提交,所有这些提交都以向后的方式彼此链接:
first  <--next ... <--almost-last  <--last

(如果它们都是线性的,那么几乎永远不会),我们可以将其绘制为:
A--B--...--H--I

每个大写字母代表一个提交。一组带有一些“分支性”(branchiness?)的提交可能看起来像:
     C--D
/
A--B
\
E--F--G

如果存在合并提交,这些合并提交将指向先前的两个提交而不是仅一个,那么它将变得更加复杂。

我们在这里最关心的名称(特别是分支名称和远程跟踪名称)是Git查找最后一次提交的一种方式:
...--H--I   <-- origin/master

据说名称 origin/master指向commit I。当您的Git创建自己的 master时,您的 master现在也指向 I:
...--H--I   <-- master, origin/master

如果您在 master上创建自己的新提交,则会发生以下情况:
...--H--I   <-- origin/master
\
J <-- master

Git为新的提交组成了一个新的ID,这是一个看上去很随机的丑陋的哈希ID,但在这里我们仅将其称为 J,然后将名称 master更改为指向此新的提交。

如果您运行 git fetch并从 origin引入新的提交,并且他们已经更新了其母版,则您将获得:
...--H--I--K   <-- origin/master
\
J <-- master

现在您的 master和他们的 origin/master有所不同。

这些名称 masterorigin/master具有使它们的提交可访问的重要作用。也就是说,通过跟随每个名称中的箭头,Git可以找到commit JK。然后,使用向后箭头(确实是提交的父提交哈希ID)从 JI或从 KI,Git可以找到提交 I。使用 I本身的向后箭头,Git可以找到 H,依此类推,一直返回到第一个提交,该操作停止。

所有无法到达的提交(在所有这些开始点(结束点)开始并向后走都找不到的提交)将在某个时刻被删除,因此它们实际上不存在。对于遍历图形的大多数Git命令而言,情况也是如此。 (有一些特殊用途的恢复技巧,可以让您将删除的提交恢复30天,但是filter-branch不兑现这些 promise 。)

这对于分支过滤意味着什么
git filter-branch的工作是复制提交。它遍历图形,使用起点(终点?)来查找所有可到达的提交。它将其哈希ID保存在一个临时文件中。然后,朝相反的方向移动(即,按时间向前移动而不是Git通常向后移动),它将提取每个提交。也就是说,它会将其检出,以便该快照中的所有文件都可用。然后filter-branch应用过滤器,然后从生成的文件中进行新提交。因此,如果您的过滤器进行了简单的更改,则结果是原始图形的副本:
A--B--C------G--H   <-- master, origin/master
\ /
D--E--F

变成:
A'-B'-C'-----G'-H'  <-- master, origin/master
\ /
D'-E'-F'

原始提交会怎样?好的,它们仍然存在:filter-branch对找到它们的名称的作用是使用其内部全名前面的 refs/original/重命名它们:
A--B--C------G--H   <-- refs/original/refs/heads/master, refs/original/refs/remotes/origin/master
\ /
D--E--F

过滤器分支具有如此多的过滤器选项的原因之一是,此过程非常缓慢。将每个文件提取到一个临时目录需要很长时间。因此,某些过滤器可以完全不提取文件而工作,这要快得多(很多!)。

另一个原因是有时我们不想复制每个提交,而只想复制一些符合某些条件的提交。 --subdirectory-filter就是这种情况:只有在更改涉及涉及子目录的文件(相对于其父提交)时,它才会复制提交。因此,在某些情况下,它可以跳过提取大量提交。当然,子目录过滤器在提取并重新提交的过程中还会重命名文件,以删除子目录路径。结果是将较大的提交图复制到较新的较小的提交图:
A--B--C------G--H   <-- master
\ /
D--E--F

可能变成:
B'--G'--H'   <-- master
\ /
E'

保留的 refs/original/refs/heads/master仍将指向commit H,而重写的 refs/heads/master将指向复制的commit H'。请注意,新图中的第一个提交是 B',而不是 A',因为 A'没有相关的子目录。

这里还有一个非常重要的附带问题:筛选器分支在完成所有提交复制后会更新哪些参考?答案在文档中:

该命令只会重写在
命令行(例如,如果您通过a..b,则只会重写b)。

由于您使用的是 --all,这将重写所有 origin/*远程跟踪名称。 ( --all在这里是对每个引用的肯定提及。标签还有一些额外的技巧:如果要重写标签,请添加 --tag-name-filter cat作为过滤器。)

摘要

进行分支过滤操作后,您将拥有一系列 refs/original/*名称,这些名称指向原始(预过滤)提交,并从其原始全名重命名。您将拥有一系列新的更新引用,包括所有分支名称( refs/heads/*)和远程跟踪名称( refs/remotes/*),这些名称指向复制的任何提交的最后一个。

新的存储库将大于原始存储库,因为它包含原始存储库以及复制的提交。请参见 清单,以缩小结尾处the git filter-branch documentation的存储库部分。但是请注意,如果您使用 git clone复制过滤的存储库,则仅复制您的分支名称,而不是您的远程跟踪名称,因此,在这一点上,如果您尚未为每个远程跟踪名称创建分支,则应执行现在。

另外,您可以在删除所有 refs/original/命名空间名称之后,将复制的存储库保留在适当的位置。然后,您可以 git checkout develop基于(过滤的) refs/heads/develop创建自己的 refs/remotes/origin/develop,依此类推。您要做的就是创建新名称-提交本身就是Git真正关心的,并由重写的远程跟踪名称引用它们-然后检查该特定提交,以使其位于索引和工作树中。 (我们在开头显示的 git branch -t命令创建了名称,而没有将提交复制到index-and-work-tree。)

关于git - Git Filter-Branch All命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50968652/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com