无法选择提交更改不存在的文件

问题描述

我想知道为什么 git 不允许挑选对不存在的文件进行更改的提交。 我的理解是提交代表工作目录的完整快照。因此,挑选包含当前不存在的文件的提交应该简单地创建该文件 - 但我可以看到情况并非如此。

下面是几个命令来重现我所说的情况。

$ 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:我不是在寻找“解决方案”,我只是想了解为什么 git 认为这是一个冲突。

解决方法

如果您查看 cherry-pick 命令的文档(参见例如 git cherry-pick --help),描述是“应用一些现有提交引入的更改”。换句话说,这会查看选定的提交及其父提交,计算两者之间的差异,并尝试将该更改应用到您当前的分支。

您尝试 cherry-pick 的提交引入的更改会影响不存在的文件,因此无法应用。

如果您只想要源代码提交中存在的文件,您可以:

git checkout 9ea19 test
,

请记住,cherry-pick 在技术上是一种三向合并。您运行 git cherry-pick C,对于某些提交 C(通常由哈希 ID 指定),Git 找到提交 P 的父 C

  • commit P 现在是合并基础;
  • ours 提交是 当前 (HEAD) 提交;和
  • theirs 提交是提交 C

PHEAD 之间的区别在于相关文件已被完全删除。 PC 的区别在于文件内容被修改了。

对于标准合并算法 (git-merge-recursive),这是一个高级树级冲突:修改/删除冲突。这是一个无法用 -X ours-X theirs 解决的合并冲突。因此合并会在中间停止,留下必须解决的合并冲突。

解决合并冲突并运行 git cherry-pick --continue 以完成挑选。您解决此合并冲突的方式取决于您; larsks answer 中的 git checkout 命令很好,或者您可以使用 git checkout --theirs testgit add test。请注意,当使用 git checkout --ours(在这种情况下不适用)和 git checkout --theirs 时,Git 不会将冲突标记为已解决,但是当使用 git checkout CHERRY_PICK_HEAD(或原始哈希 ID)时,Git does 标记冲突已解决。这是由于 git checkout 实现中的一个怪癖。