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

时间:2011-07-23 13:28:52

标签: git

git graftsreplace上的Q& A很少。搜索 [git] + grafts + replace 只找到两个与5 what-are-git-info-grafts-forgit-what-is-a-graftcommit-or-a-graft-id相关的内容。 git.wiki.kernel.org:GraftPoint

还有一条说明

replacefilter-branch现在完全超过的移植物,或者某些特殊的角落情况(以及向后兼容性)是否还需要它们?

一般来说,它们如何不同(例如哪些是在回购之间运输),它们通常是如何相同的? 我已经看到Linus在关于提交世代号的讨论中似乎并不关心移植物(最大父母回到任何根种类)"Grafts are already unreliable."

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

  1. git-filter-branch(1),
  2. v1.5.4.7 / git的过滤器分支(1),
  3. v1.5.0.7 / GIT-SVN(1)。
  4. 稍微更广泛的搜索RelNotes/1.6.5.txt包含:

      
        
    • refs / replace / hierarchy旨在用作替代品   “移植”机制,具有额外的优势,它可以   转移到存储库。
    •   

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

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

3 个答案:

答案 0 :(得分:16)

在您提及的same discussionCommit Generation Number Jakub Narębski does confirm中,移植物比解决方案更具有问题:

  

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

git filter-branch一直照着2008 thread on grafts workflow进行发布,如grafts所示。)

git replace以及SO question "Setting git parent pointer to a different parent"的评论最能说明(Jakub's again) answerGit1.6.5之间的差异。

它包含对GraftPoints

的引用
  
    

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

  
     

(Jakub :)

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

答案 1 :(得分:13)

如果您需要使用git replace重写父提交,则可以使用此方法。

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

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

(a)-(b)-(c) (d)-(e)-(f)

现在我们希望(d)成为(c)的父母。因此,我们使用正确的父(我们称之为c1)创建(c)的替换,然后使用(c1)创建git replace(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

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

git replace c c1

现在您的历史记录如下:

(a)-(b)-(c1)-(d)-(e)-(f)

宾果!

答案 2 :(得分:7)

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

  

创建移植提交。创建一个新提交,其内容与&lt; commit&gt;相同。除了它的父母将是[&lt; parent&gt; ...而不是&lt; commit&gt;的父母。然后创建替换引用以替换新创建的提交。

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


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

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

IIRC,我还有一些案例,我已经删除了提交的父级,以使其成为历史上的第一个提交。基于多个混乱的遗留存储库创建干净的历史记录有时需要采取严厉的措施(我的博客上有some experiences of migrating projects to Git)。

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