How does git merge after cherry-pick work?

44,196

Solution 1

Short answer

Don't worry, Git will handle it.

Long answer

Unlike e.g. SVN1, Git does not store commits in delta format, but is snapshot-based2,3. While SVN would naively try to apply each merged commit as a patch (and fail, for the exact reason you described), Git is generally able to handle this scenario.

When merging, Git will try to combine the snapshots of both HEAD commits into a new snapshot. If a portion of code or a file is identical in both snapshots (i.e. because a commit was already cherry-picked), Git won't touch it.

Sources

1 Skip-Deltas in Subversion
2 Git Basics
3 The Git object model

Solution 2

After such merge you may have cherry-picked commits in history twice.

Solution to prevent this I quote from article which recommends for branches with duplicate(cherry-picked) commits use rebase before merge:

git merge after git cherry-pick: avoiding duplicate commits

Imagine we have the master branch and a branch b:

   o---X   <-- master
    \
     b1---b2---b3---b4   <-- b

Now we urgently need the commits b1 and b3 in master, but not the remaining commits in b. So what we do is checkout the master branch and cherry-pick commits b1 and b3:

$ git checkout master
$ git cherry-pick "b1's SHA"
$ git cherry-pick "b3's SHA"

The result would be:

   o---X---b1'---b3'   <-- master
    \
     b1---b2---b3---b4   <-- b

Let’s say we do another commit on master and we get:

   o---X---b1'---b3'---Y   <-- master
    \
     b1---b2---b3---b4   <-- b

If we would now merge branch b into master:

$ git merge b

We would get the following:

   o---X---b1'---b3'---Y--- M  <-- master
     \                     /
      b1----b2----b3----b4   <-- b

That means the changes introduced by b1 and b3 would appear twice in the history. To avoid that we can rebase instead of merge:

$ git rebase master b

Which would yield:

   o---X---b1'---b3'---Y   <-- master
                        \
                         b2'---b4'   <-- b

Finally:

$ git checkout master
$ git merge b

gives us:

   o---X---b1'---b3'---Y---b2'---b4'   <-- master, b

EDIT Corrections supposed by David Lemon's comment

Share:
44,196

Related videos on Youtube

Paul
Author by

Paul

It is just a website. Life is somewhere else. Answers to downvoted question won't be accepted. Period. My wishlist The right syntax of with in Delphi: with r := obj.MyRecord do begin r.Field1 := 1; r.Field2 := '2'; // ... end; Favorites https://stackoverflow.blog/2019/10/17/imho-the-mythical-fullstack-engineer/ http://www.catb.org/esr/faqs/smart-questions.html Stackoverflow How to reduce image size on Stack Overflow Unicode Is there a list of characters that look similar to English letters? Windows How to programmatically get DLL dependencies Device misdetected as serial mouse Catch MSVCR120 missing error message in Delphi Get members of COM object via Delphi Olevariant type Controlling the master speaker volume in Windows 7 Filename timestamp in Windows CMD batch script getting truncated https://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory Linux How to control backlight by terminal command MS Visual Studio How to change "Visual Studio 2017" folder location? Delphi Convert a null-delimited PWideChar to list of strings Out-of-the-box flat borderless button TFDConnection.OnRecover is never fired when PostgreSQL stops TScrollBox with customized flat border color and width? How to redirect mouse events to another control? Creating object instance based on unconstrained generic type how to create a TCustomControl that behaves like Tpanel? https://stackoverflow.com/a/43990453 - How to hack into a read-only direct getter property With DDevExtensions you can disable storing Explicit... properties in the dfm https://github.com/RomanYankovsky/DelphiAST C Arrow operator (-&gt;) usage in C The Definitive C++ Book Guide and List GDI+ How to rotate Text in GDI+? GDI+ performance tricks MSXML schema validation with msxml in delphi How can I get English error messages when loading XML using MSXML Inno Setup: Save XML document with indentation PostgreSQL Checking for existence of index in PostgreSQL Web Will the IE9 WebBrowser Control Support all of IE9's features, including SVG? http://howtocenterincss.com MVC for Web, MVP for Winforms and MVVM for WPF. Just an observation: Most of the claims such as "I can't understand what you wrote", "Please provide more details", etc. are made by people with a relatively low SO score. People with the highest score on SO understand everything. Template: This is an abandoned question. Author has no longer anything to do with the topic and can neither approve nor decline your answer.

Updated on July 08, 2022

