使用git filter-branch --subdirectory-filter保留--no-ff merge提交

时间:2013-09-02 01:47:23

标签: git

我有一个具有以下结构的git存储库:

.git/
    project-root/
        abc/
        xyz/

这就是我想要的:

project-root/
    .git
    abc/
    xyz/

我一直在研究如何实现这一目标,这是我迄今为止所发现的:http://git-scm.com/docs/git-filter-branch

根据这个,我应该通过以下命令实现我想要的目标:

git filter-branch --subdirectory-filter project-root -- --all

这会重写提交历史记录,但大多数非快进合并提交都会丢失(请参见下图)。

有没有办法保留这些提交?

enter image description here

2 个答案:

答案 0 :(得分:2)

正如文档指出here

--subdirectory-filter <directory>

    Only look at the history which touches the given subdirectory. The result will 
    contain that directory (and only that) as its project root. Implies 
    [Remap_to_ancestor].

我认为问题在于合并提交实际上并没有触及给定的子目录,这意味着子目录过滤器甚至不会查看它们,因此无法保留它们。因此,我们必须使用另一个过滤器来检查每个提交。树形过滤器是完美的,但是我们必须编写一个脚本来完成我们想要对每个提交做的事情。

此外,我的问题实际上比示例更广泛,因为我的project-root文件夹中有我想删除的兄弟姐妹。子目录过滤器会删除它们,但为了使用树过滤器,find有助于救援。

每次将命令放在一个单独的文件中很方便。

对于这样的回购结构:

.git/ 
someDirectory/
someFile.txt
otherDirectory/
dontDeleteThisOne/
project-root/
    xyz/
    abc/

这对我有用:

git filter-branch --tree-filter /absolute/path/to/filterScript.sh --tag-name-filter cat -- --all 

其中/absolute/path/to/filterScript.sh是包含以下内容的可执行脚本:

#!/bin/bash

#save the folder dontDeleteThisOne so it won't get deleted
git mv -fk dontDeleteThisOne project-root && \
#remove everything not under project-root
find . -maxdepth 1 -mindepth 1 '(' -name project-root -o -name '.git' ')' -prune -o -exec git rm -rf --ignore-unmatch '{}' ';' && \
#move the contents of the project-root directory up to root
git mv -fk project-root/{,.[!.],..?}* .;

由此产生的回购结构如下:

.git/
dontDeleteThisOne/
xyz/
abc/

此结果相当于git filter-branch --subdirectory-filter project-root EXCEPT 的结果,根据需要,合并提交会保留在历史记录中。

当然,这比使用子目录过滤器需要更长的时间......

答案 1 :(得分:0)

我尝试使用--tree-filter而不是--subdirectory-filter,它似乎对我有用。这是我用过的命令:

git filter-branch --tree-filter 'git mv -k project-root/{,.[!.],..?}* .' -- --all

运行此命令后,将重写提交历史记录,就好像git从未跟踪过“project-root”一样,并保留分支拓扑,这就是我想要的方式。

如果有人试图在Windows上使用它并获得“权限被拒绝”错误,则杀死explorer.exe进程可能会有所帮助(我在此处找到了此解决方法:http://academe.co.uk/2011/12/git-mv-permission-denied/)。

编辑:上面的命令不会重写标记。为了重写标签,正确的命令是:

  

git filter-branch --tree-filter'git mv -k project-root / {,。[!。],...?}   “。 --tag-name-filter cat - --all