如何将目录和文件与提交历史一起移动到子目录?
例如:
源目录结构:[project]/x/[files & sub-dirs]
目标目录结构:[project]/x/p/q/[files & sub-dirs]
答案 0 :(得分:60)
要添加到bmargulies的comment,完整的序列为:
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,则可以避免尝试使用类似扩展的glob(使用the
shopt
built-in)将文件夹移动到自身的问题:
shopt -s extglob; git mv !(folder) folder
Captain Man报告in the comments必须执行以下操作:
mkdir temp
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;
背景:
我和Cygwin在Windows上 我刚刚意识到我的
shopt -s extglob
示例错误,所以我的方式可能没有必要,但我通常使用zsh而不是bash,它没有命令shopt -s extglob
(虽然我是确定有另一种选择),所以这种方法应该适用于shell(在你的shellmkdir
和rmdir
中,如果它特别是外来的话)
作为替代方案,spanky提及in the comments -k
option of git mv
:
跳过移动或重命名可能导致错误情况的操作。
git mv -k * target/
这样可以避免出现“can not move directory into itself
”错误。
答案 1 :(得分:40)
即使内容被移动,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
子目录中。
请注意,如果重写触及之前已经推送过的提交,则不应将结果推送到公共服务器。
答案 2 :(得分:9)
我可以看到这是一个老问题,但我仍然觉得有必要回答我目前的问题解决方案,即我从git book中的一个例子中得出。
而不是使用低效--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
答案 3 :(得分:5)
git mv命令是最简单的方法。但是,至少在我的Linux机器上,我需要提供-k标志,以避免错误地回复文件夹无法移动到自身。我能够通过使用...
来执行操作mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit
作为警告,这将跳过所有移动,这将导致错误情况,因此您可能希望在移动之后和提交之前检查一切是否正常。
答案 4 :(得分:0)
如果您由于某些原因不想使用git mv命令,这里是另一种方法:
确保没有任何未提交的更改。
git状态
只需将包含.git文件夹的文件夹移动到新文件夹:
mkdir new_folder mv old_folder new_folder
然后将.git old_folder从已移动的文件夹移回到基本文件夹:
mv new_folder / old_folder / .git new_folder /
然后暂存并提交所有检测到的更改(列为将文件添加到新位置并将其从旧位置删除)