如何重命名大量文件

时间:2010-06-05 16:51:45

标签: git command-line

我有一个包含这样的文件的目录

a.JPG
b.JPG
c.JPG

我想执行类似这样的事情

git mv a.JPG a.jpg

我尝试使用xargs和其他工具,但似乎没有任何工作。

5 个答案:

答案 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

批量重命名选项

Perl重命名

所需的操作很简单,可以使用一些shell脚本,但如果你需要做很多事情,你可以得到Perl 重命名实用程序(Jordan Lewis提到的那个)更复杂。您可以尝试使用rename from Debian's perl package,或者如果您想要使用CPAN,则可以安装File::Rename,其中包含重命名程序。

ksh bash zsh dash

下面使用的-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"

的zsh / zmv

对于 zmv git mv ,这个需要-f

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

现在你已经在Git的索引中重命名和更新了它们,你可以提交它们。

但是其他使用区分大小写的文件系统的Git用户是否能够检查出来?

git checkout 仅在案例重命名

之后

如果您的历史记录中有其他用户,他们可能仍会拥有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}'