Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cherry-picking a commit includes previous commits?

After finishing https://learngitbranching.js.org, I thought I got the idea of cherry-pick, but turned out that I didn't, at all.

I created a file abc.txt and made the commits like below:

(write a) ← (write b) ← (write c)[master][HEAD]

by which abc.txt became:

a
b
c

Now, making a branch from-a on (write a):

(write a)[from-a][HEAD] ← (write b) ← (write c)[master]

and cherry-picking (write c)[master], I thought that it would make abc.txt contain only a-line and c-line, i.e. like

a
c

but it actually resulted as:

a
<<<<<<< HEAD
=======
b
c
>>>>>>> 3a0882d... write c

Here my confusion is two-folded. Why does it conflict but not just adding the line(s)? Why does it contain b-line even though I cherry-picked only write c?

like image 577
akai Avatar asked May 06 '18 16:05

akai


2 Answers

Git is context aware and looks for the surrounding lines as well as the ones that are added/removed.

It makes sense, because git needs to know where should a change from commit be applied.

In your case, the branch from-a has the content

 a

Surrounding lines are empty.

The commit that you are trying to cherry-pick has the content like this:

diff --git a/abc.txt b/abc.txt
index 422c2b7..de98044 100644
--- a/abc.txt
+++ b/abc.txt
@@ -1,2 +1,3 @@
 a
 b
+c

Even if commit message shows a wider context around added/removed lines, git will only try to match the one line above and one line below modification. (Thanks das-g)

This means that git will try to find the line:

b

at the end of file and insert the line

c

after it.

Since on your branch from-a( current HEAD), git couldn't find the line

b

at the end of the file and therefore couldn't apply your patch cleanly, that resulted in conflict.

The text

<<<<<<< HEAD
=======
b
c
>>>>>>> 3a0882d... write c

represents the conflict at which git sees that the actual content at the end of a file is nothing, indicated by the

<<<<<<< HEAD
=======

but git expected to find the line

b

in order to add the line

c

after it, indicated by the

=======
b
c
>>>>>>> 3a0882d... write c

It is left like that for you to resolve conflict and decide how to join these 2 states.

When you have conflicts, you always look for the code between the pairs of <<<<<<< HEAD and >>>>>>>.
In between them, you will have ======= which separates the state on the current HEAD and the state that git expected after applying the patch.

like image 157
Iskustvo Avatar answered Oct 14 '22 08:10

Iskustvo


cherry-pick is a merge.

commit c differs from cs base commit, it adds line c.

commit a also differs from c's base commit, it removes line b.

                          file  [b]
                          ----
                          a
                          b


   file [a]                                  file [c]
   ----                                      ----
   a                                         a
                                             b
                                             c

Since the two change hunks overlap, Git presumes the affected lines might be related, since semantic entities in source code often occupy multiple lines you might be adding to an entity in one change and removing the entire entity in the other, line c might somehow be related to line b, and if you're deleting b you might not want to add c either.

like image 25
jthill Avatar answered Oct 14 '22 07:10

jthill