我正在编写使用git filter-branch --tree-filter
的git log --follow
命令来检查在过滤过程中是否应保留或删除某些文件。
基本上,我希望保留包含文件名的提交,即使此文件已重命名和/或已移动。
这是我正在运行的过滤器:
git filter-branch --prune-empty --tree-filter '~/preserve.sh' -- --all
这是我在preserve.sh
内部使用的命令:
git log --pretty=format:'%H' --name-only --follow --all -- "$f"
结果是,当我在新路径中搜索文件时,将删除创建历史文件的提交,而该文件后来又移至另一个路径,这是不应该的。例如:
提交1:创建
foo/hello.txt
;提交2:将
foo/hello.txt
移至bar/hello.txt
;使用
git filter-branch
传递bar/hello.txt
产生仅提交2的历史。
起初,我以为是因为我没有在--all
中使用git log
而发生问题,也就是说,在分析commit 1时找不到foo/hello.txt
,因为它只是在查找过去没有提到bar/hello.txt
的历史。但是后来我添加了--all
,它可以查看所有提交(包括“未来”提交),但是没有任何变化。
我检出了要在其中创建文件的提交,运行了该日志命令,它就起作用了(列出了foo/hello.txt
和bar/hello.txt
),因此没有任何问题。当它由filter-branch运行时,我还记录了log命令的结果,在这种情况下,我可以看到在commit 1中找不到该文件(仅列出了bar/hello.txt
)。
我认为会发生此问题,因为git在内部将每个提交都复制到“新仓库”结构中,因此在分析commit 1时,较新的提交尚不存在。
是否有解决此问题的方法,或解决保留重命名/移动的重写历史记录的另一种方法?
我正在运行this answer中找到的脚本的修改版本。
或在保留重命名/移动的同时解决重写历史记录问题的另一种方法?
自git filter-branch
is soon deprecated起,考虑使用新的git filter-branch
。
但是即使是新工具(基于newren/git-filter-repo
/ newren/git-filter-repo
)也不会跟随重命名的文件。
请参见git fast-export
,它间接说明了在考虑重命名文件的同时(使用旧的git fast-export
或新的git fast-import
命令过滤存储库的挑战。
[...]这与
git fast-import
,newren/git-filter-repo
issue 25和newren/git-filter-repo
git子命令的工作方式一致。例如。git filter-branch
不会显示该文件被重命名或复制的其他路径的任何历史记录(或文件的部分来源)。您专门使用了filter-repo
标志,这是一个大技巧,甚至在rev-list
文档中也提到过(它提到它仅在指定单个文件时有效)。如果log
/fast-export
/git log -- src/ledger/bin/app/app.cc
等具有重命名后的--follow
选项,我可以简单地将其从git log
中公开,但是尽管有这样一个选项的渴望,但没有人在许多情况下实现它年份。那里也有一些很好的挑战,例如我们可能需要遍历拓扑顺序,并且可能需要两次通过-一次创建拓扑顺序,第二次通过重命名建立其他路径。 (可能需要这样做的情况:某些分支建立在[rev-list
]之上,并且在指定的pathspec中具有一些路径,这些路径来自在存在“ master”时对pathspec之外的内容进行重命名。如果存在“ master”在另一个分支之前被遍历,那么我们已经选择了更有限的pathspec并错过了额外需要的路径。)但是,即使
log
在多个文件或目录或更多个目录的重命名之后实施,这仍然不一定足够,因为用户可能需要复制检测(即,不是从其他位置重命名的文件,而是它被复制)。但是,通过复制检测并不清楚是否要获取原件的完整历史记录。我可以想象在某些情况下您会,但在其他情况下不会。并且,如果我们开始进行重命名或复制检测,那么我们将从定义明确的正确行为转变为启发式方法。对于差异,日志或什至合并,这很好,因为结果将由用户解释(即使在合并中,如果检测错误,用户也可以修正冲突并进行其他编辑)。在这里,我们用石头记录了启发式方法的结果。这让我有点担心...这也意味着我们必须打开一堆旋钮(至少要有一个相似性百分比,以及是否需要重命名以外的副本)才能进行配置。
所有这些,我在使用时也想要类似的东西。我想到的最好的折衷方案是让人们事先运行'
fast-export
',查看重命名子报表,然后根据该信息手动选择其他路径以供其执行filter-repo运行。--follow
选项仍然具有filter-repo
,但这对于该问题而言最基本。提供它并让用户决定要包括的内容(尽管我什至不担心复制检测),似乎是我所能得到的最好选择。