问题描述
假设我是一个仓库的维护者,并且我想从一个贡献者中引入更改,有几种可能的工作流程:- 我首选
合并 cherry-pick 和 rebase 出于以下原因。
- 健壮性。提交的SHA1标识符不仅标识它本身,而且还标识它与之前的所有其他提交有关的。这为您提供了一个保证,即给定SHA1中的存储库的状态在所有克隆中都是相同的。 (理论上)有人没有机会做出看起来像是一样的变化,但实际上是腐蚀或劫持你的存储库。你可以挑选个人变化,他们可能是相同的,但你没有保证。 (作为次要的次要问题,如果其他人再次选择同样的提交,那么新的挑选承诺将占用额外的空间,因为即使您的工作副本最终完全相同,它们也会出现在历史记录中。)
- 易用性。人们很容易理解 merge 工作流程。 rebase 往往被认为更加先进。最好是了解这两者,但不想成为版本控制专家的人(根据我的经验,包括许多擅长自己的工作但不想花费额外时间的同事)更容易
即使合并工作流程 rebase 和 cherry-pick 对于特殊情况仍然有用:
- merge 是杂乱的历史。 rebase 可以防止在您的历史中散布大量的提交,就像您定期合并其他人的更改一样。事实上,这是我使用它的主要目的。你想成为 ,永远不会与你与其他仓库共享的 rebase 代码。一旦提交是 push ,其他人可能已经提交了它,而重新绑定最多会导致上面讨论的那种重复。在最糟糕的情况下,您最终会遇到一个非常混乱的存储库和细微的错误,它需要很长时间才能发现。
- cherry-pick 对从你基本上决定放弃的主题分支中抽出一小部分变化很有用,但是意识到有几个有用的部分。
至于宁愿合并许多变化:它只是简单得多。一旦开始拥有大量变更集合,就会变得非常繁琐。 git(以及Mercurial和Bazaar中)的合并解决方案非常好。大部分时间你都不会遇到长期分支融合的重大问题。我通常一次合并所有内容,只有如果我会收到大量冲突,我才能备份并重新运行合并零碎。即使那样,我也是以大块的方式做到这一点。作为一个非常实际的例子,我有一位同事对合并进行了3个月的修改,并且在250000行代码库中遇到了9000次冲突。我们所要解决的问题是,一次合并一个月的价值:冲突不会线性增加,而且冲突会导致
Assuming I am the maintainer of a repo, and I want to pull in changes from a contributor, there are a few possible workflows:
- I cherry-pick each commit from the remote (in order). In this case git records the commit as unrelated to the remote branch.
- I merge the branch, pulling in all changes, and adding a new "conflict" commit (if needed).
- I merge each commit from the remote branch individually (again in order), allowing conflicts to be recorded for each commit, instead of grouped all together as one.
- For completeness, you could do a rebase (same as cherry-pick option?), however my understanding is that this can cause confusion for the contributor. Maybe that eliminates option 1.
In both cases 2 and 3, git records the branch history of the commits, unlike 1.
What are the pro's and con's between using either cherry-pick or merge methods described? My understanding is that method 2 is the norm, but I feel that resolving a large commit with a single "conflict" merge, is not the cleanest solution.
解决方案Both rebase (and cherry-pick) and merge have their advantages and disadvantages. I argue for merge here, but it's worth understanding both. (Look here for an alternate, well-argued answer enumerating cases where rebase is preferred.)
merge is preferred over cherry-pick and rebase for a couple of reasons.
- Robustness. The SHA1 identifier of a commit identifies it not just in and of itself but also in relation to all other commits that precede it. This offers you a guarantee that the state of the repository at a given SHA1 is identical across all clones. There is (in theory) no chance that someone has done what looks like the same change but is actually corrupting or hijacking your repository. You can cherry-pick in individual changes and they are likely the same, but you have no guarantee. (As a minor secondary issue the new cherry-picked commits will take up extra space if someone else cherry-picks in the same commit again, as they will both be present in the history even if your working copies end up being identical.)
- Ease of use. People tend to understand the merge workflow fairly easily. rebase tends to be considered more advanced. It's best to understand both, but people who do not want to be experts in version control (which in my experience has included many colleagues who are damn good at what they do, but don't want to spend the extra time) have an easier time just merging.
Even with a merge-heavy workflow rebase and cherry-pick are still useful for particular cases:
- One downside to merge is cluttered history. rebase prevents a long series of commits from being scattered about in your history, as they would be if you periodically merged in others' changes. That is in fact its main purpose as I use it. What you want to be very careful of, is never to rebase code that you have shared with other repositories. Once a commit is pushed someone else might have committed on top of it, and rebasing will at best cause the kind of duplication discussed above. At worst you can end up with a very confused repository and subtle errors it will take you a long time to ferret out.
- cherry-pick is useful for sampling out a small subset of changes from a topic branch you've basically decided to discard, but realized there are a couple of useful pieces on.
As for preferring merging many changes over one: it's just a lot simpler. It can get very tedious to do merges of individual changesets once you start having a lot of them. The merge resolution in git (and in Mercurial, and in Bazaar) is very very good. You won't run into major problems merging even long branches most of the time. I generally merge everything all at once and only if I get a large number of conflicts do I back up and re-run the merge piecemeal. Even then I do it in large chunks. As a very real example I had a colleague who had 3 months worth of changes to merge, and got some 9000 conflicts in 250000 line code-base. What we did to fix is do the merge one month's worth at a time: conflicts do not build up linearly, and doing it in pieces results in far fewer than 9000 conflicts. It was still a lot of work, but not as much as trying to do it one commit at a time.
这篇关于Git Cherry-pick vs合并工作流程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!