Git:更改文件的一行以完整记录历史

48
当我开始我的Git仓库时,我将几个文件作为初始提交提交到它中。现在,许多提交后,我注意到我在这些文件中包含了一行信息,我不想发布(与其余代码不同)。所以我想删除/更改这一行,并保留其他代码。

在搜索周围的解决方案时,我发现可以通过在根提交之前插入一个空提交(在此处描述: Insert a commit before the root commit in Git?),对其进行rebase,然后通过修补修改旧的第一个提交。不幸的是,在rebase期间会出现许多严重的合并冲突(如在此处描述: git: solving conflicts caused by rebase

是否有不同的方法来解决我的问题,或者我必须逐个rebase和编辑所有冲突?

提前感谢 :)

如果你只是改变一行代码,合并冲突应该会很小。 - Clueless
可能是如何从Git的历史记录中删除敏感文件的重复问题。 - Karl Bielefeldt
@Clueless:当进行变基时,确实会出现冲突,这些是我过去解决过的冲突。 - tbolender
1
@Karl Bielefeldt:我在询问如何删除/替换这一行,而不是整个文件。 - tbolender
2
@TiBo - 现在已经太晚了,但这就是 rerere 的作用。 - Dan Ray
谢谢 :) 我现在知道了,将会一直保持它启用 :D - tbolender
5个回答

57

这是一个命令,可以从所有分支中删除文件历史记录中的错误行:

git filter-branch --tree-filter 'sed -i "/sensitive information/ d" filename' -- --all
这会检查每个修订版本,在其上运行sed命令,然后将该修订版本提交回去。
在这种情况下,sed命令匹配文件中包含模式sensitive information的任何行,并删除这些行。
注意:最好有备份,并首先单独尝试运行sed脚本以确保它按照您的意愿工作,因为在长时间的历史记录上运行可能需要相当长的时间。

有没有可能忽略sed错误(例如,当一个文件在一个版本中不存在时)? - tbolender
3
我不知道-q选项是否能实现那个功能。你可能需要将其包装在一个shell的if-then语句中,例如 if [ -e file ]; then sed...; fi - Karl Bielefeldt
4
如果你知道引入错误的提交,你可以运行git filter-branch --tree-filter 'sed -i "/sensitive information/ d" filename' <commit>..HEAD来删除文件中的敏感信息。 - exclsr
2
在Windows上,我一直收到“没有这样的文件或目录”错误。最终我发现,使用完整的文件路径作为文件名(例如:c:\filename.txt),并将其放在双引号中可以解决问题。 - Sevin7
7
以下是翻译的结果: 使用稍作修改的sed命令和参数,我在macOS上使用了以下命令:git filter-branch -f --tree-filter 'test -f yourfile.json && sed -i "" "s/oldText/newText/g" yourfile.json || echo "skipping file"' -- --all - Alon Amir
1
我不得不在filter-branch命令上使用--force,否则更改似乎没有应用。GitHub也推荐这样做。 - dimo414

8

我创建了一个命令,当文件不存在时不会出错:

 filename=./path/to/your/filename
 filter=your_regex_here

 git filter-branch --tree-filter 'test -f $filename && sed -i.bak "/$filter/d" $filename  || echo “skipping file“' -- --all

对我来说非常有效。提醒一下,以防其他人遇到同样的问题——不要删除结尾处的“跳过文件”回显。否则你可能会遇到“树过滤器失败”的错误;由于最后一个返回代码是非零的,git认为出现了故障。 - moltenform

6

我的答案综合了所有最好的东西。它仅替换给定的过滤字符串,而不是整行,并且如果在提交中找不到文件,则很好地跳过。虽然有很多转义引号,但其他答案的引号非常奇怪,对我无效。

 git filter-branch --tree-filter "test -f \"$filename\" && sed -i \"s/$filter//g\" \"$filename\" || echo \"skipping $filename\"" -- --all

2

2
我曾经找到了删除整个文件的解决方案,但是没有找到修改其中一行的方法。你能给一个例子吗? - tbolender

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接