将git目录中的所有文件移动到子目录并保留历史记录

38

如何将当前目录中的所有文件移动到一个新目录并保留历史记录。

我尝试过:

git mv . old_app

但是我得到:

fatal: bad source, source=, destination=old_app/
8个回答

62
解决使 git mv 生效的方法很简单:

git mv -k * ./subDir

选项-k 将会跳过所有可能导致错误的操作。这在较旧版本的 git 中可能不起作用。 记住有 mvgit move 两种移动方式。 正常的 bash 移动用法是:mv * ./subDir,它只会产生一个警告,但仍然会移动您的文件。 而使用 git mv 来移动文件,例如使用 git mv * ./subDir,将会产生致命错误并中止移动操作:

fatal: can not move directory into itself, source=currentDir/subDir, destination=currentDir/subDir/subDir


4
所以你使用-k选项并跳过移动文件。这有什么用处? - LuxDie
2
因为mv命令总是失败,因为它试图将目录移动到自身。因此,操作将变成无限循环,因此会产生错误并且不会移动任何内容。但是使用-k选项,它将不会失败,也不会进入无限循环。 - Julian
10
是的,但实际上它什么也做不了,我已经尝试过了。 - LuxDie
6
这对我有用。它不仅抑制错误信息,还抑制了可能导致错误的操作mkdir folder; giv mv -k * folder/。这将导致现在所有的东西都在名为folder的目录中。使用 git 的 2.8.3 版本。 - Captain Man
1
你可能在使用PowerShell时遇到困难;可以尝试使用git mv -k (get-childItem *) folder/命令代替。(参见SuperUser上的这个问题。) - Aaron Campbell
显示剩余3条评论

16

您需要启用扩展通配符,这样您才能使用正则表达式。

如果您正在使用bash shell,请在执行包含通配符的命令之前输入此shopt(shell选项)命令:

$ shopt -s extglob

如果您不想每次都输入此命令,您还可以将其添加到~/.bash_profile文件中。

然后,您可以使用以下语法:

$ git mv ./!(exclude_me|exclude_me) ./destination_folder

例如,如果这是您的文件夹结构:
root
├── aardvark
├── contrib
|   ├── folder1
|   └── folder2
├── custom
|   ├── folder1
|   └── folder2
├── elephant
├── hippopotamus
└── zebra

然后在 root 目录下运行以下命令:

$ shopt -s extglob
$ git mv ./!(custom|contrib) ./contrib

你最终会得到这个:
root
├── contrib
|   ├── aardvark
|   ├── elephant
|   ├── folder1
|   ├── folder2
|   ├── hippopotamus
|   └── zebra
└── custom
    ├── folder1
    └── folder2

如果您想进行测试并确保命令能够无误执行,请添加-n标志:
$ git mv -n ./!(exclude_me|exclude_me) ./destination_folder

添加-k标志以包括未受版本控制的文件:

$ git mv -k ./!(exclude_me|exclude_me) ./destination_folder

如果使用 zsh shell,可以通过以下方式启用扩展 globbing,并使用 ^ 来否定模式。
$ setopt extendedglob
$ git mv ^(exclude_me|exclude_me) ./destination_folder
$ git mv ^exclude_me ./destination_folder

1
这个答案帮助我将一个Angular项目移动到名为client的目录中,必须排除.git..,命令如下:git mv ./!(client|.editorconfig|..|.|.git) ./client - Val Redchenko

6

我也遇到了同样的问题,解决方法是:

for file in $(ls | grep -v 'yourfolder'); do git mv $file yourfolder; done;

这不是答案吗? - Talon
非常好用!但是我认为你可以省略grep,不是吗?for file in $(ls); do git mv $file yourfolder; done; 我在Windows Git Bash上试过了。 - KeKru

4
在Windows上,您可以使用:
FOR %F IN (*) DO IF NOT %F == old_app git mv %F old_app
FOR /D %D IN (*) DO IF NOT %D == old_app git mv %D old_app

如果您正在批处理文件中执行此操作,则需要分别使用%%F%%D代替%F%D。参考https://superuser.com/a/112141

3
在Windows Powershell中,你可以使用以下命令:dir -exclude old_app | %{git mv $_.Name old_app}。这个命令的灵感来自于https://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/。 - Scott Stafford
@ScottStafford 我该如何在从PowerShell调用的批处理文件中使用您的命令?我收到以下错误'{git'不是内部或外部命令 - A.P.
如果%F包含空格,你应该加上引号,另外,如果你在仓库的根目录中,也许还应该检查一下是否有.git文件夹。 - Vlad

4

"git ls-tree -r --name-only HEAD path" 的效果很好,但不会保留文件结构移动到新目录:/ - jdnichollsc
1
它确实可以。它列出目录,然后您可以移动它们。 - Jacek Krysztofik
谢谢,最终我使用了另一种方法: git mv path/origin path/new-name && git mv path/new-name other-directory - jdnichollsc

0

我想将所有的png文件移动到本地和远程仓库中的images子目录中:

mkdir images
git add *.png
git mv  *.png ./images
git commit -m "move"
git push -u origin master

-1
如果你是Windows用户,this 是一个适合你的解决方案。
  1. 如果你还没有安装Turtoise Git,请先安装
  2. 选择你想要移动的文件夹
  3. 右键点击,选择Turtoise git,重命名

enter image description here


-3

我认为,你正在进行无效操作。

你不能将当前目录(pwd).移动到位于当前目录内部的其他目录中。即使是使用mv 命令也无法执行。正如输出所述。

mv: cannot move ‘.’ to ‘someDir/.’: Device or resource busy

在 git mv 中使用 * 也表示

git mv * someDir
fatal: can not move directory into itself, source=curDir, destination=curDir/someDir

返回上一级目录,并选择要移动到目标目录的目录。在这种情况下,您不能将父目录移动到子目录中。可以将父目录的内容/文件移动到目标目录,但不能移动父目录本身。


使用扩展通配符而不抑制错误,可以参考我的答案来完成此操作。 - featherbelly
是的,执行命令 git mv * someDir 被拒绝了。不过,我成功地一个一个地将每个文件夹和文件使用 git mv 命令移动到了另一个目录下,该目录也在项目根目录下 :-) - Lashae

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接