如何在 Git 回购中移动所有提交的目录?

假设我有一个包含这个目录结构的回购:

repo/
blog/
_posts/
some-post.html
another-file.txt

我想把 _posts移到回购协议的顶层,所以结构应该是这样的:

repo/
_posts/
some-post.html
another-file.txt

这是足够简单的 git mv,但我想让历史看起来好像 _posts 一直都是存在的根回购,我想能够得到整个历史的 some-post.html通过 git log -- _posts/some-post.html。我想我可以使用一些魔法与 git filter-branch来完成这一点,但我还没有找到确切的方法如何做到这一点。有什么想法吗?

28900 次浏览

您可以使用子目录筛选器来实现这一点

 $ git filter-branch --subdirectory-filter blog/ -- --all

编辑1: 如果你不想有效地让 _posts成为根,那么使用一个树型过滤器:

 $ git filter-branch --tree-filter 'mv blog/_posts .' HEAD

编辑2: 如果在某些提交中不存在 blog/_posts,上述操作将会失败。使用以下代码:

 $ git filter-branch --tree-filter 'test -d blog/_posts && mv blog/_posts . || echo "Nothing to do"' HEAD

虽然 Ramkumar 的回答很有帮助,也很有价值,但是在很多情况下都不起作用。 例如,当您希望将包含其他子目录的目录移动到新位置时。

为此,手册页包含完美的命令:

git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&NEWSUBDIR/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD

只需将 NEWSUBDIR 替换为所需的新目录即可。 你也可以使用嵌套的 dir,比如 dir1/dir2/dir3/-”

为任意移动/重命名创建一个通用脚本: https://gist.github.com/xkr47/f766f4082112c086af63ef8d378c4304

例子:

git filter-mv 's!^!subdir/!'

Something 在当前分支的所有提交中将所有文件移动到子目录“ subdir/”

git filter-mv 's!^foo/bar.txt$!foo/barbar.txt!'

Something 在当前分支的所有提交中将 foo/bar.txt 重命名为 foo/barbar.txt

不鼓励使用 git filter-branch。使用 git filter-repo要方便得多:

git filter-repo --path-rename blog/_posts:_posts

参见 给你

还要注意,安装是 支离破碎,您必须从 pip 安装并将 git-filter-repo添加到 $PATH