7

我有一个具有以下结构的 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

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

有什么方法可以保留这些提交吗?

在此处输入图像描述

4

2 回答 2

2

正如文档在这里指出的那样:

--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].

我认为问题在于合并提交实际上并没有触及给定的子目录,这意味着 subdirectory-filter 甚至不查看它们,因此无法保留它们。因此,我们必须使用另一个过滤器来检查每个提交。tree-filter 非常适合这个,但是我们必须编写一个脚本来执行我们想要对每个提交执行的操作。

此外,我的问题实际上比示例更广泛,因为我的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除非合并提交根据需要保留在历史记录中。

当然,这比使用子目录过滤器花费的时间要长得多......

于 2014-05-28T00:34:43.800 回答
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-权限被拒绝/)。

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

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

于 2013-09-02T14:17:11.363 回答