如何推动" git replace --graft"

时间:2017-02-27 15:23:33

标签: git git-push

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

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

这改变了我的(本地,私人)存储库。

我现在想让我的团队中的其他成员可以通过&#34;推送&#34;它到我们的共享存储库(在Github上,它发生了)。我怎么做?一个简单的git push似乎没有效果。

3 个答案:

答案 0 :(得分:9)

移植物存在于refs/replace/层次结构中。 (或者,可能更好地说,“将它们的存在归功于”此类引用。)要将它们从一个存储库传输到另一个存储库,那么,您必须推送或获取此类引用。

例如:

git push origin refs/replace/5c714d7798d1dc9c18d194fa6448680515c0ccdb

当commit 5c714d7798d1dc9c18d194fa6448680515c0ccdb有替换时(在我的情况下,替换是新的提交对象ceba978ce6dad3b52d12134f4ef2720c5f3a9002,即Git通常不“看到”5c714d7,寻找替换对象{ {1}}代替)。

推动所有替换:

ceba978

(有时需要引号来保持shell不会破坏星号;确切地说,何时以及使用哪种 kind 引用有些依赖于shell,尽管单引号和双引号都可以工作所有的Unix-y shell)。

获取替换的注意事项

如果某些远程 R 有替换,并且您想将所有这些替换为存储库,请使用git push origin 'refs/replace/*:refs/replace/*' (或者如果您使用前缀git fetch R 'refs/replace/*:refs/replace/*',则使用+希望他们替换覆盖你已经拥有的任何东西。您可以为任何给定的存储库和远程自动执行此操作。例如,如果您运行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不会处理这一行。)前导加号与通常具有相同的含义: 1 没有它,如果你已经有< / em>一些参考,你保留你的,忽略他们的。使用前导加号,您会丢弃您的并使用他们的。与标签一样,如果您的参考文献和参考文献已经匹配,那么您是保留自己的名称还是将其替换为他们的名称并不重要;这只有当你有不同的想法关于某个引用应该命名的对象时才重要。

1 事实上,前导加号的“通常含义”取决于引用是假定要移动,这样的分支名称,还是 not 应该移动,例如标记名称。加号标记设置强制标记,即“始终采用建议的新设置”,但对于分支名称 - 预期“向前移动” - 如果且仅在时允许更新这是一个“前进”(或“快进”)动作。 Git最初也将此规则应用于其他引用,例如标签,但Git人员在Git 1.8.2中修复了它。我不清楚Git哪些规则适用于refs/replace/引用,这些引用不应该移动,但不会特别注意标记的方式。

答案 1 :(得分:2)

为了完整性:git 替换是“虚拟的”,不是永久的。被操纵提交的原始版本仍然存在——它只是被替换提交掩盖了。 accepted answer 描述了如何将这些“虚拟替换”也发布到共享存储库中,以及如何在获取时安排获取此类替换。通常这是正确的做法。

但是,有时我们希望永久修复此类历史记录。使用 Git,唯一的方法是合成一个新的历史。这可以通过 git filter-branch(脆弱的、低级的)或非常好的工具 git-filter-repo 来完成在 Gitub 上(Git 项目官方推荐)。

但是请注意,没有办法强制共享存储库的其他用户使用重写的历史记录。您需要让他们切换,例如通过重置他们的主分支或切换到另一个新分支。因此,在公共设置中,永久改写历史是不可行的;但是对于封闭的用户组,例如在商业设置中,这是一个非常有效的选择(并且可能确实需要删除一些合理的内容,例如凭据)

答案 2 :(得分:0)

使用git replace --graft时要格外小心:Git 2.22(2019年第二季度)修复了一个错误:当给定指向提交承诺的标签时,“ git replace --graft”在写之前未能剥离标签替换引用,这没有意义,因为该功能要模仿的旧嫁接机制仅允许用另一个替换提交对象。

请参见commit ee521eccommit f8e44a8commit 5876170commit 502d87bChristian Couder (chriscool)(2019年3月31日)。
(由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'."
     

此修补程序通过传递带注释的标记时使用基础提交的哈希值来解决此问题。