如何推广“git replace -graft”

pepwfjgg  于 2023-03-11  发布在  Git
关注(0)|答案(3)|浏览(130)

我已经使用git replace --graft记录了一个版本实际上是两个版本之间的(手动执行的)合并:

git replace --graft <merged-version> <predecessor-version> <version-merged-from>

这对我的(本地、私有)存储库进行了更改。
现在我想让我团队的其他成员也可以使用这个修改,方法是将它“推送”到我们的共享存储库(在Github上,这是常有的事)。我该怎么做呢?一个简单的git push似乎没有什么效果。

ee7vknir

ee7vknir1#

移植存在于refs/replace/层次结构中(或者,更好的说法是,“将它们的存在归功于”这样的引用)。为了将它们从一个存储库转移到另一个存储库,必须推送或获取这样的引用。
例如:

git push origin refs/replace/5c714d7798d1dc9c18d194fa6448680515c0ccdb

当提交对象5c714d7798d1dc9c18d194fa6448680515c0ccdb有一个替换对象时(在我的例子中,替换对象是新的提交对象ceba978ce6dad3b52d12134f4ef2720c5f3a9002,即Git通常不会“看到”5c714d7,而是寻找替换对象ceba978)。
要推送所有替换:

git push origin 'refs/replace/*:refs/replace/*'

(the有时需要引号来防止shell损坏星号;确切的时间以及使用哪种引号在某种程度上取决于shell,尽管单引号和双引号在所有Unix-y shell上都有效)。

关于获取替换的说明

如果某个远程 R 有替换项,并且您希望将它们全部放入存储库中,请使用git fetch *R* 'refs/replace/*:refs/replace/*'(或者如果你想让它们的替换 override 任何你已经有的替换,可以加上前缀+).你可以为任何给定的仓库和远程自动化这个过程.例如,如果你运行git config --edit,你会发现你现有的origin遥控器有几个设置,看起来像这样:

[remote "origin"]
    url = ...
    fetch = +refs/heads/*:refs/remotes/origin/*

只需添加以下行:

fetch = refs/replace/*:refs/replace/*

或:

fetch = +refs/replace/*:refs/replace/*

让你的Git把他们的Git的refs/replace/*带过来。(注:这里不需要引号,因为shell不会处理这一行。2)前面的加号和通常的意义相同:1没有它,如果你 * 已经 * 有了一些引用,你 * 保留你的引用而忽略他们的引用。3有了前面的加号,你 * 放弃你的引用而使用他们的引用。4和标记一样,如果你的引用和他们的引用已经匹配,你保留你的引用还是用他们的引用替换你的引用都无关紧要;只有当你对引用应该命名什么对象有不同的想法时,这才是重要的。
1实际上,前导加号的“通常含义”取决于引用是 * 应该 * 移动,如分支名称,还是 * 不应该 * 移动,如标记名称。加号设置强制标志,即“总是采用建议的新设置”,但是对于分支名称--期望“向前移动”--当且仅当 * 是“向前”时,允许不强制地更新Git最初也将这条规则应用于其他引用,如标签,但Git的人在Git 1.8.2中修正了它。我不清楚Git将哪些规则应用于refs/replace/引用,因为refs/replace/引用不应该移动,但是不像标签那样被特别地处理。

7uzetpgm

7uzetpgm2#

为完整起见:git替换是“虚拟的”,而不是永久的。被操作的提交的原始版本仍然存在--它只是被替换提交所遮蔽。accepted answer描述了如何将那些“虚拟替换”也发布到共享仓库中,以及如何在获取时安排获取这样的替换。通常这是正确的做法。
然而,有时候我们想让这样的历史修复永久化,在Git中,唯一的方法就是 * 合成一个新的历史 * 这可以用git filter-branch(脆弱的,低级的)或者Github上非常好的工具git-filter-repo(Git项目官方推荐的)来完成。
然而,注意,没有办法 * 强迫共享储存库的其他用户使用重写的历史。* 您需要要求他们切换,例如通过重置他们的主分支或通过切换到另一个新分支。因此,在公共设置中,永久重写历史是不可行的;然而,对于封闭的用户组,例如在商业设置中,这是非常有效的选项(并且可能确实需要移除一些敏感的内容,如证书)。

xpcnnkqh

xpcnnkqh3#

使用git replace --graft时要小心:Git 2.22(Q2 2019)修复了一个bug,即当给定一个指向commit-ish的标记时,“git replace --graft“无法在写入replace ref之前剥离标记,这没有意义,因为该功能想要模仿的旧移植机制只允许用另一个对象替换一个commit对象。
参见commit ee521eccommit f8e44a8commit 5876170commit 502d87b(2019年3月31日)和Christian Couder ( chriscool )
(由Junio C Hamano -- gitster --合并至commit ce2a18f,2019年5月8日)

replace:在将标签首先传递到--graft时剥离标签

当将标记作为第一个参数传递给git replace --graft时,接受它并将底层提交用作将被替换的提交会很有用。
这已经适用于轻量级标记,但不幸的是,对于带注解的标记,我们一直使用标记对象的哈希值,而不是底层提交的哈希值。
特别是我们会将标记对象的散列传递给replace_object_oid(),在那里我们可能会失败,并显示如下错误:

"error: Objects must be of the same type.
'annotated_replaced_object' points to a replaced object of type 'tag'
while 'replacement' points to a replacement object of type 'commit'."

这个补丁修复了这个问题,当一个带注解的标记被传递时,它使用底层提交的哈希值。

相关问题