git 移植和替换有何不同?(现在不推荐移植吗?)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6800692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 05:44:17  来源:igfitidea点击:

How do git grafts and replace differ? (Are grafts now deprecated?)

git

提问by Philip Oakley

There are very few Q&A's on git graftsversus replace. The search [git] +grafts +replaceonly found two that felt relevant of the 5. what-are-git-info-grafts-forand git-what-is-a-graftcommit-or-a-graft-id. There is also a note on git.wiki.kernel.org:GraftPoint

关于 gitgraftsreplace. 搜索[git] +grafts +replace只找到两个感觉与 5. what-are-git-info-grafts-forgit-what-is-a-graftcommit-or-a-graft-id 相关的git.wiki.kernel.org上还有一个注释:GraftPoint

Are grafts now completely overtakenby the replaceand filter-branch, or do they still needed for some special corner cases (and backward compatibility) ?

现在移植是否完全replaceand取代filter-branch,或者它们仍然需要一些特殊的极端情况(和向后兼容性)?

In general, how do they differ (e.g. which are transported between repos), and how are they generically the same? I've seen that Linus doesn't appear to care about grafts at present in the discussion on commit generation numbers (of the max parents back to any root variety) "Grafts are already unreliable."

一般而言,它们有何不同(例如,哪些在 repos 之间传输),以及它们一般如何相同?我已经看到 Linus 目前在关于提交代数(最大父母回到任何根品种)的讨论中似乎并不关心移植,“移植已经不可靠了。”

EDIT: more info found.
A search of www.kernel.org/pub/software/scm/git/docs for graftonly found 3 results:

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

  1. git-filter-branch(1),
  2. v1.5.4.7/git-filter-branch(1),
  3. v1.5.0.7/git-svn(1).
  1. git-filter-branch(1),
  2. v1.5.4.7/git-filter-branch(1),
  3. v1.5.0.7/git-svn(1)。

A slightly broader search found RelNotes/1.6.5.txtwhich contains:

稍微广泛的搜索找到了RelNotes/1.6.5.txt,其中包含:

  • refs/replace/ hierarchy is designed to be usable as a replacement of the "grafts" mechanism, with the added advantage that it can be transferred across repositories.
  • refs/replace/hierarchy 被设计为可用作“grafts”机制的替代品,具有可以跨存储库传输的附加优势。

Unfortunately, the gitrepository-layout(5)isn't yet up to date with the refs/replace/ repository layout info (and notes), nor any deprecation note of info/grafts.

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

This gets closer to supporting what I was thinking but I'd welcome any confirmation or clarification.

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

回答by VonC

In the same discussionabout Commit Generation Numberthat you mention, Jakub Nar?bskidoes confirmthat grafts are more aproblem than a solution:

在您提到的关于Commit Generation Number同一讨论中Jakub Nar?bski确实确认移植比解决方案更成问题:

grafts are so horrible hack that I would be not against turning off generation numbers if they are used.
In the case of replace objects you need both non-replaced and replaced DAG generation numbers.
[...] Grafts are non-transferable, and if you use them to cull rather than add history they are unsafe against garbage collection... I think.

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

(publishing has always been taken care of with git filter-branch, as illustrated by this 2008 thread on grafts workflow.)

git filter-branch2008 年关于嫁接工作流程的线程所示,发布一直由 处理。)

The difference between graftsand git replaceis best illustrated by this SO question "Setting git parent pointer to a different parent", and the comments of (Jakub's again) answer.

嫁接git replace之间的区别最好通过这个SO 问题“将 git 父指针设置为不同的父级”以及(Jakub 再次回答)的评论来说明。

It does include the reference to Git1.6.5

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

From what I understand (from GraftPoints), git replacehas superseded git grafts(assuming you have git 1.6.5 or later)

(Jakub:)

  • if you want to rewrite historythen grafts+ git-filter-branch(or interactive rebase, or fast-export + e.g. reposurgeon) is the way to do it.
  • If you want/need to preserve history, then git-replaceis far superior to graft

据我了解(来自GraftPoints),git replace已取代git grafts(假设您有 git 1.6.5 或更高版本)

(雅各布:)

  • 如果您想重写历史记录,那么grafts+ git-filter-branch(或交互式 rebase,或快速导出 + 例如 reposurgeon)就是这样做的方法。
  • 如果你想/需要保存历史,那git-replace比嫁接要好得多

回答by Adrian Macneil

If you need to rewrite a parent commit using git replace, this is how to do it.

如果您需要使用 重写父提交git replace,这就是这样做的方法。

As Philip Oakley mentioned, git replace simply replaces one commit with another. To graft on a parent to an existing commit, you need to first create a fake commit with the correct parent.

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

Say you have two git branchs you want to graft:

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

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

Now we want (d) to be the parent of (c). So we create a replacement for (c) with the correct parent (let's call this c1), then git replace(c) with (c1). In these steps each of the letters refers to the SHA1 hash representing that commit.

现在我们想让 (d) 成为 (c) 的父级。所以我们用正确的父级(我们称之为 c1)创建(c)的替代品,然后git replace(c)用(c1)替代。在这些步骤中,每个字母都指代表示该提交的 SHA1 哈希。

To create the new commit:

创建新提交:

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

Now you have commit (c1) which has the correct parent (d). So all we need to do is replace the existing (c) with (c1):

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

git replace c c1

Now your history looks like this:

现在你的历史看起来像这样:

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

Bingo!

答对了!

回答by Esko Luontola

EDIT: git replace --graft <commit> [<parent>…?]does the same thing as grafts and it can add or remove parents. The documentationsays:

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

Create a graft commit. A new commit is created with the same content as <commit> except that its parents will be [<parent> …?] instead of <commit>'s parents. A replacement ref is then created to replace with the newly created commit.

创建移植提交。新提交的创建内容与 <commit> 相同,但其父项将是 [<parent> ...?] 而不是 <commit> 的父项。然后创建一个替换引用来替换新创建的提交。

(I'm leaving the old answer below as a reference.)

(我将下面的旧答案留作参考。)



AFAIK, there is one use case that graftscan handle but replacecannot: adding or removing parents. It's a power tool for refactoring histories.

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

For example, if you're importing the history from an old SVN repository into Git, there is no merge information. What you can do (and I've done it lots of times) is to read through the commit messages to find out where a SVN "merge" was done, and then use Git grafts to add a parent to the merge commit.

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

IIRC, I've also had some cases where I've removed the parent of a commit, in order to make it the first commit in the history. Creating a clean history based on multiple chaotic legacy repositories sometimes requires drastic measures (there are some experiences of migrating projects to Gitat my blog).

IIRC,我也有一些情况,我删除了提交的父级,以便使其成为历史上的第一次提交。基于多个混乱的遗留存储库创建一个干净的历史有时需要大刀阔斧的措施(在我的博客中有一些将项目迁移到 Git 的经验)。

Then after you've cleaned up the whole history, you would do a git filter-branchbefore publishing the new Git repository.

然后在你清理了整个历史之后,你会git filter-branch在发布新的 Git 存储库之前做一个。