如何在Git存储库中为所有提交移动目录?


70

假设我有一个包含以下目录结构的存储库:

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

我想移到存储库_posts的顶层,因此结构如下所示:

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

这样做很简单git mv,但是我想使历史看起来好像_posts 一直存在于仓库的根部,并且我希望能够获得some-post.htmlvia的全部历史git log -- _posts/some-post.html。我想我可以使用一些魔术git filter-branch来完成此操作,但是我还没有弄清楚该怎么做。有任何想法吗?

Answers:


100

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

 $ 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

3
这也是很多更快地使用--index-filter,因为它没有检查出的树。
卡斯卡贝尔

7
是的,索引过滤器速度更快,但由于显示的命令不会影响索引,因此它无法工作。你需要做索引操作只有当你想使用索引过滤器(如git rm --cached替代rm
sehe

我也可以保留标签吗?在我看来,它们已经消失了。
迈克尔(Michael

1
git filter-branch --index-filter 'git read-tree --prefix=/ $GIT_COMMIT:_posts; git rm -r --cached _posts' -- --all。添加--tag-name-filter cat如果你的标签是不签,你想将它们移动/无效旧的。
jthill

对于此处仅用于复制粘贴的那些:记住git push --force --all所有分支。否则,您可能会遇到一些有趣的情况。
SiliconMind

37

尽管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替换为所需的新目录即可。您也可以使用嵌套的目录,例如dir1 / dir2 / dir3 /-“


12
而且由于从该命令或由此产生的错误中并不能立即看出,\ t在os x的sed版本上不起作用。有很多解决方法,但是最快的方法是删除ct并通过键入ctrl-v <tab>将其替换为文字选项卡。
Jeremy Huiskamp 2014年

4
您如何指定原始文件夹,还是仅移动整个分支?当我尝试从文件夹中运行该文件时,我得到了You need to run this command from the toplevel of the working tree
joshcomley15年

1
sed命令做什么?我正在Windows上尝试此操作,需要替代方法。
Lucius

1
辉煌。但是,是的,sed令人困惑,因此请仅尝试第二行对其进行测试。即删除不必要的顶层目录,我做了一个简单的操作git ls-files -s | sed "s-\tdir1/dir2/dir3/-\t-"
KCD

2
如果要过滤有效删除所有文件的提交,最终将导致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 进入了过滤分支脚本。
Knut Forkalsrud '16

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.