如何在Git repo中为所有提交移动目录?
假设我有一个包含以下目录结构的回购协议:如何在Git repo中为所有提交移动目录?,git,git-filter-branch,Git,Git Filter Branch,假设我有一个包含以下目录结构的回购协议: repo/ blog/ _posts/ some-post.html another-file.txt 我想将\u posts移动到回购协议的顶层,因此结构如下所示: repo/ _posts/ some-post.html another-file.txt 这对于git mv来说非常简单,但是我想让历史看起来好像\u posts始终存在于repo的根目录中,并且我想能够通过git log--\u post
repo/
blog/
_posts/
some-post.html
another-file.txt
我想将\u posts
移动到回购协议的顶层,因此结构如下所示:
repo/
_posts/
some-post.html
another-file.txt
这对于
git mv
来说非常简单,但是我想让历史看起来好像\u posts
始终存在于repo的根目录中,并且我想能够通过git log--\u posts/some post.html
获得some post.html
的整个历史。我想我可以通过git-filter-branch
来实现这一点,但我还没有弄清楚如何做到这一点。有什么想法吗?您可以使用子目录过滤器来实现这一点
$ git filter-branch --subdirectory-filter blog/ -- --all
编辑1:如果您不想有效地将\u posts
设置为根目录,请改用树过滤器:
$ git filter-branch --tree-filter 'mv blog/_posts .' HEAD
编辑2:如果部分提交中不存在blog/\u帖子
,则上述操作将失败。改用这个:
$ git filter-branch --tree-filter 'test -d blog/_posts && mv blog/_posts . || echo "Nothing to do"' HEAD
虽然拉姆库马尔的答案非常有用,也很有价值,但在很多情况下都不起作用。 例如,当您要将一个目录和其他子目录移动到一个新位置时 为此,手册页包含完美的命令:
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/-“为任意移动/重命名创建通用脚本: 示例:
git filter-mv 's!^!subdir/!'
➜ 在当前分支的所有提交中将所有文件移动到子目录“subdir/”
git filter-mv 's!^foo/bar.txt$!foo/barbar.txt!'
➜ 在当前分支的所有提交中将foo/bar.txt重命名为foo/barbar.txt使用
--索引过滤器
也要快得多,因为它不必签出树。是的,索引过滤器更快,但它不会工作,因为显示的命令不会影响索引。只有当您想使用索引过滤器时,才需要进行索引操作r(例如,git rm——缓存的
而不是rm
)我也可以保留标记吗?在我的情况下,它们看起来已经不存在了。git filter branch--index filter'git read tree--prefix=/$git\u COMMIT:\u posts;git rm-r--cached--u posts--all
。如果您的标记没有签名,并且您想移动它们/使旧的无效,则添加--tag name filter cat
:请记住对所有分支执行git push--force--all
。否则,您可能会遇到一些有趣的情况。由于查看该命令或由此产生的错误并不明显,因此\t在os x版本的sed上不起作用。有很多方法可以解决此问题,但也许最快的方法是删除\t并替换它通过键入ctrl-v,可以使用文本选项卡进行编辑。您如何指定原始文件夹,还是只移动整个分支?当我尝试从要移动的文件夹运行此命令时,我得到您需要从工作树的顶层运行此命令sed
命令的作用是什么?我正在Windows上尝试此操作,需要一个alternative.Brilliant。但是sed是令人困惑的,所以请尝试单独使用第二行来测试它。例如,为了删除不必要的顶级目录,我做了一个简单的git ls files-s | sed“s-\tdir1/dir2/dir3/-\t-”
如果您过滤的提交有效地删除了所有文件,那么您最终得到的git update index
不会创建文件$GIT_INDEX_FILE.new”,因此mv命令失败。我在过滤器分支脚本中使用了test-f\$GIT_INDEX_FILE.new和&mv\$GIT_INDEX_FILE.new\$GIT_INDEX_FILE | touch\$GIT_INDEX_FILE
。
git filter-mv 's!^foo/bar.txt$!foo/barbar.txt!'