gpt4 book ai didi

git - 清除已删除文件的 git 历史记录,保留重命名文件的历史记录

转载 作者:太空狗 更新时间:2023-10-29 14:44:54 24 4
gpt4 key购买 nike

我想将一些文件提取到新的存储库中,保留它们的历史记录,包括文件重命名

我能找到的最佳和最接近的答案是 new-repo-with-copied-history-of-only-currently-tracked-files ,使用 git filter-branch --index-filter。它成功地保留了现有文件的历史记录,但不保留重命名文件的历史记录。

(我能找到的另一个答案是使用 git filter-branch --subdirectory-filter。但它有两个问题:似乎不适用于整个 repo(文件夹“.”)并且不保留重命名文件的历史记录。)

(另一个答案是使用 git subtree。但它根本不保留历史。)

所以我可能正在寻找一种方法来改进 git ls-files > keep-these.txt 命令,从最接近的答案到还列出所有以前的文件名 .也许是脚本?

最佳答案

Git 不存储文件名更改。

每个提交存储一个完整的树,例如,可能提交 1234567... 有文件 READMEfoo.txt 和提交 fedcba9。 .. 有文件 readme.txtfoo。如果您要求 git 比较提交 1234567 与提交 fedcba9,并且 README 足够相似1 readme.txt,git会说将一个提交转换为另一个提交的方法是重命名文件。 (如果一个提交是另一个的父提交,子提交的 git show 将显示重命名,因为 git showgit show 时间。)

另一方面,如果第二个 readme 文件差异太大,但 READMEfoo 足够相似,git 会说改变1234567实现fedcba9的方法是将README重命名为foo

关键是 git 计算那个当你要求比较时,而不是更早。提交之间没有任何内容表示“重命名某些文件”。 Git 只是比较提交并决定然后文件是否足够相似。

就您的目的而言,这最终意味着对于您的复制或部分复制提交序列中的每个提交,您必须决定保留哪些路径名以及丢弃哪些路径名。如何实现这一目标主要取决于您。 git log 命令确实有一个 --follow 标志来激活有限数量的重命名检测,因为它从子提交到他们的父提交向后工作,而 git blame 自动尝试做同样的事情;您可以使用这些(一次一个路径名)来得出以下形式的映射:

      in:   commits A..B    C..D             E..F
use path: dir/file.ext dir/frill.txt lib/frill.next

例如。但是没有内置的东西可以做到这一点,而且也不会特别容易。我首先将 git log --follow--raw--name-status 输出结合起来,看看是否有任何有趣的检测到重命名。如果有的话,这些是提交边界,您将在提交边界处更改要保留和丢弃的路径(无论是使用 filter-branch 还是其他方法).

如果这不起作用,或者您需要更多控制,请考虑在各种提交对之间运行 git diff --name-status(提交对信息来自 git rev-list )。


1只要您要求进行重命名检测,“完全相同”就足够相似了,任何低至“50% 相似”的东西都是如此。您可以使用提供给 git diff-M 标志的可选值来调整所需的相似度。


编辑:这似乎工作正常。我是在git自带的builtin/var.c上使用的,以前有两个名字是这样的:

$ git log --follow --raw --diff-filter=R --pretty=format:%H builtin/var.c
81b50f3ce40bfdd66e5d967bf82be001039a9a98
:100644 100644 2280518... 2280518... R100 builtin-var.c builtin/var.c

55b6745d633b9501576eb02183da0b0fb1cee964
:100644 100644 d9892f8... 2280518... R096 var.c builtin-var.c

--diff-filter 抑制除重命名输出之外的所有内容,以便我们能够看到哪个提交似乎重命名了文件。将它变成更有用的东西需要更多的工作,但这可能会让你走得更远:

git log --follow --raw --diff-filter=R --pretty=format:%H builtin/var.c |
while true; do
if ! read hash; then break; fi
IFS=$'\t' read mode_etc oldname newname
read blankline
echo in $hash, rename $oldname to $newname
done

产生了:

in 81b50f3ce40bfdd66e5d967bf82be001039a9a98, rename builtin-var.c to builtin/var.c
in 55b6745d633b9501576eb02183da0b0fb1cee964, rename var.c to builtin-var.c

关于git - 清除已删除文件的 git 历史记录,保留重命名文件的历史记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33865637/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com