我有一个包含这样的文件的目录
a.JPG
b.JPG
c.JPG
我想执行类似这样的事情
git mv a.JPG a.jpg
我尝试使用xargs和其他工具,但似乎没有任何工作。
答案 0 :(得分:9)
解决方案的核心是使用可自动进行批量重命名的工具/方法。您可以将 mv 与 git add 结合使用,也可以只使用 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
所需的操作很简单,可以使用一些shell脚本,但如果你需要做很多事情,你可以得到Perl 重命名实用程序(Jordan Lewis提到的那个)更复杂。您可以尝试使用rename from Debian's perl package,或者如果您想要使用CPAN,则可以安装File::Rename,其中包含重命名程序。
下面使用的-ef
与POSIX不兼容。同样,虽然在POSIX中指定了-e
,但它不是纯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"
或者使用 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"
对于 zmv 和 git mv ,这个需要-f
。
zsh -c 'autoload zmv && $0 $@' zmv -fp git -o 'mv -f' '(*).JPG' '$1 x.jpg'
现在你已经在Git的索引中重命名和更新了它们,你可以提交它们。
但是其他使用区分大小写的文件系统的Git用户是否能够检查出来?
如果您的历史记录中有其他用户,他们可能仍会拥有JPG
个文件,并且最终结帐(后代)您使用jpg
文件的提交。他们会怎么样?
无论发生什么,都不需要“重命名为temp,commit,rename to final,commit”。在提交之间移动时, git checkout 不会按顺序应用提交。它确实通过将HEAD中的索引和工作树“合并”到新提交来实现。这实际上意味着它可以直接“跳转”到新提交,同时拖动HEAD和索引/工作树之间发生的非冲突更改。
在内部,Git视图重命名为删除和添加。我没有找到任何描述 git checkout 关于删除和添加顺序的行为的文档,所以我查看了源代码。 git checkout 在任何更新/添加之前处理所有删除(cmd_checkout - &gt; switch_branches - &gt; merge_working_tree( - &gt; reset_tree) - &gt; unpack_trees - &gt; 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
文件中的 git blame 似乎表明可能的提交:Make unpack-tree update removed files before any updated files,它首先在Git 1.5.6-rc0(2008-06-18)中发布。因此,虽然没有文档(?),但这种行为是专门为支持不区分大小写的文件系统而实现的。
谢谢,Linus!
答案 1 :(得分:3)
您是否可以只更改文件的大小取决于您的文件系统。即使它适用于您的文件系统,也可能导致其他人更新出现问题。你最好重命名它们,提交它们,然后重命名它们。使用以下bash脚本将所有内容更改为* .tmp:
for i in *.JPG; do mv $i ${i%.JPG}.tmp; done
然后用git将它们全部移动。您可以使用类似的命令,但我建议您查看guess-renames,这将有助于移动。
然后使用类似的过程将它们全部重命名为* .jpg。
答案 2 :(得分:2)
使用标准Linux rename(1) utility.重命名文件后,git添加它们。
答案 3 :(得分:1)
可能将它们重命名为* .somethingelse,然后重命名为* .jpg
答案 4 :(得分:0)
要将文件扩展名从.JPG重命名为小写。这使用git mv
,以便保留git历史记录。
find . -name "*.JPG" | xargs -L1 bash -c 'git mv $0 ${0/JPG/jpg}'