如何git-cherry-pick只改变某些文件?

如果我想要合并到一个Git分支中,所做的更改只对在特定提交中更改的某些文件(包括对多个文件的更改)进行,那么如何实现这一点?

假设被调用的Git提交对文件ABCD进行了更改,但我只想将文件AB的更改合并。 这听起来像是一个git cherry-pick的工作,但cherry-pick只知道如何合并整个提交,而不是文件的一个子集。

我会用cherry-pick -n (– --no-commit ),它可以让你检查(和修改)之前提交结果:

 git cherry-pick -n <commit> # unstage modifications you don't want to keep, and remove the # modifications from the work tree as well. # this does work recursively! git checkout HEAD <path> # commit; the message will have been stored for you by cherry-pick git commit 

如果绝大多数的修改是你不想要的东西,而不是检查单个path(中间步骤),你可以重新设置一切,然后添加你想要的:

 # unstage everything git reset HEAD # stage the modifications you do want git add <path> # make the work tree match the index # (do this from the top level of the repo) git checkout . 

其他方法对我来说不起作用,因为提交对许多其他文件有很多变化和冲突。 我想到的是简单的

 git show SHA -- file1.txt file2.txt | git apply - 

它实际上并没有提供给你,所以你可能需要跟进

 git commit -c SHA 

也许这个方法优于Jefromi的答案是你不必记得git reset的哪个行为是正确的:)

  # Create a branch to throw away, on which we'll do the cherry-pick: git checkout -b to-discard # Do the cherry-pick: git cherry-pick stuff # Switch back to the branch you were previously on: git checkout - # Update the working tree and the index with the versions of A and B # from the to-discard branch: git checkout to-discard -- AB # Commit those changes: git commit -m "Cherry-picked changes to A and B from [stuff]" # Delete the temporary branch: git branch -D to-discard 

我通常使用-p标志与另一个分支的git checkout,我发现比我遇到的大多数其他方法更容易和更细化。

原则上:

 git checkout <other_branch_name> <files/to/grab in/list/separated/by/spaces> -p 

例:

 git checkout mybranch config/important.yml app/models/important.rb -p 

然后你会得到一个对话框,询问你想要在“blob”中进行哪些更改,这对于每一个连续的代码改变块都是可行的,然后你可以给每个代码块发信号(是) n (否)等等。

-ppatch选项适用于git中的各种命令,包括git stash save -p ,它允许您从当前工作中select要存储的内容

我有时使用这种技术,当我做了很多工作,并希望分离出来,使用git add -p提交更多基于主题的提交,并select我想要的每个提交:)

樱桃挑选是从特定的“提交”中select更改。 最简单的解决方法是挑选某些文件的所有更改即可使用

  git checkout source_branch <paths>... 

例如:

 $ git branch * master twitter_integration $ git checkout twitter_integration app/models/avatar.rb db/migrate/20090223104419_create_avatars.rb test/unit/models/avatar_test.rb test/functional/models/avatar_test.rb $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: app/models/avatar.rb # new file: db/migrate/20090223104419_create_avatars.rb # new file: test/functional/models/avatar_test.rb # new file: test/unit/models/avatar_test.rb # $ git commit -m "'Merge' avatar code from 'twitter_integration' branch" [master]: created 4d3e37b: "'Merge' avatar code from 'twitter_integration' branch" 4 files changed, 72 insertions(+), 0 deletions(-) create mode 100644 app/models/avatar.rb create mode 100644 db/migrate/20090223104419_create_avatars.rb create mode 100644 test/functional/models/avatar_test.rb create mode 100644 test/unit/models/avatar_test.rb 

来源和完整的解释http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

更新:

使用这种方法,git不会合并文件,它只会覆盖在目标分支上完成的任何其他更改。 您将需要手动合并更改:

$ git diff HEAD文件名

我会挑选一切,然后做这个:

 git reset --soft HEAD^ 

然后我会恢复我不想要的更改,然后进行新的提交。

我发现另一种方法可以防止在采摘樱桃时出现任何冲突的合并,而这种合并是易于记忆和理解的。 既然你实际上不是挑选一个提交,而是其中的一部分,你需要先分割它,然后创build一个满足你的需求的提交并挑选它。

首先创build一个分支,从你想要分割和检出它:

 $ git checkout COMMIT-TO-SPLIT-SHA -b temp 

然后恢复以前的提交:

 $ git reset HEAD~1 

然后添加你想樱桃挑选的文件/更改:

 $ git add FILE 

并承诺:

 $ git commit -m "pick me" 

注意提交散列,让我们把它叫做PICK-SHA,然后回到你的主分支,例如强制结帐的主人:

 $ git checkout -f master 

并挑选承诺:

 $ git cherry-pick PICK-SHA 

现在你可以删除临时分支了:

 $ git branch -d temp -f 

使用git merge --squash branch_name这将获得来自其他分支的所有更改,并将为您做好准备。 现在删除所有不需要的更改,并离开你想要的。 而git不会知道有一个合并。