Am I misunderstanding git cherry-pick?
On reading the man page for git cherry-pick, my understanding is that it takes just the changes introduced by one commit, and you can then apply these changes pretty much anywhere.
So let's say I have a file that I build up over 4 commits like so:
line from commit 1
line from commit 2
line from commit 3
line from commit 4
If I then start another branch at commit 1, I should be able to get to
开发者_JAVA技巧line from commit 1
line from commit 4
by cherry-picking in commit 4
If I have that right, then why does it not work? I get a conflict, and then when I look at the conflict, it looks as if git is trying to pull in lines from commits 2,3,4. Here's the log of my work (skip to HERE'S THE MEAT to see the meat..):
szbwood-mbp15:proj5 bwood$ git init
Initialized empty Git repository in /Users/bwood/work/gitplay/proj5/.git/
szbwood-mbp15:proj5 bwood$ vi file1
szbwood-mbp15:proj5 bwood$ git add file1
szbwood-mbp15:proj5 bwood$ git commit -a
[master (root-commit) 4cb9b97] ..
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 file1
szbwood-mbp15:proj5 bwood$ vi file1
szbwood-mbp15:proj5 bwood$ git commit -a
[master 809d87c] ..
1 files changed, 1 insertions(+), 0 deletions(-)
szbwood-mbp15:proj5 bwood$ vi file1
szbwood-mbp15:proj5 bwood$ git commit -a
[master b534ac9] ..
1 files changed, 1 insertions(+), 0 deletions(-)
szbwood-mbp15:proj5 bwood$ vi file1
szbwood-mbp15:proj5 bwood$ git commit -a
[master fabc779] ..
1 files changed, 1 insertions(+), 0 deletions(-)
szbwood-mbp15:proj5 bwood$ git log
commit fabc7795fb660d55a7ad5636321b6180157954f7
Author: B
Date: Sun Nov 7 21:58:07 2010 -0800
..
commit b534ac9d1f8139fc7ffa9479a3d0cb0fd08c9508
Author: B
Date: Sun Nov 7 21:57:53 2010 -0800
..
commit 809d87c24b1c2d27354d6bfcb34d3a1981cb7ae5
Author: B
Date: Sun Nov 7 21:57:35 2010 -0800
..
commit 4cb9b97c3cae9b9551fa039f87e2fff5624fbbe3
Author: B
Date: Sun Nov 7 21:57:19 2010 -0800
..
szbwood-mbp15:proj5 bwood$ git checkout 4cb9b97c3cae9b9551fa039f87e2fff5624fbbe3
Note: checking out '4cb9b97c3cae9b9551fa039f87e2fff5624fbbe3'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 4cb9b97... ..
szbwood-mbp15:proj5 bwood$ git checkout -b new_branch
Switched to a new branch 'new_branch'
HERE'S THE MEAT
szbwood-mbp15:proj5 bwood$ more file1
line from commit 1
szbwood-mbp15:proj5 bwood$ git cherry-pick -x fabc7795fb660d55a7ad5636321b6180157954f7
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result with:
git commit -c fabc7795fb660d55a7ad5636321b6180157954f7
szbwood-mbp15:proj5 bwood$ more file1
line from commit 1
<<<<<<< HEAD
=======
line from commit 2
line from commit 3
line from commit 4
>>>>>>> fabc779... ..
szbwood-mbp15:proj5 bwood$
The problem here isn't that git's actually trying to insert content from commits 2 and 3, it's that the content from commit 4 is intertwined with that from commits 2 and 3. The patch for commit 4 looks something like this:
line from commit 1
line from commit 2
line from commit 3
+line from commit 4
(except given that this looks like a test case, I'm guessing you may not have any lines below there.)
So when git tries to apply that patch to the content of the file in commit 1, it says, hm, I need to insert this line after the line from commit 3. Uh oh, that's not here. Okay, where was that line in the file? It works backwards and manages to match it up, but knows something's fishy - it had to add lines that weren't part of the patch to get the patch to apply. The key idea here is that patches are applied by matching up their edges - a patch doesn't just say "add to the end of the file", it says "add after this line with this content".
So it gives you that conflict: the version in HEAD (commit 1) has nothing at this spot, and the version in commit 4 has those three lines. It's up to you to decide whether those two lines are "part of" the last line, and need to be brought along for the insertion to make sense, or whether they're separate from it, and can be removed. This is exactly the same thing you'll see with normal merge conflicts.
If you try this on an example where the patches are disjoint - commits 2 and 3 make changes several lines away from anything in commit 4, or better yet, in different files from commit 4 - you'll see the behavior you expect from cherry-pick. You're understanding the purpose completely correctly; you just have a messy test case.
精彩评论