Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git cherry-pick does not just pick the diff of the commit

I have two branches: A and B.

  • A's commit history: a <- b <- c;
  • B's commit history: a <- h <- i;

Assume that there is only one file here.

  1. In commit b, I adds some texts like "foo".
  2. In commit c, I adds some texts like "bar".
  3. Then I git cherry-pick c on B branch. I thought cherry-pick will only pick the changes in c to branch B. However, it will add both foo and bar to branch B. Which is obviously not what I want.

Therefore, cherry-pick will pick all the changes of those files touched in commit c since the ancestor commit a. Is that right? What if I only want to pick the diff from b to c and apply it onto i?

Update the exact steps

  1. Init a git repo;
  2. Add file test.txt and issue the first commit init commit. test.txt is now:

    first line  
    second line
    
  3. Create a new branch dev but stay in branch master;

  4. Add added in commit b to the file and issue the commit b. test.txt is now:

    first line
    added in commit b
    second line
    
  5. Add added in commit c to the file and issue the commit c. test.txt is now:

    first line
    added in commit b
    added in commit c
    second line
    
  6. Check out dev branch and issue the commit h. test.txt is now:

    first line
    second line
    
    adding by commit h
    
  7. git cherry-pick <commit c SHA1 ID> to cherry-pick commit c onto commit h.

  8. The conflict message:

    index 6a8dc57,594c6ec..0000000
    @@@ -1,4 -1,4 +1,9 @@@
      first line
    ++<<<<<<< HEAD
    ++=======
    + added in commit b
    + added in commit c
    ++>>>>>>> 06ce9b1... commit c adding another line
      second line
     +
     +adding by commit h
    
  9. See? cherry-pick also brings the changed in commit b.

Thanks!

like image 608
tamlok Avatar asked Mar 03 '17 05:03

tamlok


People also ask

Does cherry pick remove commit?

This makes it useful for undoing changes, however, it's noteworthy to remember that cherry-picking will NOT delete the commit that was cherry-picked from the feature branch, so you will have to create a new feature branch and cherry-pick all your commits once more without the bug fix.

What does git cherry pick do?

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.

What happens when you cherry pick a merge commit?

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.


2 Answers

git cherry-pick tries to bring just one commit. But it does this by applying a patch which requires some context. The change done in commit C is very close to the change done by commit b, so you get the conflict - it can't just find the correct place where change has to be applied. And when you have conflict, you also get some of the conflicting context which is at least a part of your commit B.

Here's how it would work without the conflict:

$ git init
$ cat > f
line1
line2
line3
$ git add f
$ git commit -a -m "initial"
# Edited to add a line in the beginning of f
$ cat f
Commit b
line1
line2
line3
$ git commit f -m "B"
# Edited to add a line in the end of f
$ cat f
Commit b
line1
line2
line3
Commit c
$ git commit f -m "C"
$ git checkout HEAD^^
$ git cherry-pick master
$ cat f
line1
line2
line3
Commit c
like image 164
aragaer Avatar answered Oct 14 '22 22:10

aragaer


What if I only want to pick the diff from b to c and apply it onto i?

You can find/write the diff of a file between two commits (c..d). Then apply that in your current branch.

$ git checkout <B-branch>

# write the diff in a file named 'change.patch' (root directory) 
$ git diff <b-commit> <c-commit> <file-name> >> ~/changes.patch

$ git apply ~/changes.patch       # apply the changes
$ git add .

# merge the changes to i (previous commit)
$ git commit --amend -m 'Apply the diff of b and c'

$ git push -f origin HEAD      # force(-f) push since history is changed
like image 45
Sajib Khan Avatar answered Oct 14 '22 21:10

Sajib Khan