将文件和目录与提交历史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的mkdirrmdir如果它特别是外部的)


作为一个替代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 

作为一个警告,这将跳过所有会导致错误条件的移动,所以你可能会想要在移动之后和提交之前检查一切正常工作。