如何在Git仓库中移动所有提交的目录?

mip*_*adi 68 git git-filter-branch

假设我有一个包含此目录结构的仓库:

repo/
  blog/
    _posts/
      some-post.html
  another-file.txt
Run Code Online (Sandbox Code Playgroud)

我想移动_posts到repo的顶层,所以结构将如下所示:

repo/
  _posts/
    some-post.html
  another-file.txt
Run Code Online (Sandbox Code Playgroud)

这是够简单的git mv,但我想使历史看起来好像_posts 总是在回购的根源存在,我希望能够得到的全部历史some-post.html通过git log -- _posts/some-post.html.我想我可以用一些魔法git filter-branch来完成这个,但我还没弄清楚到底是怎么做到的.有任何想法吗?

art*_*non 98

您可以使用子目录过滤器来实现此目的

 $ git filter-branch --subdirectory-filter blog/ -- --all
Run Code Online (Sandbox Code Playgroud)

编辑1:如果您不想有效地创建_posts根,请使用树过滤器:

 $ git filter-branch --tree-filter 'mv blog/_posts .' HEAD
Run Code Online (Sandbox Code Playgroud)

编辑2:如果blog/_posts某些提交中不存在,则上述操作将失败.请改用:

 $ git filter-branch --tree-filter 'test -d blog/_posts && mv blog/_posts . || echo "Nothing to do"' HEAD
Run Code Online (Sandbox Code Playgroud)

  • 是的索引过滤器更快,但它不起作用,因为显示的命令不会影响索引.只有当你想使用索引过滤器时才需要进行索引操作(例如`git rm --cached`而不是`rm`) (7认同)
  • 使用`--index-filter`也快**快,因为它不必检查树. (3认同)

the*_*uke 34

虽然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
Run Code Online (Sandbox Code Playgroud)

只需将NEWSUBDIR替换为您想要的新目录即可.您也可以使用嵌套目录,如dir1/dir2/dir3/ - "

  • 并且由于查看该命令或产生的错误并不是很明显,因此\ t对于os x的sed版本不起作用.有很多方法,但最快的方法是删除\ t,然后输入ctrl-v,<tab>将其替换为文字标签. (12认同)
  • 如何指定原始文件夹,或者这只是移动整个分支?当我尝试从我想移动的文件夹运行它时,我得到`你需要从工作树的顶层运行这个命令 (4认同)
  • 如果您正在过滤一个有效删除所有文件的提交,那么您最终会使用`git update-index`而不创建文件"$ GIT_INDEX_FILE.new",因此mv命令会失败.我最终得到了`test -f\$ GIT_INDEX_FILE.new && mv\$ GIT_INDEX_FILE.new\$ GIT_INDEX_FILE || 在filter-branch脚本中触摸\ $ GIT_INDEX_FILE`. (2认同)