1

Note: It was a mistake from my side. I cherry-picked the parent hash. Please see the update section.
Original Question:
I have a file vmu_hw_test in a branch "test_imu" which has a change similar to seen below

if( g_imu_spi.readFromFifo() == 0)
{
    //Find local maxima and minima event
    g_imu_spi.compute_event();
    //compute the euler
    g_imu_spi.compute_euler();
    //From the average values compute the max
    //g_imu_spi.compute_Max();
    g_imu_spi.compute_Max(buffer);
}

The if statement and the removal of comment were introduced on this commit.
And master branch had

//Find local maxima and minima event
g_imu_spi.compute_event();
//compute the euler
g_imu_spi.compute_euler();
//From the average values compute the max
g_imu_spi.compute_Max(buffer);

Question
1. As I've read cherry-pick takes a single commit change and applies it. Is there a problem if the branches are different (in commit history)
2. A Microsoft document says not to cherry pick. Is it a bad practice to cherry pick?
3. Why would have cherry pick failed? (Update: It did not.)

Git Diff
For the latest commit on test_imu.c

diff --git a/Src/vmu_hw_test.c b/Src/vmu_hw_test.c
index 14b0a67..1954d64 100644
--- a/Src/vmu_hw_test.c
+++ b/Src/vmu_hw_test.c
@@ -2694,14 +2694,16 @@ unsigned short  IMU_sendData(void)
                }
            }
    //Regular run
-                               g_imu_spi.readFromFifo();
-                               //Find local maxima and minima event
-                               g_imu_spi.compute_event();
-                               //compute the euler
-                               g_imu_spi.compute_euler();
-                               //From the average values compute the max
-//                             g_imu_spi.compute_Max();
-                               g_imu_spi.compute_Max(buffer);
+                               if( g_imu_spi.readFromFifo() == 0)
+                               {
+                                   //Find local maxima and minima event
+                                   g_imu_spi.compute_event();
+                                   //compute the euler
+                                   g_imu_spi.compute_euler();
+                                   //From the average values compute the max
+                                   g_imu_spi.compute_Max(buffer);
+                               }
+

Update
Git cherry-pick did not fail. I tried looking into the diffs as suggested by torek and found that the diffs do state that a cherry pick should have included the if statement.
Here's the git diff --find-renames <hash-of-B> <hash-of-C> (please refer to torek's answer)

unsigned short  IMU_sendData(void)    
{
@@ -2703,7 +2731,6 @@ unsigned short  IMU_sendData(void)
                                //compute the euler
                                g_imu_spi.compute_euler();
                                //From the average values compute the max
-//                             g_imu_spi.compute_Max();
                                g_imu_spi.compute_Max(buffer);

                    //Low pass filter for each axis
@@ -2741,28 +2768,8 @@ unsigned short  IMU_sendData(void)
        }
    }

And the git diff --find-renames <hash-of-B> <hash-of-A> is already provided in the Git Diff section. From this we can see that the if statement should be cherry picked.

What went wrong was that I cherry picked the wrong hash (I picked the parent hash).

