如何将目录和文件以及提交历史记录移到子目录?
例如:
源目录结构:
[project]/x/[files & sub-dirs]
目标目录结构:
[project]/x/p/q/[files & sub-dirs]
如何将目录和文件以及提交历史记录移到子目录?
例如:
源目录结构: [project]/x/[files & sub-dirs]
目标目录结构: [project]/x/p/q/[files & sub-dirs]
Answers:
要添加到bmargulies的注释中,完整序列为:
mkdir -p x/p/q # make sure the parent directories exist first
git mv x/* x/p/q # move folder, with history preserved
git commit -m "changed the foldername x into x/p/q"
请先尝试一下,以查看移动预览:
git mv -n x/* x/p/q
如果你正在使用bash,就可以避免试图通过使用扩展水珠像这样的一个文件夹移动到其自身的问题(使用了
shopt
内置的):
shopt -s extglob; git mv !(folder) folder
mkdir temp
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;
内容:
我在Windows上使用Cygwin。
我只是意识到我把shopt -s extglob
示例弄错了,所以我的方法可能不是必需的,但是我通常确实使用zsh代替bash,并且它没有命令shopt -s extglob
(尽管我确定有替代方法),所以这种方法应在整个壳工作(在你的shell底涂mkdir
和rmdir
它是否特别是外国)
作为替代,spany在评论中提到了以下-k
选项:git mv
:
跳过移动或重命名可能导致错误情况的动作。
git mv -k * target/
这样可以避免出现“ can not move directory into itself
”错误。
x
进入自身的子目录。git mv ...
做这项工作,git add ...
如果没有进一步的更改,则无需任何操作。
shopt -s extglob; git mv !(folder) folder
git mv -k * target/
来避免“无法将目录移入自身”错误。
即使内容四处移动,Git也可以很好地跟踪内容,因此 git mv
移动文件显然是一种方法,因为文件曾经属于x
,但是现在它们属于x/p/q
项目,因为项目以这种方式发展了。
但是,有时有理由在整个项目历史中将文件移动到子目录中。例如,如果文件被错误地放到某个地方,并且此后又进行了一些提交,但是对于错误的位置,间歇性提交甚至都没有意义。如果所有这些都发生在本地分支上,我们希望在推送之前清理混乱。
该问题指出“连同提交历史记录”,我将其解释为完全以这种方式重写历史记录。这可以用
git filter-branch --tree-filter "cd x; mkdir -p p/q; mv [files & sub-dirs] p/q" HEAD
这些文件然后出现在 p/q
整个历史记录中子目录中。
树过滤器非常适合小型项目,其优点是命令简单易懂。对于大型项目,此解决方案不能很好地扩展,如果性能很重要,则考虑使用此答案中概述的索引过滤器。
请注意,如果重写接触已提交过,则不应将结果推送到公共服务器。
mv * ./the-subdir
但出现了错误:“无法将-subdir移到自身的子目录中。我的解决方案是mv the-subdir /tmp; mv * /tmp/the-subdir mv /tmp/the-subdir ./
在tree-filter命令中使用。就像一个魅力。
git mv [files & sub-dirs] p/q
不打电话给raw mv
,否则我无法使它工作;在Mac上运行。但这最终对我来说效果很好,谢谢!
mv * .* the/subdir/ || true
移动文件和点文件而忽略错误消息。
我可以看到这是一个古老的问题,但是我仍然有义务使用当前解决方案来回答这个问题,我是从git书中的一个示例中得出的。代替使用效率低下的方法,--tree-filter
我使用来将文件直接移到索引上--index-filter
。
git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/^<old_location>/<new_location>/"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all
这是本书中的一个示例的一种特殊化,在一种特殊情况下,我还使用相同的示例在提交历史记录中批量重命名文件。如果在子目录中移动文件:请记住在路径中使用\来转义/字符,以使sed命令按预期工作。
例:
Project Directory
|-a
| |-a1.txt
| |-b
| | |-b1.txt
将b目录移动到项目根目录:
git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/a\/b\//b\//"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all
结果:
Project Directory
|-a
| |-a1.txt
|
|-b
| |-b1.txt
fatal: malformed index info -n 100644
。随着git filter-branch -f --index-filter 'git ls-files -s | sed "s/<old_location>/<new_location>/" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
它的工作在我的情况。不要忘了逃跑/
用\/
。
:
用作的分隔符sed
,则不必担心转义/
。
git mv命令是最简单的方法。但是,至少在我的Linux机器上,我需要提供-k标志,以免出现无法将文件夹移入其自身的错误。我能够通过使用...执行操作
mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit
作为警告,这将跳过所有会导致错误状态的移动,因此您可能需要检查在移动之后和提交之前,一切是否正常。