Comments

  • Paul
    Paul almost 2 years

    Let's imagine that we have a master branch.

    Then we create a newbranch

    git checkout -b newbranch
    

    and make two new commits to newbranch: commit1 and commit2

    Then we switch to master and make cherry-pick

    git checkout master
    git cherry-pick hash_of_commit1
    

    Looking into gitk we see that commit1 and its cherry-picked version have different hashes, so technically they are two different commits.

    Finally we merge newbranch into master:

    git merge newbranch
    

    and see that these two commits with different hashes were merged without problems although they imply that the same changes should be applied twice, so one of them should fail.

    Does git really do a smart analysis of commit's content while merging and decide that changes shouldn't be applied twice or these commits are marked internally as linked together?

  • cregox
    cregox over 10 years
    Actually, I'd say you should worry about merging and "git will handle it" is not a good rule of thumb.
  • donquixote
    donquixote over 10 years
    In fact the merge CAN result in duplicate content in some cases. Git does handle it sometimes, but sometimes it does not.
  • he_the_great
    he_the_great about 8 years
    This is horribly wrong. Got pretty much stores the file files in all condevable forms. And if I recall correctly SVN used to store snapshots.
  • helmbert
    helmbert about 8 years
    @he_the_great, no. SVN's skip-delta storage format (!= snapshots) is well documented in the manual. And I really don't get what you mean by condevable. I'm not a native speaker, but I'm pretty sure that's not a real word.
  • he_the_great
    he_the_great about 8 years
    @helmbert, sorry 'conceivable' is what I wanted. I unfortunately can't find any historic records about SVN's backend. But my main point is Git does use deltas.
  • helmbert
    helmbert about 8 years
    @he_the_great, again, no. Git storage internals are documented in-depth in various documentations, as for example here, here or here.
  • Peter Olson
    Peter Olson about 8 years
    @he_the_great But even as packfiles any given hash for a file results in the full file. Yes it compresses using deltas, but it is not a delta for the changes in a commit, but instead a delta between hashes for a file. As far as the commit object is concerned it is referencing a tree that is referencing the hash for a full file. That under the hood the data is compressed does not effect the way git works. Git stores complete files as far as a commit is concerned, SVN stores deltas for commits as I understand.
  • he_the_great
    he_the_great about 8 years
    @PeterOlson Sorry Locking my computer committed a started message. A hash is made from the whole file content, but you don't delta the hash because it doesn't contain all the data of the file. But as quoted, git does store deltas for similar files, "When Git packs objects, it looks for files that are named and sized similarly, and stores just the deltas from one version of the file to the next."
  • iTake
    iTake over 6 years
    great hint about rebase! it will 'skip' all cherry-picked commits automatically.
  • Imperishable Night
    Imperishable Night over 6 years
    Why did you condemn SVN's "apply each merged commit as a patch" method as "naive"? I find that sometimes git aligns the wrong parts of files, and I really hope that it were patch-based, so that at least the merge conflicts are easier to understand. Disclaimer: I don't actually use SVN.
  • helmbert
    helmbert over 6 years
    @ImperishableNight "naive" is this context was meant to be read as: "using the easy, obvious solution of applying each change from the to-be-merged branch as a patch (instead of Git's more complex three-way-merge) that would work most of the time, but not in the scenario that was stated in the original question (merging a branch from which individual changes have already been cherry-picked)."
  • David Lemon
    David Lemon almost 6 years
    Honestly, it sounds too good to be true, I have to see it with my eyes. Also rebase modifies commits, your last timeline should be ---Y---b2'---b4'
  • ice_chrysler
    ice_chrysler almost 5 years
    Works perfectly. Very helpful if you don't want to have the cherry-picked commits twice in history.
  • JHH
    JHH over 4 years
    Shouldn't it be noted that while rebase is beautiful, the danger with using it is that any forks or branches created from the old b will be out of sync, and users may need to resort to stuff like git reset --hard and git push -f?
  • ephemerr
    ephemerr over 4 years
    @JHH thats why we rebase local branch here
  • Jose V
    Jose V almost 4 years
    @JHH That is correct, but is it a danger? or just part of the workflow? I think it's not usually a big issue, I can imagine if the repo was super large and distributed then it might be but usually you are rebasing your own branches. E.g., here b is your branch that you are putting out of sync, but the branch that is usually shared, master, doesn't go out of sync at any time
  • JHH
    JHH almost 4 years
    Jose, for reviews it can be a pain since tracking differences between two reviewed versions could be difficult. Github, Gerrit etc usually deals with it though.
  • Ofek Shilon
    Ofek Shilon over 2 years
    @ephemerr There is nothing associating b1 and b3 on b to b1' and b3' on master. How can git know to eliminate b1 and b3 while rebasing?
  • ephemerr
    ephemerr over 2 years
    @OfekShilon they do not bring any changes so rebase removes them as empty ones
  • Ofek Shilon
    Ofek Shilon over 2 years
    @ephemerr the diff is taken from the parent commit, so to git it looks like they do bring changes.