git cherry-pick 不只是选择提交的差异

git cherry-pick does not just pick the diff of the commit

我有两个分支:AB

假设这里只有一个文件。

  1. 在提交 b 中,我添加了一些文本,例如 "foo"。
  2. 在提交 c 中,我添加了一些文本,例如 "bar"。
  3. 然后我 git cherry-pick cB 分支。我以为 cherry-pick 只会选择 c 中的更改来分支 B。但是,它会将 foobar 添加到分支 B。这显然不是我想要的。

因此,cherry-pick 将选择自祖先提交 a 以来提交 c 中涉及的那些文件的所有更改。那正确吗?如果我只想选择从 bc 的差异并将其应用到 i 怎么办?

更新确切步骤

  1. 初始化一个 git 回购;
  2. 添加文件 test.txt 并发出第一个提交 init committest.txt 现在是:

    first line  
    second line
    
  3. 创建一个新分支 dev 但留在分支 master;

  4. added in commit b 添加到文件并发出提交 btest.txt 现在是:

    first line
    added in commit b
    second line
    
  5. added in commit c 添加到文件并发出提交 ctest.txt 现在是:

    first line
    added in commit b
    added in commit c
    second line
    
  6. 签出 dev 分支并发出提交 htest.txt 现在是:

    first line
    second line
    
    adding by commit h
    
  7. git cherry-pick <commit c SHA1 ID> 挑选提交 c 到提交 h.

  8. 冲突信息:

    index 6a8dc57,594c6ec..0000000
    @@@ -1,4 -1,4 +1,9 @@@
      first line
    ++<<<<<<< HEAD
    ++=======
    + added in commit b
    + added in commit c
    ++>>>>>>> 06ce9b1... commit c adding another line
      second line
     +
     +adding by commit h
    
  9. 看到了吗? cherry-pick 也会在提交 b.

  10. 中带来更改

谢谢!

What if I only want to pick the diff from b to c and apply it onto i?

您可以 find/write 两次提交 (c..d) 之间的文件 diff。然后在您当前的分支中应用它。

$ git checkout <B-branch>

# write the diff in a file named 'change.patch' (root directory) 
$ git diff <b-commit> <c-commit> <file-name> >> ~/changes.patch

$ git apply ~/changes.patch       # apply the changes
$ git add .

# merge the changes to i (previous commit)
$ git commit --amend -m 'Apply the diff of b and c'

$ git push -f origin HEAD      # force(-f) push since history is changed

git cherry-pick 尝试只提交一次。但它通过应用需要一些上下文的补丁来做到这一点。提交 C 中所做的更改与提交 b 中所做的更改非常接近,因此您会遇到冲突 - 它不能只找到必须应用更改的正确位置。当你有冲突时,你也会得到一些冲突的上下文,这至少是你提交 B 的一部分。

如果没有冲突,它是这样工作的:

$ git init
$ cat > f
line1
line2
line3
$ git add f
$ git commit -a -m "initial"
# Edited to add a line in the beginning of f
$ cat f
Commit b
line1
line2
line3
$ git commit f -m "B"
# Edited to add a line in the end of f
$ cat f
Commit b
line1
line2
line3
Commit c
$ git commit f -m "C"
$ git checkout HEAD^^
$ git cherry-pick master
$ cat f
line1
line2
line3
Commit c