如何将孤立的分支附加到“按原样"母版? [英] How can I attach an orphan branch to master "as-is"?

查看:53
本文介绍了如何将孤立的分支附加到“按原样"母版?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用 git 的过程中,我们已经获得了解决方案的生产版本,并将其提交为 master .

In the process of moving to use git we have taken a production version of a solution and committed it as master.

然后,我们获得一个开发版本,并创建了一个名为 develop 孤立分支.

Then we took a development version and made an orphan branch called develop.

(背景:为什么我们在这里有些纠结是因为从开发版本到生产版本并没有一个清晰的演变.另外,组装涉及的解决方案也很复杂,这使得我们希望避免报废最后,我们只想将这些版本放入 git 中,并在 git 中开始清理.)

(Background: why we are getting a bit tangled up here is that the there was not a clean evolution from the development version to the production version. Plus there is a complexity to assembling the solutions involved that makes us want to avoid scrapping the repo and trying again. In the end, we just want to get these versions into git and commence the cleanup within git.)

所以-现在,我们认为最好从 master 分支开发版本,而不是将其保留为孤立分支.

So - now we think it would have been better to branch the development version from master rather than keep it as an orphan branch.

我们基本上如何接受 master 提交,并使其成为 develop 提交的父级>但没有进行任何合并?无需更改第一次 develop 提交的文件内容?

How can we basically take the master commit and make it the parent to the develop commit but without any merging taking place? Without changing the file contents of that first develop commit?

那是-只是将 develop 移植到其上, 原样 ,如果可以的话有道理吗?

That is - to just graft develop onto it somehow, as-is, if that makes any sense?

推荐答案

听起来您想修改自己的提交图而无需修改附加在这些树上的提交.

It sounds like you want to modify your commit graph without modifying any of the trees attached to those commits.

如果您了解git在内部如何工作,则此语句将更有意义.这里的关键项目是:

This statement will make more sense if you understand how git works internally. The key items here are:

  1. 所有提交都是永久不变的,因为提交(或git的四个内部对象中的任何一个)的真实名称"是其内容的SHA-1低温校验和.这意味着,如果您尝试更改任何内容(或发生故障的磁盘驱动器更改了某些内容),则git将抱怨校验和不正确,因为您在每个对象中看到的内容不再与它的真实名称"匹配.

  1. All commits are permanent and unchanging, because the "true name" of a commit (or indeed any of git's four internal objects) is the SHA-1 crypographic checksum of its contents. This means that if you attempt to change anything (or a failing disk drive changes something), git will complain of a bad checksum since what you see in each object doesn't match its "true name" any more.

每个提交都带有树"对象的SHA-1 ID,该对象充当该提交附带的源的完整快照. (该树给出了每个文件或目录的文件名和SHA-1真名".子目录由另一棵树表示.这里的细节并不重要.)

