我正在尝试使用git filter-branch
功能来删除最近更新并提交的文件。我尝试运行以下命令:
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch myfile' --prune-empty --tag-name-filter cat -- 6f7fda9..HEAD
但是,这只会从master分支中删除文件,而我希望将其从所有分支中删除。
从6f7fda9
到HEAD
的提交开始,我要删除文件。我执行的命令有误吗?
答案 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-branch
是6f7fda9..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)
所以HEAD
在master
,而F
在;并且有一个分支(显然)是从A
创建的(在6f7fda9
之后但在HEAD
之前)。
现在的问题是,给定这张图,6f7fda9..HEAD
是什么意思?不幸的是,答案并不是很多人凭直觉想到的。
6f7fda9..HEAD
是HEAD ^6f7fda9
的缩写-意思是“一切都可以从HEAD
到达,但 不能从6f7fda9
到达”。 “可达到”是指“提交本身,以及通过遵循父指针找到的所有提交”。因此,在这种情况下,它意味着A
,B
,C
和F
;但不是x
或6f7fda9
(因为它们可以从6f7fda9
到达),也不是D
或E
(因为它们不能从{ {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
是合并,则必须为其每个父项列出否定提交引用。