我有一个包含这样文件的目录
a.JPG
b.JPG
c.JPG
Run Code Online (Sandbox Code Playgroud)
我想做这样的事情
git mv a.JPG a.jpg
Run Code Online (Sandbox Code Playgroud)
我尝试使用xargs和其他工具,但似乎没有任何工作.
解决方案的核心是使用一种工具/方法来自动化批量重命名.您可以使用MV结合git的添加,或只是git的MV.在任何一种情况下,如果使用不区分大小写的文件系统,则可能需要执行额外的步骤.因此,在我们解决批量重命名之前,讨论如何处理案例可能是有用的.
某些系统(或系统+文件系统组合 - 如Mac OS X *上的HFS +文件系统的默认变体)是大小写保留,但不区分大小写.在这样的系统上,在进行仅涉及更改名称大小写的重命名时可能需要小心.通常的解决方法是使用一个临时名称,该名称的不同之处不仅仅是作为两个名称之间的"桥梁",这些名称因情况而异(例如mv foo.JPG tmp && mv tmp foo.jpg).
*可以在Mac OS X上使用区分大小写的文件系统(包括HFS +的区分大小写的变体).
从这里开始,我将假设一个不区分大小写的文件系统.
Mac OS X上的mv命令只需一步即可处理仅更改大小写的命令.如果使用该-i选项运行,它将给出"覆盖?"提示,如果给出选项,它将跳过重命名-n.它只是通过"足够的绳索挂起你自己"继承了类Unix系统的许多部分的默认操作.
关于这种情况,git mv命令有点偏执.除非给出-f/ --force选项,否则它拒绝操作("目标存在"错误).
# 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
Run Code Online (Sandbox Code Playgroud)
所需的操作很简单,可以使用一些shell脚本,但如果你需要做一些更复杂的事情,你可以得到Perl 重命名工具(Jordan Lewis提到的那个).您可以尝试从Debian的perl包重命名,或者如果您觉得使用CPAN,可以安装File :: Rename,其中包括重命名程序.
以下-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
Run Code Online (Sandbox Code Playgroud)
最后一节(mv,git rm,git add)可以用git mv替换:
# "git mv"
git mv -f "$f" "$ff"
Run Code Online (Sandbox Code Playgroud)
如果您非常关心在不区分大小写的系统上重命名可能会失败的方式,那么您可以使用临时名称:
# 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"
Run Code Online (Sandbox Code Playgroud)
或者使用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"
Run Code Online (Sandbox Code Playgroud)
这其中需要-f两个zmv和git的MV.
zsh -c 'autoload zmv && $0 $@' zmv -fp git -o 'mv -f' '(*).JPG' '$1 x.jpg'
Run Code Online (Sandbox Code Playgroud)
现在你已经在Git的索引中重命名和更新了它们,你可以提交它们.
但是其他使用区分大小写的文件系统的Git用户是否能够检查出来?
如果您的历史记录中有其他用户,他们可能仍会拥有这些JPG文件以及最终签出(后代)您对jpg文件的提交.他们会怎么样?
无论发生什么,都不需要"重命名为temp,commit,rename to final,commit".在提交之间移动时,git checkout不会按顺序应用提交.它确实通过将HEAD中的索引和工作树"合并"到新提交来实现.这实际上意味着它在拖拽HEAD和索引/工作树之间发现的非冲突更改时直接"跳转"到新提交.
在内部,Git视图重命名为删除和添加.我没有找到任何描述git checkout关于删除和添加顺序的行为的文档,所以我查看了源代码.git checkout在任何更新/添加之前处理所有删除(cmd_checkout - > switch_branches - > merge_working_tree( - > reset_tree) - > unpack_trees - > check_updates).
您可以在重命名提交后立即对此进行测试:
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
Run Code Online (Sandbox Code Playgroud)
该文件的git责备似乎表明可能的提交:在任何更新的文件之前将unpack-tree更新删除文件,这是在Git 1.5.6-rc0(2008-06-18)中首次发布的.因此,虽然没有文档(?),但这种行为是专门为支持不区分大小写的文件系统而实现的.
谢谢,Linus!
是否可以更改文件的大小写取决于您的文件系统。即使它可以在您的文件系统上运行,也可能会导致其他人更新出现问题。您最好重命名它们,提交它们,然后将它们重命名回来。使用以下 bash 脚本将所有内容更改为 *.tmp:
for i in *.JPG; do mv $i ${i%.JPG}.tmp; done
Run Code Online (Sandbox Code Playgroud)
然后将它们全部移动到git中。您可以使用类似的命令,但我建议您检查一下猜测重命名,这将有助于移动。
然后使用类似的过程将它们全部重命名回 *.jpg。
| 归档时间: |
|
| 查看次数: |
6157 次 |
| 最近记录: |