gpt4 book ai didi

git - 如何在保留历史记录的同时将 git 存储库重新定位到父文件夹?

转载 作者:IT王子 更新时间:2023-10-29 00:43:38 25 4
gpt4 key购买 nike

我在 /foo/bar/baz 中有一个 git 存储库,它有大量的提交历史和多个分支。

我现在希望 /foo/qux/foo/bar/baz 在同一个 repo 中,这意味着我需要它们都在一个 repo 中 Root 于 /foo。但是,我想保留对 /foo/bar/baz 所做更改的历史记录。

我首先想到的是 git format-patch,然后是 apply,但是提交消息没有被保留。

所以,

我需要重新根目录

(1) 到任意更高的祖先目录(2) 同时保留我的提交历史,让它看起来像我一直在提交 /foo/bar/baz

最佳答案

您想要的是 git filter-branch,它可以将整个存储库移动到一个子树中,通过使历史看起来一直如此来保存历史。在使用之前备份您的存储库!

这就是魔法。在 /foo/bar 中,运行:

git filter-branch --commit-filter '
TREE="$1";
shift;
SUBTREE=`echo -e 040000 tree $TREE"\tbar" | git mktree`
git commit-tree $SUBTREE "$@"' -- --all

这将使 /foo/bar 存储库拥有另一个“bar”子目录,其中包含其整个历史中的所有内容。然后你可以将整个 repo 移动到 foo 级别并向其添加 baz 代码。

更新:

好的,这就是发生的事情。提交是指向“树”的链接(将其视为代表整个文件系统子目录内容的 SHA)加上一些“父”SHA 和一些元数据链接作者/消息/等。 git commit-tree 命令是将所有这些包装在一起的低级位。 --commit-filter 的参数被视为一个 shell 函数,并在过滤过程中代替 git commit-tree 运行,并且必须像它一样运行。

我正在做的是采用第一个参数,要提交的原始树,并通过 git mktree 构建一个新的“树对象”,表示它位于子文件夹中,这是另一个低级 git命令。为此,我必须向其中输入一些看起来像 git 树的东西,即一组(模式 SP 类型 SP SHA TAB 文件名)行;因此 echo 命令。当我链接到真正的 commit-tree 时,mktree 的输出将替换为第一个参数; "$@" 是一种完整传递所有其他参数的方法,用 shift 去除了第一个参数。有关信息,请参阅 git help mktreegit help commit-tree

因此,如果您需要多个级别,则必须嵌套一些额外级别的树对象(这没有经过测试,但这是一般的想法):

git filter-branch --commit-filter '
TREE="$1"
shift
SUBTREE1=`echo -e 040000 tree $TREE"\tbar" | git mktree`
SUBTREE2=`echo -e 040000 tree $SUBTREE1"\tb" | git mktree`
SUBTREE3=`echo -e 040000 tree $SUBTREE2"\ta" | git mktree`
git commit-tree $SUBTREE3 "$@"' -- --all

这应该将实际内容向下移动到 a/b/bar(注意相反的顺序)。

更新:综合改进来自下面 Matthew Alpert 的回答。如果没有 -- --all 这仅适用于当前 checkout 的分支,但由于问题是询问整个 repo 协议(protocol),因此这样做比逐个分支更有意义.

关于git - 如何在保留历史记录的同时将 git 存储库重新定位到父文件夹?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3212485/

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