我已经使用git replace --graft记录了一个版本实际上是两个版本之间的(手动执行的)合并:
git replace --graft
git replace --graft <merged-version> <predecessor-version> <version-merged-from>
这对我的(本地、私有)存储库进行了更改。现在我想让我团队的其他成员也可以使用这个修改,方法是将它“推送”到我们的共享存储库(在Github上,这是常有的事)。我该怎么做呢?一个简单的git push似乎没有什么效果。
git push
ee7vknir1#
移植存在于refs/replace/层次结构中(或者,更好的说法是,“将它们的存在归功于”这样的引用)。为了将它们从一个存储库转移到另一个存储库,必须推送或获取这样的引用。例如:
refs/replace/
git push origin refs/replace/5c714d7798d1dc9c18d194fa6448680515c0ccdb
当提交对象5c714d7798d1dc9c18d194fa6448680515c0ccdb有一个替换对象时(在我的例子中,替换对象是新的提交对象ceba978ce6dad3b52d12134f4ef2720c5f3a9002,即Git通常不会“看到”5c714d7,而是寻找替换对象ceba978)。要推送所有替换:
5c714d7798d1dc9c18d194fa6448680515c0ccdb
ceba978ce6dad3b52d12134f4ef2720c5f3a9002
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遥控器有几个设置,看起来像这样:
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不会处理这一行。2)前面的加号和通常的意义相同:1没有它,如果你 * 已经 * 有了一些引用,你 * 保留你的引用而忽略他们的引用。3有了前面的加号,你 * 放弃你的引用而使用他们的引用。4和标记一样,如果你的引用和他们的引用已经匹配,你保留你的引用还是用他们的引用替换你的引用都无关紧要;只有当你对引用应该命名什么对象有不同的想法时,这才是重要的。1实际上,前导加号的“通常含义”取决于引用是 * 应该 * 移动,如分支名称,还是 * 不应该 * 移动,如标记名称。加号设置强制标志,即“总是采用建议的新设置”,但是对于分支名称--期望“向前移动”--当且仅当 * 是“向前”时,允许不强制地更新Git最初也将这条规则应用于其他引用,如标签,但Git的人在Git 1.8.2中修正了它。我不清楚Git将哪些规则应用于refs/replace/引用,因为refs/replace/引用不应该移动,但是不像标签那样被特别地处理。
refs/replace/*
7uzetpgm2#
为完整起见:git替换是“虚拟的”,而不是永久的。被操作的提交的原始版本仍然存在--它只是被替换提交所遮蔽。accepted answer描述了如何将那些“虚拟替换”也发布到共享仓库中,以及如何在获取时安排获取这样的替换。通常这是正确的做法。然而,有时候我们想让这样的历史修复永久化,在Git中,唯一的方法就是 * 合成一个新的历史 * 这可以用git filter-branch(脆弱的,低级的)或者Github上非常好的工具git-filter-repo(Git项目官方推荐的)来完成。然而,注意,没有办法 * 强迫共享储存库的其他用户使用重写的历史。* 您需要要求他们切换,例如通过重置他们的主分支或通过切换到另一个新分支。因此,在公共设置中,永久重写历史是不可行的;然而,对于封闭的用户组,例如在商业设置中,这是非常有效的选项(并且可能确实需要移除一些敏感的内容,如证书)。
git filter-branch
xpcnnkqh3#
使用git replace --graft时要小心:Git 2.22(Q2 2019)修复了一个bug,即当给定一个指向commit-ish的标记时,“git replace --graft“无法在写入replace ref之前剥离标记,这没有意义,因为该功能想要模仿的旧移植机制只允许用另一个对象替换一个commit对象。参见commit ee521ec、commit f8e44a8、commit 5876170、commit 502d87b(2019年3月31日)和Christian Couder ( chriscool )。(由Junio C Hamano -- gitster --合并至commit ce2a18f,2019年5月8日)
chriscool
gitster
replace
--graft
当将标记作为第一个参数传递给git replace --graft时,接受它并将底层提交用作将被替换的提交会很有用。这已经适用于轻量级标记,但不幸的是,对于带注解的标记,我们一直使用标记对象的哈希值,而不是底层提交的哈希值。特别是我们会将标记对象的散列传递给replace_object_oid(),在那里我们可能会失败,并显示如下错误:
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'."
这个补丁修复了这个问题,当一个带注解的标记被传递时,它使用底层提交的哈希值。
3条答案
按热度按时间ee7vknir1#
移植存在于
refs/replace/
层次结构中(或者,更好的说法是,“将它们的存在归功于”这样的引用)。为了将它们从一个存储库转移到另一个存储库,必须推送或获取这样的引用。例如:
当提交对象
5c714d7798d1dc9c18d194fa6448680515c0ccdb
有一个替换对象时(在我的例子中,替换对象是新的提交对象ceba978ce6dad3b52d12134f4ef2720c5f3a9002
,即Git通常不会“看到”5c714d7
,而是寻找替换对象ceba978
)。要推送所有替换:
(the有时需要引号来防止shell损坏星号;确切的时间以及使用哪种引号在某种程度上取决于shell,尽管单引号和双引号在所有Unix-y shell上都有效)。
关于获取替换的说明
如果某个远程 R 有替换项,并且您希望将它们全部放入存储库中,请使用
git fetch *R* 'refs/replace/*:refs/replace/*'
(或者如果你想让它们的替换 override 任何你已经有的替换,可以加上前缀+
).你可以为任何给定的仓库和远程自动化这个过程.例如,如果你运行git config --edit
,你会发现你现有的origin
遥控器有几个设置,看起来像这样:只需添加以下行:
或:
让你的Git把他们的Git的
refs/replace/*
带过来。(注:这里不需要引号,因为shell不会处理这一行。2)前面的加号和通常的意义相同:1没有它,如果你 * 已经 * 有了一些引用,你 * 保留你的引用而忽略他们的引用。3有了前面的加号,你 * 放弃你的引用而使用他们的引用。4和标记一样,如果你的引用和他们的引用已经匹配,你保留你的引用还是用他们的引用替换你的引用都无关紧要;只有当你对引用应该命名什么对象有不同的想法时,这才是重要的。1实际上,前导加号的“通常含义”取决于引用是 * 应该 * 移动,如分支名称,还是 * 不应该 * 移动,如标记名称。加号设置强制标志,即“总是采用建议的新设置”,但是对于分支名称--期望“向前移动”--当且仅当 * 是“向前”时,允许不强制地更新Git最初也将这条规则应用于其他引用,如标签,但Git的人在Git 1.8.2中修正了它。我不清楚Git将哪些规则应用于
refs/replace/
引用,因为refs/replace/
引用不应该移动,但是不像标签那样被特别地处理。7uzetpgm2#
为完整起见:git替换是“虚拟的”,而不是永久的。被操作的提交的原始版本仍然存在--它只是被替换提交所遮蔽。accepted answer描述了如何将那些“虚拟替换”也发布到共享仓库中,以及如何在获取时安排获取这样的替换。通常这是正确的做法。
然而,有时候我们想让这样的历史修复永久化,在Git中,唯一的方法就是 * 合成一个新的历史 * 这可以用
git filter-branch
(脆弱的,低级的)或者Github上非常好的工具git-filter-repo(Git项目官方推荐的)来完成。然而,注意,没有办法 * 强迫共享储存库的其他用户使用重写的历史。* 您需要要求他们切换,例如通过重置他们的主分支或通过切换到另一个新分支。因此,在公共设置中,永久重写历史是不可行的;然而,对于封闭的用户组,例如在商业设置中,这是非常有效的选项(并且可能确实需要移除一些敏感的内容,如证书)。
xpcnnkqh3#
使用
git replace --graft
时要小心:Git 2.22(Q2 2019)修复了一个bug,即当给定一个指向commit-ish的标记时,“git replace --graft
“无法在写入replace ref之前剥离标记,这没有意义,因为该功能想要模仿的旧移植机制只允许用另一个对象替换一个commit对象。参见commit ee521ec、commit f8e44a8、commit 5876170、commit 502d87b(2019年3月31日)和Christian Couder (
chriscool
)。(由Junio C Hamano --
gitster
--合并至commit ce2a18f,2019年5月8日)replace
:在将标签首先传递到--graft
时剥离标签当将标记作为第一个参数传递给
git replace --graft
时,接受它并将底层提交用作将被替换的提交会很有用。这已经适用于轻量级标记,但不幸的是,对于带注解的标记,我们一直使用标记对象的哈希值,而不是底层提交的哈希值。
特别是我们会将标记对象的散列传递给
replace_object_oid()
,在那里我们可能会失败,并显示如下错误:这个补丁修复了这个问题,当一个带注解的标记被传递时,它使用底层提交的哈希值。