Each commit carries with it the SHA-1 ID of a "tree" object that acts as the complete snapshot of the source that goes with that commit. (The tree gives the file-names and SHA-1 "true names" of each file or directory. with sub-directories being represented by yet another tree. The details don't matter too much here.)

每个提交还列出其父级的真实名称" SHA-1 ID.因此,给定develop的尖端提交,git可以读取该提交并找到其直接父级. git读到该父母(或那些父母)后,会找到下一个ID(为父母读取),依此类推.该过程在读取"root"提交时停止,该提交是没有父母的提交.进行--orphan检出,然后进行提交,将导致新的根提交,这无疑是您如何创建分支的.

Each commit also lists the "true name" SHA-1 IDs of its parent(s). Thus, given the tip commit of develop, git can read that commit and find its immediate parent(s). Reading that parent (or those parents), git finds the next ID(s), which it reads for their parents, and so on. The process stops upon reading a "root" commit, which is one with no parents. Doing an --orphan checkout followed by making a commit results in a new root commit, which is no doubt how you made your branch.

存储在任何给定提交中的这些父ID和树ID被称为指向" git存储库中的其他对象. (回购中只有四种类型的对象.我们已经提到过"commit"和"tree",另外两种是"blob"(即git保存文件的方式)和"tag".树指向blob和sub -tree和"tag"对象用于带注释的标签.)

These parent and tree IDs, as stored in any given commit, are said to "point to" the other objects in the git repository. (There are only four types of objects in a repo. We already mentioned "commit" and "tree", the other two are "blob"—which is how git holds a file—and "tag". Trees point to blobs and sub-trees, and "tag" objects are used for annotated tags.)

因此,您要做的是更改develop分支的根提交,使其现在具有父提交,尤其是从master分支的当前尖端可到达的某些提交. (也许您想要小费本身,也许您想要类似master~100的东西:仅当您进行更改时,此细节才重要.)

Thus, what you want to do is to change the root commit of your develop branch so that it now has a parent commit, in particular some commit that is reachable from the current tip of the master branch. (Perhaps you want the tip itself, perhaps you want something like master~100: this detail only matters when you go to make the change.)

坏消息是,由于项目#1,您不能完全做到这一点.

The bad news is that because of item #1, you can't quite do this.

好消息是,您可以使用三种替代方法中的任一种来进行此操作(然后根据需要将移植物永久化).

The good news is that you can sort-of do this using any of three alternative methods (and then make the graft permanent, if needed and desired).

首先,git有一个叫做"grafts"的东西.它们工作得不太好,所以git有了一个更好的新东西,叫做替换".根据您的git年份,您应该至少有一个,并且几乎可以肯定两者都有.

First, git has a thing called "grafts". They don't work too terribly well, so git has a new better thing called "replacements". Depending on your git vintage you should have at least one, and almost certainly both.

这两个都使用相同的总体思路.在git执行其图遍历时,从提交到父级,您希望在某个时候能够使git更改其遍历.使用git移植,您只需指定ID为<X>的对象上时应遍历到父级<Y>.这样,您就可以找到当前develop上的根提交,并将其直接嫁接到master中的某些提交上.

These both use the same general idea. As git is doing its graph traversal, going from commit to parent, you want, at some point, to be able to get git to change its traversal. Using git grafts, you simply specify that when on object with id <X> it should traverse to parent <Y>. This lets you find the root commit on your current develop and graft it directly onto some commit in master.

这些嫁接文件不会被git clone复制,并引入了其他问题,因此git现在具有

These grafts do not get copied by git clone, and introduce other issues, so now git has git replace. This creates an actual object in the repository, and allow you to inspect the commit graph both with and without replacements. To use it for this case, you would make a replacement commit for your root-commit, that's exactly like the existing root-commit except that it has your desired parent.

如果要完全重写历史记录,使一个痛苦的重写步骤使所有用户都易于使用,则可以设置移植,然后使用git filter-branch复制和替换移植.或者,也许稍微容易一点,指定一个父过滤器(而不指定其他过滤器).请参见 git filter-branch文档有关详细信息;它有这种情况的一个例子. (文档表明,创建嫁接更为简单,我认为使用--parent-filter更为简单;但是无论哪种方式,都有一个方便的示例.)

If you want to rewrite history entirely, making it easy for all users after the one painful rewrite step, you can set up a graft and then use git filter-branch to copy-and-replace the graft. Or, perhaps slightly easier, specify a parent-filter (and no other filters). See the git filter-branch documentation for details; it has an example of this very case. (The documentation suggests that creating the graft is simpler, I think using --parent-filter is simpler; but either way, there's a handy example.)

请注意,过滤器分支复制每个过滤的"提交,并应用一些更改,方法是(虚拟)检查该提交,然后应用过滤器,然后创建一个结果中的新提交.在这种情况下,第一个更改是将父ID添加到根提交中.第二个更改是一个筛选器分支自动执行的操作:进行跟随的提交,即不再孤立的根副本指向根副本.第三次更改与第二次更改相同,依此类推:

Note that filter-branch copies every "filtered" commit, with some change(s) applied, by (virtually) checking out that commit, then applying the filter(s), then creating a new commit from the result. In this case the first change is to add a parent ID to the root commit. The second change is one filter-branch does automatically: make the commit that follows the no-longer-orphaned root-copy point to the root-copy. The third change is the same as the second, and so on:

      A--B--C     <-- develop (before filtering)

...--o--o--...    <-- master
      \
       A'-B'-C'   <-- develop (after filtering)

在这里,提交A'与提交A完全一样,除了它有一个父ID. B'B完全相同,不同之处在于它的父级是A'而不是A;等等.

Here, commit A' is exactly like commit A except that it has a parent ID; B' is exactly like B except that its parent is A' instead of A; and so on.

(顺便说一下,请注意,父箭头都在这里指向左,但是filter-branch是从左到右的.它是通过枚举所有要首先过滤的提交,使它们的ID从右到右来实现的.左时尚,然后从左到右进行过滤.)

(Note, by the way, that the parent arrows all point leftward here, but filter-branch works left-to-right. It does this by enumerating all the commits to filter first, getting their IDs in right-to-left fashion, bu then doing the filtering left-to-right.)

此现有的SO Q-and-A关于使用嫁接或替换的更多信息.

我确实提到了上面的第三种方法.仅当develop没有现有的合并提交时,此选项才有效.然后,您可以将develop中的每个提交简单地重新设置为目标提交,如

I did mention a third method above. This one works only when develop has no existing merge commits. You can then simply rebase every commit in develop onto your target commit, as siride suggested in a comment. You'll need to run that rebase command with --root to copy every commit from the root of your independent develop branch.

之所以有用,是因为git rebase只是复制提交,与git filter-branch一样.从某种意义上说,这是更多的工作,因为 way 重新建立基准的副本提交是通过应用差异(或多或少地使用重复的git cherry-pick)而不是简单地保留每个复制的提交的现有树"对象,但是它比git filter-branch容易得多.此处的缺点是rebase根本无法处理合并提交(嗯,除非您使用--preserve-merges,它使用交互式rebase代码,否则不会).

This works because git rebase simply copies commits, much the same way git filter-branch does. It's more work in one sense, because the way rebase copies commits is by applying diffs (using repeated git cherry-picks, more or less) rather than simply keeping each copied commit's existing "tree" object, but it's a lot easier to work than git filter-branch. The drawback here is that rebase does not handle merge commits at all (well, not unless you use --preserve-merges, which uses the interactive rebase code).

这篇关于如何将孤立的分支附加到“按原样"母版?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