使用 filter-branch --index-filter 总是失败并显示 "fatal: bad source" 的解决方法

10

所以,我正在尝试使用 git filter-branch --index-filter 重命名我的存储库中的文件夹,但我总是遇到“致命错误:坏源”的错误。

这个问题可以通过在测试存储库中使用一个文件而不是一个文件夹来轻松演示。

准备工作:

$ git init
$ echo whatever >> my_file.txt
$ git add .
$ git commit -m "initial"
$ echo whatever2 >> my_file2.txt
$ git add .
$ git commit -m "second"

现在,我正在尝试将my_file.txt更改为your_file.txt:
$ git filter-branch --index-filter 'git mv my_file.txt your_file.txt' HEAD

但它不起作用:
Rewrite dac9a2023bdf9dd0159fab46213d9e1342ae9f75 (1/2)fatal: bad source, source=my_file.txt, destination=your_file.txt
index filter failed: git mv my_file.txt your_file.txt

然而,同样执行正常的git mv命令却没有问题:
$ git mv my_file.txt your_file.txt
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    my_file.txt -> your_file.txt
#

我确定,我在这里缺少了一些重要的东西 - 但是它是什么?


1
我猜在那个特定的提交中,“my_file.txt”不存在,这会导致“git mv”失败 - 你可以尝试使用“git mv -k -f”。此外,“git mv”不适用于“--index-filter”,因为它影响的不仅仅是索引 - 应该改用“--tree-filter”。 - twalberg
@twalberg:你的猜测是不正确的。在 --index-filter 中,git rm [...] my_file.txt 可以正常工作... - Daniel Hilgarth
@twalberg:但我猜你评论的第二部分就是“答案”:它根本不起作用。 - Daniel Hilgarth
“--index-filter” 不会为每个提交检出树,这使其效率更高,但由于它基本上不会影响工作目录,我认为 git mv 不能始终按照您的期望进行。它可能会“起作用”,但可能会给您带来意外的结果... - twalberg
@twalberg:感谢您的评论。很有道理,我没有真正考虑过git mv的作用。所有关于git rm的示例都始终使用--cached选项仅在索引上工作。不过,我在手册页面上找到了答案。 - Daniel Hilgarth
2个回答

15
正如twalberg在他的答案中所指出的,git mv不仅访问索引,还访问磁盘。这可能是它无法工作的原因。
我不想使用缓慢的--tree-filter,所以尝试更改来自git filter-branch手册页面的示例,该示例显示如何将完整的存储库移动到子文件夹中。
结果就是这样 - 它实际上可以工作;-)
git filter-branch --index-filter '
git ls-files -s | \
sed "s-\(\t\"*\)my_file.txt-\1your_file.txt-" | \
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD

2
有关上述脚本的更详细解释,请参阅此博客文章:使用Git重命名过去 - user456814
3
谢谢您的留言。我已经将您的答复用于帮助另一个人解决重命名问题,并提供了详细的说明。感谢您的提示 ;) - user456814

4

git mv--index-filter 子句中并不是很合适。由于 --index-filter 不会检出要重写到工作目录中的每个提交,而 git mv 操作的是工作目录(除了索引),在 --index-filter 中使用 git mv 将不能达到预期的结果。请改用 --tree-filter。 (可能仍然可以通过使用 git update-index--index-filter 中完成此操作,但我头脑中没有这个选项)。


谢谢你的回答。我正在使用update-index。老实说,我不太清楚它是如何工作的,我只是从man-page中取了样本,并调整了传递给sed的正则表达式 :) - Daniel Hilgarth
1
“--tree-filter” 对我来说并不是一个真正的选择,因为我的真实场景是要修复同一目录的不同大小写。 - Daniel Hilgarth
哎呀,既然这样,也许你应该考虑在 Windows 上完成工作(呃,我竟然说出了这种话...),因为在那里,不同的大小写不会在你需要检查它们时(使用“--tree-filter”或其他方式)造成太多麻烦。 - twalberg
我一直在使用Windows系统。这就是为什么--tree-filter不是一个好主意的原因。我必须执行mv CASE case_tmp && mv case_tmp case,其中CASE是错误的大小写,而case是正确的大小写。 - Daniel Hilgarth
1
我对我找到的update-index解决方案感到非常满意。它快速而且无痛。 - Daniel Hilgarth

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