使用git filter-branch进行特定的提交

时间:2018-08-09 16:37:52

标签: git github

我正在尝试使用git filter-branch功能来删除最近更新并提交的文件。我尝试运行以下命令:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- 6f7fda9..HEAD

但是,这只会从master分支中删除文件,而我希望将其从所有分支中删除。

6f7fda9HEAD的提交开始,我要删除文件。我执行的命令有误吗?

3 个答案:

答案 0 :(得分:0)

git filter-branch -- --all在所有分支上运行筛选器。所以:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --all

答案 1 :(得分:0)

  

我要从所有分支中删除[文件]

重要的是要意识到分支几乎(但不是很)无关紧要。重要的是 commits

您实际上不能更改任何现有的提交,并且Git不会尝试。 git filter-branch的作用是复制提交。也就是说,对于每个要过滤的提交,Git都会将其提取到一个临时工作区中,应用您的过滤器,然后从结果中进行一个 new 提交。

如果新提交与原始提交逐位相同,则会重新使用存储库数据库中的实际基础对象。如果不是(目的是导致结果为“ not”),则将保留原始提交,而新副本将获得新的,不同的哈希ID。如果我们使用大写字母来表示提交哈希ID,并记住每个提交都存储其 parent 提交的哈希ID,则可以这样绘制原始文档:

... <-F <-G <-H <-I   <-- master

类似于master的分支 name 记住 last 提交的哈希ID。该提交会记住其父级的哈希ID,并记住另一个父级的另一个哈希ID,依此类推:master让Git find 提交I,从而找到提交{{ 1}},找到提交H,依此类推。

使用G,我们告诉Git:提取提交git filter-branch,并可能对其进行一些更改,然后重新提交。如果F中没有任何变化,我们坚持使用实际的哈希ID。然后,我们Git提取了提交F并进行了一些更改。这次,也许我们删除了一个敏感文件。因此,我们进行了一个类似于G的新提交,但又有所不同:它获得了一个新的,不同的哈希ID,我们可以将其称为G。提交G'仍以提交G'作为其父对象:

F

然后我们提取...--F--G--H--I <-- master \ G' 并应用过滤器。即使没有其他更改,我们也需要新的提交来指向H,因此filter-branch确保了这种情况的发生,因此我们得到了指向G'的提交H' 。我们重复G',结果是:

I

最后一步是让...--F--G--H--I <-- master \ G'-H'-I' 重写每个分支名称。现在,名称git filter-branch必须指向提交master(具有新的和不同的哈希值),而不是陈旧的老臭小I'

I在处理结束时重写的名称是您在命令行上肯定标识的所有名称。这部分有点棘手:git filter-branch需要,作为其一个或某些自变量,是适合git filter-branch的字符串。这些可以是诸如git rev-list之类的正引用,也可以是诸如master^develop之类的负引用

一个否定引用告诉Git:不要为这些提交打扰。如果您使用^6f7fda9跳过提交^6f7fda9以及提交之前(按图形方式)的任何内容,则6f7fda9将不必花费任何计算机时间来处理该提交。

表达式git filter-branch6f7fda9..HEAD的缩写,而^6f7fda9 HEAD表示当前分支名称。因此,这是一个分支名称(例如HEAD正引用,而哈希ID是一个负引用。

您可以使用master为分支名称命名 all 。您可以使用--branches来命名所有引用(包括不是分支名称的名称)。 Filter-branch只会重写肯定引用,但会重写全部 。请注意这一点,因为它可以重写--all

当您要做时,重写任何分支,标记或其他名称,这些分支,标签或其他名称引用了某些包含您的文件的提交想要拥有,您将得到类似的东西:

refs/stash

如果您不要重写某些名称,该名称指向 tip2 [abandoned] / ...--good--bad--...--tip [abandoned] \ copied--...--tip' <-- branch1 \ tip2' <-- branch2 向下(向右)的任何提交,则这些名称仍将指向“错误”的提交,有您要删除的文件。 (请记住,在我在StackOverflow上执行的这些特定图形绘图中,较早的/父提交位于左侧,稍后的/子提交位于右侧。)

答案 2 :(得分:0)

您的要求是矛盾的。具体地

  

我希望将其从所有分支中删除。

  

从将6f7fda9提交到HEAD开始,我希望删除文件。

需要核对。我怀疑这归因于对提交范围的不正确理解-只是git中的某种事情。

考虑此提交图:

x -- 6f7fda9 -- A -- B -- C -- F <--(master)
                 \                        ^(HEAD)
                  D -- E <--(branch)

所以HEADmaster,而F在;并且有一个分支(显然)是从A创建的(在6f7fda9之后但在HEAD之前)。

现在的问题是,给定这张图,6f7fda9..HEAD是什么意思?不幸的是,答案并不是很多人凭直觉想到的。

6f7fda9..HEADHEAD ^6f7fda9的缩写-意思是“一切都可以从HEAD到达,但 不能从6f7fda9到达”。 “可达到”是指“提交本身,以及通过遵循父指针找到的所有提交”。因此,在这种情况下,它意味着ABCF;但不是x6f7fda9(因为它们可以从6f7fda9到达),也不是DE(因为它们不能从{ {1}}。

有几种方法可以使HEAD处理所有分支。例如,您可以

filter-branch

但这将包括所有引用(不只是所有分支);如果有问题

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --all

另一个警告-如果在重写git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- --branches 之前明确想要提交,则需要包括一个或多个否定提交引用。但是,假设您要做打算包含6f7fda9本身,那么您将排除其父项(而不是其自身)。

6f7fda9

如果git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- ^6f7fda9^ --branches 是合并,则必须为其每个父项列出否定提交引用。