git 重命名许多文件和文件夹
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9984722/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
git rename many files and folders
提问by Jonathan
I am trying to rename many files in my application and need to be able to do a rename in all subdirectories from the app root through git (i.e. git mv %filenamematch% %replacement%) that only replaces the matching text. I'm no good with bash scripting though.
我正在尝试重命名我的应用程序中的许多文件,并且需要能够通过仅替换匹配文本的 git(即 git mv %filenamematch% %replacement%)在应用程序根目录中的所有子目录中进行重命名。不过我不擅长 bash 脚本。
update: would be good it if also renamed directories that match as well!
更新:如果也重命名匹配的目录就好了!
回答by Jonathan Camenisch
This should do the trick:
这应该可以解决问题:
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*//' | uniq); git mv $file $(echo $file | sed -e 's/%filenamematch%/%replacement%/')
To follow what this is doing, you'll need to understand piping with "|" and command substitution with "$(...)". These powerful shell constructs allow us to combine several commands to get the result we need. See Pipelinesand Command Substitution.
要了解它的作用,您需要了解带“|”的管道 并用“$(...)”替换命令。这些强大的 shell 构造允许我们组合多个命令来获得我们需要的结果。请参阅管道和命令替换。
Here's what's going on in this one-liner:
这是单线中发生的事情:
git ls-files
: This produces a list of files in the Git repository. It's similar to what you could get fromls
, except it only outputs Git project files. Starting from this list ensures that nothing in your .git/ directory gets touched.| grep %filenamematch%
: We take the list fromgit ls-files
and pipe it through grep to filter it down to only the file names containing the word or pattern we're looking for.| sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
: We pipe these matches through sed(the stream editor), executing (-e) sed's s (substitute) command to chop off any / and subsequent characters after our matching directory (if it happens to be one).| uniq
: In cases where the match is a directory, now that we've chopped off contained directories and files, there could be many matching lines. We use uniq to make them all into one line.for file in ...
: The shell's "for" commandwill iterate through all the items (file names) in the list. Each filename in turn, it assigns to the variable "$file" and then executes the command after the semicolon (;).sed -e 's/%filenamematch%/%replacement%/'
: We use echoto pipe each filename through sed, using it's substitute command again--this time to perform our pattern replacement on the filename.git mv
: We use this git command to mv the existing file ($file) to the new filename (the one altered by sed).
git ls-files
:这会生成 Git 存储库中的文件列表。它类似于您可以从 中获得的内容ls
,只是它只输出 Git 项目文件。从此列表开始可确保 .git/ 目录中的任何内容都不会被触及。| grep %filenamematch%
:我们从列表中取出git ls-files
并通过 grep 将其过滤为仅包含我们正在查找的单词或模式的文件名。| sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
:我们通过sed(流编辑器)对这些匹配进行管道传输,执行 (-e) sed 的 s(替代)命令以在我们的匹配目录(如果恰好是一个)之后切掉任何 / 和后续字符。| uniq
: 在匹配是目录的情况下,既然我们已经切断了包含的目录和文件,可能会有很多匹配的行。我们使用 uniq 将它们全部合并为一行。for file in ...
:shell 的“for”命令将遍历列表中的所有项目(文件名)。每个文件名依次分配给变量“$file”,然后在分号 (;) 后执行命令。sed -e 's/%filenamematch%/%replacement%/'
:我们使用echo将每个文件名通过 sed 进行管道传输,再次使用它的替换命令——这次对文件名执行我们的模式替换。git mv
: 我们使用这个 git 命令将现有文件 ($file) 转换为新文件名(由 sed 更改的文件名)。
One way to understand this better would be to observe each of these steps in isolation. To do that, run the commands below in your shell, and observe the output. All of these are non-destructive, only producing lists for your observation:
更好地理解这一点的一种方法是单独观察每个步骤。为此,请在您的 shell 中运行以下命令,并观察输出。所有这些都是非破坏性的,只为您的观察生成列表:
git ls-files
git ls-files | grep %filenamematch%
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file | sed -e 's/%filenamematch%/%replacement%/'
git ls-files
git ls-files | grep %filenamematch%
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/'
git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file
for file in $(git ls-files | grep %filenamematch% | sed -e 's/\(%filenamematch%[^/]*\).*/\1/' | uniq); echo $file | sed -e 's/%filenamematch%/%replacement%/'
回答by Flimm
Rename the files with a regular expression using the command rename
:
使用以下命令使用正则表达式重命名文件rename
:
rename 's/old/new/' *
Then register the changes with Git by adding the new files and deleting the old ones:
然后通过添加新文件并删除旧文件向 Git 注册更改:
git add .
git ls-files -z --deleted | xargs -0 git rm
In newer versions of Git you can use the --all
flag instead:
在较新版本的 Git 中,您可以改用该--all
标志:
git add --all .
回答by GoZoner
Late to the party but, this should work in BASH (for files and directories, but I'd be careful regarding directories):
迟到了,但这应该在 BASH 中工作(对于文件和目录,但我会小心目录):
find . -name '*foo*' -exec bash -c 'file={}; git mv $file ${file/foo/bar}' \;
回答by Gregg Lind
git mv
inside a shell loop?
git mv
在外壳循环内?
(Assuming you are on a platform with a reasonable shell!)
(假设您在一个具有合理外壳的平台上!)
Building on the answer by @jonathan-camenish:
# things between backticks are 'subshell' commands. I like the $() spelling over ``
# git ls-files -> lists the files tracked by git, one per line
# | grep somestring -> pipes (i.e., "|") that list through a filter
# '|' connects the output of one command to the input of the next
# leading to: for file in some_filtered_list
# git mv f1 f2 -> renames the file, and informs git of the move.
# here 'f2' is constructed as the result of a subshell command
# based on the sed command you listed earlier.
for file in `git ls-files | grep filenamematch`; do git mv $file `echo $file | sed -e 's/%filenamematch%/%replacement%/'`; done
Here is a longer example (in bash or similar)
这是一个更长的例子(在 bash 或类似的)
mkdir blah; cd blah;
touch old_{f1,f2,f3,f4} same_{f1,f2,f3}
git init && git add old_* same_* && git commit -m "first commit"
for file in $(git ls-files | grep old); do git mv $file $(echo $file | sed -e 's/old/new/'); done
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# renamed: old_f1 -> new_f1
# renamed: old_f2 -> new_f2
# renamed: old_f3 -> new_f3
# renamed: old_f4 -> new_f4
#
回答by Alex W
This worked well for my use case:
这对我的用例很有效:
ls folder*/*.css | while read line; do git mv -- $line ${line%.css}.scss; done;
Explanation:
解释:
ls folder*/*.css
- Usesls
to get a list of all directories with CSS files that match the glob pattern. (Directories starting withfolder
and containing files with.css
extensions)while read line
- Reading in the resulting output of thels
command line-by-linedo git mv -- $line ${line%.css}.css
- Executegit mv
on the line-by-line output ($line
variable contains each line) while matching the beginning of each filename and excluding the.css
extension (with${line%
and adding a new.scss
extension (--
is used to prevent ambiguity between filenames and flags)
ls folder*/*.css
- 用于ls
获取包含与 glob 模式匹配的 CSS 文件的所有目录的列表。(folder
以.css
扩展名开头并包含文件的目录)while read line
-ls
逐行读取命令行的结果输出do git mv -- $line ${line%.css}.css
-git mv
在逐行输出($line
变量包含每一行)上执行,同时匹配每个文件名的开头并排除.css
扩展名(使用${line%
并添加新.scss
扩展名(--
用于防止文件名和标志之间的歧义)
Code below can be used for a "dry run" (won't actually execute git mv
):
下面的代码可用于“试运行”(实际上不会执行git mv
):
ls variant*/*.css | while read line; do echo git mv $line to ${line%.css}.scss; done;
回答by samjewell
I solved this for myself by using
https://github.com/75lb/renamer- worked perfectly :-)
Doesn't explicitly do a git mv
but git seemed to deal with the results perfectly anyway.
我通过使用https://github.com/75lb/renamer为自己解决了这个问题
- 工作得很好:-) 没有明确地做 agit mv
但 git 似乎无论如何都能完美地处理结果。
When I followed all the steps in the top answer I got stuck at the final step, when my console responded with
当我按照最佳答案中的所有步骤进行操作时,我卡在了最后一步,当我的控制台响应为
for pipe quote>
for pipe quote>
If anyone can explain this I'd appreciate it!
如果有人可以解释这一点,我将不胜感激!
回答by Vincent Cantin
I am usually using NetBeans to do this type of stuff because I avoid the command line when there is a easier way. NetBeans has some support for git, and you can use it on arbitrary directory/file via the "Favorites" tab.
我通常使用 NetBeans 来做这类事情,因为当有更简单的方法时我会避免使用命令行。NetBeans 对 git 有一些支持,您可以通过“收藏夹”选项卡在任意目录/文件上使用它。