将文件和目录与提交历史logging一起移动到一个子目录中
如何将目录和文件与提交历史一起移动到子目录?
例如:
-
源目录结构:
[project]/x/[files & sub-dirs]
-
目标目录结构:
[project]/x/p/q/[files & sub-dirs]
Git在跟踪内容时做得非常好,即使它移动了,所以git mv
显然是一种移动文件的方式,因为它们以前属于x
,但现在属于x/p/q
因为项目演变的方式。
然而有时候,在整个项目的历史中,有一个将文件移动到子目录的理由。 例如,如果这些文件被错误地放在某个地方,而且已经有了更多的提交,但间歇提交甚至对错误位置的文件没有意义。 如果发生在本地分店的所有事情,我们希望在推动之前清理混乱。
这个问题与“提交历史”一起提到,我将这样解释为以这种方式重写历史。 这可以用来完成
git filter-branch --tree-filter "cd x; mkdir -pp/q; mv [files & sub-dirs] p/q" HEAD
这些文件将出现在整个历史logging的p/q
子目录中。
请注意,如果重写涉及之前已经被提交的提交,则不应该将结果推送到公共服务器。
为了增加bmargulies的评论 ,完整的序列是:
mkdir -px/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 -nx/* x/p/q
沃尔夫冈 评论说 :
如果你使用的是bash,你可以避免使用像这样的扩展的glob来移动一个文件夹到自己的问题(使用内置的
shopt
):
shopt -s extglob; git mv !(folder) folder
曼上尉 在评论中必须这样做:
mkdir temp git mv x/* temp mkdir -px/p/q git mv temp x/p/q rmdir temp;
语境:
我在Cygwin的Windows上。
我只是意识到我做了shopt -s extglob
例子错了,所以我的方式可能没有必要,但我通常使用zsh而不是bash,它没有命令shopt -s extglob
(虽然我确定那里是一个替代scheme),所以这种方法应该跨越shell(在shell的mkdir
和rmdir
如果它特别是外部的)
作为一个替代scheme, sp men 在评论中提到git mv
的-k
选项 :
跳过移动或重命名会导致错误情况的操作。
git mv -k * target/
这将避免“ can not move directory into itself
”的错误。
我可以看到这是一个古老的问题,但我仍然有必要回答以我现在解决这个问题的方法,我已经从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`
这是本书中的一个例子的一个特例,在一个特例中,我也使用了相同的例子来批量重命名提交历史中的文件。 如果在子目录中移动文件:记住要使用\来使path中的/字符转义,以使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
git mv命令是最简单的方法。 但是,至less在我的Linux机器上,我需要提供-k标志来避免返回一个文件夹无法移入的错误。 我能够通过使用…执行操作
mkdir subdirectory git mv -k ./* ./subdirectory # check to make sure everything moved (see below) git commit
作为一个警告,这将跳过所有会导致错误条件的移动,所以你可能会想要在移动之后和提交之前检查一切正常工作。