问题
I have a question related to cherry-picking commits and conflicts.
The 'Pro Git' book explains that commits are kind of snapshots and not patches/diffs.
But cherry-picking commit may behave as it was a patch.
Example below, in short:
create 3 commits, each time edit first (and single) line of the file
reset the branch to first commit
test1 : try to cherry-pick third commit (conflict)
test 2: try to cherry-pick second commit (OK)
mkdir gitlearn
cd gitlearn
touch file
git init
Initialized empty Git repository in /root/gitlearn/.git/
git add file
#fill file by single 'A'
echo A > file && cat file
A
git commit file -m A
[master (root-commit) 9d5dd4d] A
1 file changed, 1 insertion(+)
create mode 100644 file
#fill file by single 'B'
echo B > file && cat file
B
git commit file -m B
[master 28ad28f] B
1 file changed, 1 insertion(+), 1 deletion(-)
#fill file by single 'C'
echo C > file && cat file
C
git commit file -m C
[master c90c5c8] C
1 file changed, 1 insertion(+), 1 deletion(-)
git log --oneline
c90c5c8 C
28ad28f B
9d5dd4d A
test 1
#reset the branch to 9d5dd4d ('A' version)
git reset --hard HEAD~2
HEAD is now at 9d5dd4d A
git log --oneline
9d5dd4d A
#cherry-pick 'C' version over 'A'
git cherry-pick c90c5c8
error: could not apply c90c5c8... C
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
#the conflict:
cat file
<<<<<<< HEAD
A
=======
C
>>>>>>> c90c5c8... C
test 2
#same for 'B' - succeeds
git reset --hard HEAD
HEAD is now at 9d5dd4d A
git cherry-pick 28ad28f
[master eb27a49] B
1 file changed, 1 insertion(+), 1 deletion(-)
Please explain why test 1 failed (I could imagine the answer if commits were patches, but snapshots?)
回答1:
The Pro Git book is correct: a commit is a snapshot.
You are also correct, though: git cherry-pick
applies a patch.
How can this be? The answer is that when you cherry-pick a commit, you also specify which parent commit to consider, with the -m parent-number
argument. The cherry-pick command then generates a diff against that parent, so that the resulting diff can be applied now.
Should you choose to cherry-pick a non-merge commit, there is only one parent, so you don't actually pass -m
and the command uses the (single) parent to generate the diff. But the commit itself is still a snapshot, and it's the cherry-pick
command that finds the diff of commit^1
(the first and only parent) vs commit
and applies that.
来源:https://stackoverflow.com/questions/27760257/cherry-picking-commit-is-commit-a-snapshot-or-patch