git子树没有保留历史记录,因此我无法推动子树更改,我如何在将来修复/避免此问题?

git子树没有保留历史记录,因此我无法推动子树更改,我如何在将来修复/避免此问题?,git,git-subtree,Git,Git Subtree,我一直在使用git子树扩展()来管理主项目中的子项目。它做的正是我想要的,而不是当我试图将对子项目所做的更改从主项目中分离出来时,它失败了 e、 早些时候,我已经做了 git subtree add -P Some/Sub/Dir --squash git@gitserver:lib.git master 将库代码引入主项目中的Some/Sub/Dir。这里的一切都很顺利,所以我将我的更改推到了我们的中心主项目bare git repo上。然后,我决定在Some/Sub/Dir中对本地版本的l

我一直在使用git子树扩展()来管理主项目中的子项目。它做的正是我想要的,而不是当我试图将对子项目所做的更改从主项目中分离出来时,它失败了

e、 早些时候,我已经做了

git subtree add -P Some/Sub/Dir --squash git@gitserver:lib.git master
将库代码引入主项目中的Some/Sub/Dir。这里的一切都很顺利,所以我将我的更改推到了我们的中心主项目bare git repo上。然后,我决定在Some/Sub/Dir中对本地版本的lib进行更改,提交它,然后将其拆分,以将其推回到lib.git repo

git subtree split -P Some/Sub/Dir -b some_branch
一切正常。不再需要回购协议的本地副本,我将其删除

在从我们的中心repo克隆了一个新的repo副本后,我在some/Sub/Dir中对lib做了一些更改,并决定将这些更改拆分出来,并将它们推回到lib.git存储库中。我尝试使用与前面相同的子树拆分命令,但这次我得到以下输出:

1/      3 (0)
2/      3 (1)
3/      3 (1)
fatal: bad object d76a03f0ec7e20724bcfa253e6a03683211a7bb1
当我添加子树时,d76a03f0ec7e20724bcfa253e6a03683211a7bb1来自:

commit 43b3eb7d69d5eb64241eddb12e5bd74fd0215083
Author: Ian Bond <ibond@onezero.com>
Date:   Fri Apr 22 15:06:50 2011 -0400

    Squashed 'Subtree/librepoLib/' content from commit d76a03f

    git-subtree-dir: Subtree/librepoLib
    git-subtree-split: d76a03f0ec7e20724bcfa253e6a03683211a7bb1
拆分自“git子树添加”以来的所有历史记录,并将其合并回原始回购协议(谢天谢地,自添加以来,原始回购协议没有任何更改)。这是最好的方式吗?有关于如何执行合并的建议吗


2)我能做些什么让git子树按预期工作吗?我相信如果我省略了'git subtree add'上的--squash参数,那么一切都会工作,但是这会导致一堆无关的历史被注入到我的回购协议中。是否有某种方法可以保留所需的提交(最好不保留库的整个历史)?

git子树拆分的目的是在子树的原始历史之上创建一些新的提交(表示最初在子树的本地目录中所做的“本地”更改)。由于它直接涉及子树的原始历史记录(作为第一次重写的本地提交的父提交,该本地提交与子树接触),因此在子树的原始历史记录本身不存在的情况下,无法执行拆分操作

想想你将如何处理
git subtree split
生成的历史记录。您可能希望将其推送到一个存储库,在那里您可以将其合并到“上游”历史的其余部分中。为了使此合并操作有意义,拆分历史需要基于原始历史本身1

为用户安排子树原始历史记录的最可靠方法可能是在文档中发布子树上游存储库的URL,并让他们为其定义一个远程(在单个存储库中有“不相关”的远程存储库是完全正确的)。例如

如果您需要使用
Some/Sub/Dir
的“上游”(拉入外部更改或推出本地更改),请在使用
git子树之前为库的存储库定义并更新远程:

git remote add lib git@host:the-lib-repository &&
git fetch lib
即使您没有使用
--squash
,您也需要执行类似的操作,因为用户需要知道在哪里获得新的上游提交(以及(最终)在哪里推送新的拆分生成的提交)

使用
--squash
可以在主项目中为您提供一个“干净”的历史记录,这意味着只有那些需要处理子树的“上游”的用户才必须在其存储库中拥有其对象


看起来您对对象模型有很好的理解。您是正确的,
git子树add--squash
拉入的历史将变为悬空2,但是
git子树split
仍然可以使用它,直到它被剪除

(参考您的复制脚本)
只有本地克隆自动硬链接(或复制)
.git/objects/
中的所有文件(从而从
repoLib
访问
repoMain
中悬空(或几乎悬空2)对象的副本),而不是使用通常的“打包协议”,您才能在
repoMainClone
中成功拆分传输(将传输的对象限制为仅传输引用所需的对象;即从
repoLib
中省略任何内容)。您的
repoMainPull
实际上相当于克隆
file://“$(pwd)”/repomainrepomainclonefile
file://
URL强制本地克隆使用基于包的传输,而不只是链接/复制所有内容)


一, 实际上,您可以直接合并不相关的历史记录,但是您将失去进行三方合并的能力(因为没有共同的祖先)。这将是相当大的牺牲

您建议的
git子树拆分-p Some/Sub/Dir 43b3eb7^--忽略连接…
(其中43b3eb7是由
git子树add--squash…
生成的合成提交),将生成一个不相关的历史记录(除了它需要是
43b3eb7..
,因为
43b3eb7^
表示“43b3eb7的第一个父级”,而43b3eb7没有父级)。我不确定git subtree split是否设计成这样的范围。git subtree split
的文档只说了
,但从未真正提到它的用途。读取代码会显示它默认为HEAD,这可能表示它是一个单一的提交,指定应该为拆分处理的历史记录的“提示”。此外,打开调试输出会显示一条消息
顺序不正确:
,这可能表明使用范围参数会使拆分操作处于意外情况(它希望在处理提交本身之前已处理提交的所有父级,但范围会确保
git remote add lib git@host:the-lib-repository &&
git fetch lib