2010-06-05 90 views
7

我有文件的目录这样如何重命名大量文件

a.JPG 
b.JPG 
c.JPG 

我想这样

git mv a.JPG a.jpg 

我使用xargs的和其他工具,但似乎没有试图进行一些上班。

+0

您在下面的评论中提到您使用OS X.这意味着您(可能)正在使用保留大小写的不区分大小写的文件系统。因此,重命名中的问题是:你的文件系统将目标名称视为与目标名称相同,并且由于Git通过文件系统工作,所以它也具有打开外壳的功能。 wbyoung下面的方法将通过将文件传递给可识别的中间名称来解决问题。 – Jeet 2010-06-06 05:29:29

+0

注意:git 2.0.1解决了这个问题:http://stackoverflow.com/a/24979063/6309 – VonC 2014-07-27 08:06:44

回答

7

解决方案的核心将是使用一种工具/方法来自动执行批量重命名。您可以使用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 

批量重命名选项

Perl的重命名

所需的操作是很简单的一个位shell脚本做,但你可以得到的Perl 重命名实用程序(一个乔丹·刘易斯提及)如果你需要做一些更复杂的事情。您可以尝试rename from Debian's perl package,或者如果您觉得需要使用CPAN,则可以安装File::Rename,其中包括重命名程序。

ksh的的bash的zsh破折号

下面使用不兼容POSIX的-ef。同样,虽然在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 

最后一节(MVgit的RMgit的添加)可能只有混帐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" 

或用混帐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 /&#xfeff; zmv

这其中需要-f两个zmv混帐MV

zsh -c 'autoload zmv && $0 [email protected]' zmv -fp git -o 'mv -f' '(*).JPG' '$1 x.jpg' 

现在,你把它们都改名和Git的索引更新,你可以提交他们。

但是会使用区分大小写的文件系统的其他Git用户能够检查它们吗?

git的结帐后为例,仅重命名

如果有你的历史的其他用户,他们可能会仍然有JPG文件,当他们最终结账(的后代),您与jpg提交文件。他们会发生什么?

无论发生什么事情,都不需要“重命名为temp,提交,重命名为final,commit”。git checkout在提交之间移动时不按顺序应用提交。它通过将来自HEAD的索引和工作树“合并”到新提交而起作用。这实际上意味着它在“HEAD”和索引/工作树之间发现的非冲突性变化时直接“跳转”到新提交。

在内部,Git视图重命名为删除和添加。我没有发现任何描述git结账关于删除和添加顺序的行为的文档,所以我查看了源代码。 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 

混帐怪上的文件似乎表明一个可能犯:Make unpack-tree update removed files before any updated files,这是首次在Git的发布1.5.6-RC0 (2008-06-18)。所以,尽管没有记录(?),但这种行为是专门为支持不区分大小写的文件系统而实现的。

谢谢,Linus!

1

可能重命名为* .somethingelse,然后重命名回* .JPG

2

使用标准的Linux rename(1) utility.一旦你重命名的文件,git的添加。

+0

使用“rename's/JPG/jpg /'* .JPG” GIT是内容寻址的,所以重命名文件被自动检测(只要内容保持不变)。 – tucuxi 2010-06-05 17:12:20

+0

我正在使用mac,所以我没有重命名。 – 2010-06-05 17:16:37

+0

如果您希望git将提交存储为重命名,而不是作为文件销毁和文件创建,则需要使用'git add -A .'。 -A意味着检查删除(如果被跟踪),不仅仅是文件创建。 – ivanxuu 2015-01-29 11:42:38

3

您是否可以更改文件的大小取决于您的文件系统。即使它在你的文件系统上工作,你也可能会导致其他人更新的问题。你最好重新命名它们,提交它们,然后重新命名它们。使用以下bash脚本将所有内容更改为* .tmp:

for i in *.JPG; do mv $i ${i%.JPG}.tmp; done 

然后将它们全部移入git中。你可以使用类似的命令,但我建议检查guess-renames这将有助于此举。

然后使用类似的过程将它们全部重命名为* .jpg。

+0

我认为我会推荐'* .JPG'作为'\'ls \'' – Dustin 2010-06-05 20:00:11

+0

好建议,我更新了使用* .JPG的答案。 – wbyoung 2010-06-05 20:07:33

+0

在提交之间移动时,Git不会重播每个中间变更集。移至新提交会更新当前HEAD /索引与目标提交之间已更改的文件。在多个阶段提交重命名将无助于那些不能直接处理'mv foo.JPG foo.jpg'的机器的用户(除非他们在移动到“on”提交时手动“访问”“.tmp”提交重命名的另一面“)。 * git不需要* guess-renames *,'git add -u && git add '将拾取“重命名”而不是'git mv'(或者,只需使用'git mv'而不是'mv')。 – 2010-06-05 20:10:16