Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git Cherry-pick vs Merge Workflow

Assuming I am the maintainer of a repo, and I want to pull in changes from a contributor, there are a few possible workflows:

  1. I cherry-pick each commit from the remote (in order). In this case git records the commit as unrelated to the remote branch.
  2. I merge the branch, pulling in all changes, and adding a new "conflict" commit (if needed).
  3. 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.
  4. 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.

like image 479
cmcginty Avatar asked Aug 06 '09 21:08

cmcginty


People also ask

What is the difference between cherry-pick and merge?

With the cherry-pick command, Git lets you incorporate selected individual commits from any branch into your current Git HEAD branch. When performing a git merge or git rebase , all the commits from a branch are combined. The cherry-pick command allows you to select individual commits for integration.

Is cherry-pick a good practice?

Cherry picking has a negative connotation as the practice neglects, overlooks or directly suppresses evidence that could lead to a complete picture. Cherry picking can be found in many logical fallacies.

What is cherry-pick in git?

git cherry-pick is a powerful command that enables arbitrary Git commits to be picked by reference and appended to the current working HEAD. Cherry picking is the act of picking a commit from a branch and applying it to another. git cherry-pick can be useful for undoing changes.

Is it possible to get merge conflict during git cherry-pick?

Yes, at least with the standard git setup. You cannot cherry-pick while there are conflicts. Furthermore, in general conflicts get harder to resolve the more you have, so it's generally better to resolve them one by one. That said, you can cherry-pick multiple commits at once, which would do what you are asking for.


2 Answers

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.

  1. 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.)
  2. 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:

  1. 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.
  2. 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.

like image 141
quark Avatar answered Oct 04 '22 13:10

quark


In my opinion cherry-picking should be reserved for rare situations where it is required, for example if you did some fix on directly on 'master' branch (trunk, main development branch) and then realized that it should be applied also to 'maint'. You should base workflow either on merge, or on rebase (or "git pull --rebase").

Please remember that cherry-picked or rebased commit is different from the point of view of Git (has different SHA-1 identifier) than the original, so it is different than the commit in remote repository. (Rebase can usually deal with this, as it checks patch id i.e. the changes, not a commit id).

Also in git you can merge many branches at once: so called octopus merge. Note that octopus merge has to succeed without conflicts. Nevertheless it might be useful.

HTH.

like image 35
Jakub Narębski Avatar answered Oct 04 '22 12:10

Jakub Narębski