2

I'm wondering why git doesn't allow cherry-picking a commit that introduces changes to a file that doesn't exist. My understanding is that a commit represents a full snapshot of working directory. So cherry-picking a commit containing file that currently doesn't exist should simply create that file - but I can see that it's not the case.

Below is a couple of commands to reproduce the situation I'm talking about.

$ git init
Initialized empty Git repository in /home/mzakrze/workspace/tmp/.git/
$ echo "Hello world!" > first_file; git add first_file; git commit -m "Init commit"
[master (root-commit) 7f9478a] Init commit
 1 file changed, 1 insertion(+)
 create mode 100644 first_file
$ echo "Fox jumps over the layz dog" > test; git add test; git commit -m "Commit with a typo"
[master 776387b] Commit with a typo
 1 file changed, 1 insertion(+)
 create mode 100644 test
$ echo "Fox jumps over the lazy dog" > test; git add test; git commit -m "Fix typo"
[master 9ea19df] Fix typo
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log 
commit 9ea19dfe2597b28eb576e2682e745de3da74733f
Author: mzakrze <xxxxxx@gmail.com>
Date:   Sun Apr 11 17:01:13 2021 +0200

    Fix typo

commit 776387b563edba9df2a12c5d1a2fd5bffb10c643
Author: mzakrze <xxxxxx@gmail.com>
Date:   Sun Apr 11 17:00:53 2021 +0200

    Commit with a typo

commit 7f9478a83e3938bf57552c1b90ddc7322b1bf315
Author: mzakrze <xxxxxx@gmail.com>
Date:   Sun Apr 11 16:59:04 2021 +0200

    Init commit
$ git reset --hard 7f9478a83e3938bf57552c1b90ddc7322b1bf315
HEAD is now at 7f9478a Init commit
$ git cherry-pick 9ea19 # cherry-pick "Fix typo"
error: could not apply 9ea19df... Fix typo
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'

INB4: I'm not looking for a "solution", I just want to understand why git thinks it's a conflict.

mzakrze
  • 53
  • 3
  • Pretty much a duplicate of e.g. https://stackoverflow.com/questions/60847892/git-cherry-pick-weird-issue-sometimes-conflicts-but-sometimes-not – matt Apr 11 '21 at 22:33

2 Answers2

4

If you look at the documentation for the cherry-pick command (see e.g. git cherry-pick --help), the description is "Apply the changes introduced by some existing commits". In other words, this looks at the selected commit and its parent, computes the diff between the two, and attempts to apply that change to your current branch.

The change introduced by the commit you're trying to cherry-pick affects a file that doesn't exist, so it can't be applied.

If you simply want the file as it exists in the source commit, you can:

git checkout 9ea19 test
larsks
  • 277,717
  • 41
  • 399
  • 399
1

Remember that cherry-pick is technically a three-way merge. You run git cherry-pick C, for some commit C—often specified by a hash ID—and Git finds the parent P of commit C:

  • commit P is now the merge base;
  • the ours commit is the current (HEAD) commit; and
  • the theirs commit is commit C.

The difference between P and HEAD is that the file in question has been deleted entirely. The difference between P and C is that the content of the file has been modified.

For the standard merge algorithm (git-merge-recursive), this is a high level or tree level conflict: a modify/delete conflict. That's a merge conflict that cannot be resolved with -X ours or -X theirs. The merge therefore stops in the middle, leaving you with a merge conflict that you must resolve.

Resolve the merge conflict and run git cherry-pick --continue to finish the cherry-pick. The way you resolve this merge conflict is up to you; the git checkout command in larsks answer is fine, or you can use git checkout --theirs test and git add test. Note that when using git checkout --ours (not applicable in this case) and git checkout --theirs, Git does not mark the conflict resolved, but when using git checkout CHERRY_PICK_HEAD (or a raw hash ID), Git does mark the conflict resolved. This is due to a quirk in the implementation of git checkout.

torek
  • 448,244
  • 59
  • 642
  • 775