该解决方案的核心是使用一种工具/方法来自动执行批量重命名。您可以使用mv结合git add要不就git mv。在任何一种情况下,如果您使用不区分大小写的文件系统,则可能需要采取额外的步骤。因此,在我们处理批量重命名之前,讨论一下大小写的处理方式可能会很有用。
区分大小写
Some systems (or system+filesystem combinations—like the default variant of the HFS+ filesystem on Mac OS X*) are case preserving, but case insensitive. On such systems, you may need to be careful when making renames that involve only changing the case of a name. The usual workaround is to use a temporary name that differs by more than just case as a “bridge” between the two names that differ by case alone (e.g. mv foo.JPG tmp && mv tmp foo.jpg
).
* It is possible to use case sensitive file systems on Mac OS X (including a case
sensitive variant of HFS+).
从这里开始,我将假设一个不区分大小写的文件系统。
The mvMac OS X 上的命令可以一步处理仅大小写更改的重命名。它会给出一个“覆盖?”如果运行时提示-i
选项,如果给定,它将跳过重命名-n
选项。它只有通过类 Unix 系统许多部分的“足够的绳子来吊死自己”的默认操作才能成功。
The git mv指挥部对这种情况有点偏执。除非给出,否则它拒绝操作(“目的地存在”错误)-f
/--force
option.
# this will succeed, though it may fail/prompt if mv is aliased to use -n/-i
mv foo.JPG foo.jpg
# this will succeed
mv -f bar.JPG bar.jpg
# this will succeed but give a warning
git mv -f quux.JPG quux.jpg
批量重命名选项
Perl重命名
所需的操作非常简单,只需编写一些 shell 脚本即可完成,但您可以获得 Perlrename如果你需要做一些更复杂的事情,那么实用程序(乔丹·刘易斯提到的那个)。你可以尝试rename来自 Debian 的perl package http://git.debian.org/?p=perl/perl.git;a=blob_plain;f=debian/rename;hb=HEAD,或者如果您愿意使用 CPAN,您可以安装文件::重命名 http://search.cpan.org/dist/File-Rename/,其中包括rename程序。
ksh, bash, zsh, dash
The -ef
下面使用的不兼容 POSIX。同样,虽然-e
是在 POSIX 中指定的,它不与纯 Bourne 兼容。但两者都得到了广泛的支持。
for f in *.JPG; do
ff="${f%.JPG}.jpg"
test -e "$f" || continue # possible when not using nullglob
test "$f" != "$ff" || continue # possible when using nocaseglob
if test -e "$ff" &&
! test "$f" -ef "$ff"; then # possible on a case sensitive filesystem
echo "skipping <$f>: destination <$ff> exists and is distinct" 1>&2
continue
fi
# "mv" with "git rm" and "git add"
mv -f "$f" "$ff" &&
git rm --cached "$f" &&
git add "$ff"
done
最后一节(mv, git rm, git add)可以替换为git mv:
# "git mv"
git mv -f "$f" "$ff"
如果您非常担心重命名在不区分大小写的系统上可能会失败,那么您可以使用临时名称:
# temp-based "mv" with "git rm" and "git add"
t="$ff.tmp"; while test -e "$t"; do t="$t.tmp"; done
mv -n "$f" "$t" &&
mv -n "$t" "$ff" &&
git rm --cached "$f" &&
git add "$ff"
Or with git mv:
# temp-based "git mv"
t="$ff.tmp"; while test -e "$t"; do t="$t.tmp"; done
git mv "$f" "$t" &&
git mv "$t" "$ff"
zsh/zmv
这个需要-f
对彼此而言zmv and git mv.
zsh -c 'autoload zmv && $0 $@' zmv -fp git -o 'mv -f' '(*).JPG' '$1 x.jpg'
现在您已将它们全部重命名并更新到 Git 的索引中,您可以提交它们了。
但是使用区分大小写的文件系统的其他 Git 用户是否能够查看它们?
git 结账仅大小写重命名后
如果您的历史记录中有其他用户,他们可能仍然拥有JPG
文件,以及当它们最终签出您的提交(的后代)时jpg
文件。他们会发生什么?
无论发生什么,都不需要“重命名为 temp,提交,重命名为 Final,提交”。git 结账在提交之间移动时不会按顺序应用提交。它实际上是通过将索引和工作树从 HEAD“合并”到新的提交来工作的。这实际上意味着它直接“跳转”到新提交,同时拖动 HEAD 和索引/工作树之间发现的非冲突更改。
在内部,Git 将重命名视为删除和添加。我没有找到任何描述行为的文档git 结账关于删除和添加的顺序,所以我看了源码。git 结账在任何更新/添加之前处理所有删除(cmd_checkout -> switch_branches -> merge_working_tree (-> reset_tree) -> unpack_trees ->检查更新 http://git.kernel.org/?p=git/git.git;a=blob;f=unpack-trees.c;h=c29a9e067ff362063d6626e8e4d1e4466d63b8af;hb=HEAD#l76).
您可以在重命名提交后立即进行测试:
git checkout HEAD~ # note: detached HEAD
# verify that the original names are back in place
git checkout - # back to your branch
# verify that the new names are in place again
The git 责备文件上似乎表明可能的提交:使 unpack-tree 在任何更新的文件之前更新删除的文件 http://git.kernel.org/?p=git/git.git;a=commit;h=1fa6ead492c81bffdbe336373e5b162d3b5ac6d3,首次发布于 Git 1.5.6-rc0 (2008-06-18)。因此,虽然没有记录(?),但这种行为是专门为了支持不区分大小写的文件系统而实现的。
谢谢,莱纳斯!