git移植和替换有何不同?(移植物现在已被弃用吗?)

Phi*_*ley 53 git

有极少数的Q&A的上的git graftsreplace.搜索[git] + grafts + replace只发现了两个与5. what-are-git-info-grafts-forgit-what-a-a-graftcommit-or-a-graft-id相关的两个.git.wiki.kernel.org:GraftPoint上还有一个注释

被移植现在完全取代replacefilter-branch,或者他们仍然需要一些特殊的情况(和向后兼容)?

一般来说,它们如何不同(例如哪些在回购之间运输),它们通常是如何相同的?我已经看到Linus似乎并不关心目前在关于提交代数的讨论(最大父母回到任何根种类)的问题"移植已经不可靠了."

编辑:找到更多信息.
搜索www.kernel.org/pub/software/scm/git/docs graft仅找到3个结果:

  1. GIT-滤波器分支(1),
  2. v1.5.4.7/GIT-滤波器分支(1),
  3. v1.5.0.7/GIT-s​​vn的(1).

稍微宽泛的搜索发现RelNotes/1.6.5.txt包含:

  • refs/replace/hierarchy被设计为可用作"移植"机制的替代,其附加优势是它可以跨存储库传输.

不幸的是,gitrepository-layout(5)还没有更新refs/replace/repository布局信息(和注释),也没有任何信息/移植的弃用说明.

这更接近支持我的想法,但我欢迎任何确认或澄清.

Von*_*onC 16

在你提到的关于Commit Generation Number同一讨论中,JakubNarębski 确实证实了移植物比解决方案更具有问题:

移植是如此可怕的黑客攻击,如果他们被使用,我不会反对关闭世代号码.
在替换对象的情况下,您需要未替换和替换的DAG生成号.
[...]移植是不可转让的,如果你使用它们来剔除而不是添加历史,它们对垃圾收集是不安全的......我想.

(发布一直都是照顾的git filter-branch,如2008年关于移植工作流程的主题所示.)

移植git替换之间的区别最好通过这个SO问题"将git父指针设置为另一个父级"以及(Jakub的再次)回答的注释来说明.

它确实包括对Git1.6.5的引用

根据我的理解(来自GraftPoints),git replace已被取代git grafts(假设你有git 1.6.5或更高版本)

(:)的Jakub

  • 如果你想重写历史,那么grafts+ git-filter-branch(或交互式rebase,或快速导出+例如reposurgeon)就是这样做的方法.
  • 如果你想/需要保存历史,那么git-replace远远优于移植

  • 因此,移植定义了现有提交的替代父级,而替换定义了替换现有提交(Object)的替代提交(Object),但是您必须创建该替换对象,而移植不需要创建.但是,替换引用是在repos之间复制的,而移植不是(我认为). (11认同)

Adr*_*eil 13

如果您需要使用重写父提交git replace,这是如何做到的.

正如Philip Oakley所提到的,git replace只是将一个提交替换为另一个提交.要将父级移植到现有提交,您需要首先使用正确的父级创建虚假提交.

假设您有两个要移植的git分支:

(a)-(b)-(c) (d)-(e)-(f)
Run Code Online (Sandbox Code Playgroud)

现在我们希望(d)成为(c)的父母.因此,我们使用正确的父(我们称之为c1)创建(c)的替换,然后git replace使用(c1)创建(c).在这些步骤中,每个字母都引用表示该提交的SHA1哈希.

要创建新提交:

git checkout d
git rm -rf * # remove all files from working direcotry
git checkout c -- . # commit everything from c over top of it
GIT_AUTHOR_DATE="..." GIT_COMMITTER_DATE="..." git commit -m "..." # create replacement commit with date author
Run Code Online (Sandbox Code Playgroud)

现在你有提交(c1),它具有正确的父(d).所以我们需要做的就是用(c1)替换现有的(c):

git replace c c1
Run Code Online (Sandbox Code Playgroud)

现在您的历史记录如下:

(a)-(b)-(c1)-(d)-(e)-(f)
Run Code Online (Sandbox Code Playgroud)

答对了!

  • 最终图中 d 是 c 的父级吗?c(现在是 c1)肯定是 d 的父级吗?不应该是abd-c1-ef吗? (3认同)

Esk*_*ola 7

编辑:git replace --graft <commit> [<parent>…?]与移植物做同样的事情,它可以添加或删除父母.该文件说:

创建移植提交.创建一个与<commit>具有相同内容的新提交,但其父项将是[<parent> ...]而不是<commit>的父项.然后创建替换ref以替换新创建的提交.

(我将以下旧答案作为参考.)


AFAIK,有一个用例grafts可以处理但replace不能:添加或删除父项.它是重构历史的强大工具.

例如,如果您将历史记录从旧的SVN存储库导入Git,则没有合并信息.你可以做的(我已经做了很多次)是通读提交消息来找出SVN"合并"的位置,然后使用Git grafts将父级添加到合并提交.

IIRC,我还有一些情况,我已经删除了提交的父级,以使其成为历史上的第一个提交.基于多个混乱的遗留存储库创建干净的历史记录有时需要采取严厉的措施(在我的博客中有一些将项目迁移到Git的经验).

然后,在清理完整个历史记录之后,您将git filter-branch在发布新的Git存储库之前执行此操作.

  • 关键的修正是`git replace`可以完成移植的所有操作,包括在提交对象中添加或删除父项.只需使用具有正确父级的新提交对象替换旧对象.合并提交和单个父提交都是相同的对象类型,因此可以通过`replace`自由交换.希望可以扩展文档以使其清晰.你能纠正你的回答吗? (5认同)