clamentjohn
  • 3,417
  • 2
  • 18
  • 42
  • Well, interactive rebase is basically cherry picking with a nicer interface – Mad Physicist Aug 16 '18 at 05:18
  • Cherry pick applies the *changes* introduced by the commit(s) you cherry pick, not the final state. Could it be that the if-statement wasn't introduced in the commit(s) you chose? – Lasse V. Karlsen Aug 16 '18 at 05:26
  • It was introduced in the commit I cherry picked. – clamentjohn Aug 16 '18 at 05:27
  • Can you add the appropriate commit diff output by `git show ` (where `` is the commit you're cherry picking?) – Timshel Aug 16 '18 at 05:28
  • @Timshel Added a git diff. Also is it bad to share my SHA hash publicly? – clamentjohn Aug 16 '18 at 05:50
  • 1
    The hash itself is only of use to someone who has a copy of your repository, including that particular commit. If the repository is public, it's useful; if not, it's not. – torek Aug 16 '18 at 05:51
  • 1
    Instead of showing partial, conflicting, and edited evidence, could you perhaps show the actual evidence you're looking at? Your presentation here makes the situation much more confusing than the one you're actually looking at yourself. – jthill Aug 16 '18 at 12:05
  • @jthill I have a feeling I messed up and took the parent commit's hash as `git cherry-pick `. And posted the `git diff` of the latest commit. Because when I tried `cherry picking` now, I get the `if statement` after the merge. I can close this question as it's misleading. – clamentjohn Aug 16 '18 at 15:23
  • Correcting the evidence would preserve a good answer as torek guessed what was really going on, but it'd be more work for you. I'd like to see it fixed or closed, either would be helpful. – jthill Aug 16 '18 at 17:17

1 Answers1

6

git cherry-pick works by merging—but the inputs to the merge are a bit unusual.

Specifically, with a normal, typical merge, we start with the commit graph, from which we find what you have done on your branch, vs what someone else has done on their branch:

             A--B--C   <-- you (HEAD)
            /
...--o--o--*
            \
             D--E--F   <-- them

Each round node, or *, or uppercase letter, represents a commit (the actual commits have commit hash IDs, which are are too unwieldy for ordinary humans to work with). Here, commit * is the common starting point, so for Git to combine your changes on your branch, Git must compare commit C—your latest work—to commit *, to see what you changed:

git diff --find-renames <hash-of-*> <hash-of-C>   # what you changed

Likewise, Git must compare commit F—their latest work—to commit *, to see what they changed:

git diff --find-renames <hash-of-*> <hash-of-F>   # what they changed

Git can now combine the two sets of changes. If you modified line 12 of some file, but they did not, Git takes your change. If they modified line 20 of that same file, but you did not, Git takes their change. Both changes get applied to that one file as it appears in commit *, to make the merged version of that file.

(For a real merge, eventually, Git makes a merge commit, which remembers both branch tips, but for cherry-pick that does not happen.)

Cherry-pick uses this same merge machinery to accomplish a cherry-pick, but this time, the merge base is not some common starting commit. Instead, it's the parent of the commit whose name or hash ID you give to git cherry-pick:

...--o--o--o--o--A   <-- master (HEAD)
      \
       o--o--B--C   <-- test_imu

If you are in this situation, with commit A being your current commit because you are on master, and you issue the command:

git cherry-pick test_imu

Git makes a merge with the merge base being commit B—the parent of commit C, which is the commit you are picking—and commits C and A being the two commits that get compared:

git diff --find-renames <hash-of-B> <hash-of-A>   # what you did
git diff --find-renames <hash-of-B> <hash-of-C>   # what they did

Git now combines these changes. You get a merge conflict where you both made differing changes, but to the same line(s) of the same file.

If the if test is removed by going from commit B to commit A, but nothing in B-to-C touches the if test, Git assumes that the correct action is to keep the removal of the if test. The only way to know for sure why Git did what Git did, though, is to look at the three inputs, e.g., by running those two git diff commands.

I find it quite helpful to set merge.conflictStyle to diff3, so that when there is a conflict, Git includes the base-commit file section, as well as the two conflicting changes. This often makes it unnecessary to look at commit B directly. In particularly complex cases, though, you may want to look at all three inputs.

torek
  • 448,244
  • 59
  • 642
  • 775
  • This is a great answer, thank you! Is it possible to raise an `issue` on git to include a feature like what I expected it to be? I couldn't find a `issues` tab for github git repo – clamentjohn Aug 16 '18 at 06:17
  • Also, how to see the git diff file-rename of a specific file? /Src/file doesn't work – clamentjohn Aug 16 '18 at 06:19
  • 1
    The GitHub copy of Git is just a mirror; Git has its own mailing list, with its own protocol. If there's a rename that `--find-renames` finds, it's a bit tricky to diff just the one file (Git has to compare the entire tree to *find* the rename), but you can redirect `git diff` output somewhere and inspect that separately. – torek Aug 16 '18 at 06:31
  • Great answer @torek! However, doesn't the `git diff` output that @Clament John added to the question suggest that the `if` statement **is** being touched in the `B`-to-`C` commit? I'm a bit unsure about how this could be happening if the `if` statement is only being introduced in the `cherry-pick` commit... it should be a merge conflict at least. – Timshel Aug 17 '18 at 00:47
  • @Timshel: we need to see the `git diff` output between the merge base and the `HEAD` commit. The original quoted text in the question doesn't match the added diff text either, which suggests there might be some sort of transcription issues. See also https://stackoverflow.com/questions/51870015/git-cherry-pick-failed-to-pick-the-right-changes/51870145?noredirect=1#comment90712453_51870015 – torek Aug 17 '18 at 00:53
  • @torek My apologies. I've updated the question to state that it was my mistake. Should I remove the question as it might be misleading? – clamentjohn Aug 17 '18 at 05:32
  • @ClamentJohn: Well, it's up to you, but at this point the question has all the information in it to help someone else recover from a similar error... – torek Aug 17 '18 at 05:39