如何git-cherry-pick仅更改某些文件?

时间:2011-04-19 13:22:54

标签: git github cherry-pick

如果我想合并到Git分支中,只对某个特定提交中更改的某些文件进行了更改,其中包括对多个文件的更改,如何实现?

假设名为stuff的Git提交已对文件ABCD进行了更改,但我只想合并{{1}对文件stuffA进行了更改。这听起来像是B的工作,但git cherry-pick只知道如何合并整个提交,而不是文件的子集。

12 个答案:

答案 0 :(得分:568)

我会使用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

如果绝大多数修改是您不想要的,而不是检查单个路径(中间步骤),您可以重置所有内容,然后添加您想要的内容:

# 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 .

答案 1 :(得分:112)

其他方法对我不起作用,因为提交对很多其他文件有很多更改和冲突。我想出的只是

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

它实际上并不add文件或为您提交,因此您可能需要跟进

git add file1.txt file2.txt
git commit -c SHA

或者如果您想跳过添加,可以使用--cached参数git apply

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

答案 2 :(得分:56)

我通常使用-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

然后,您会看到一个对话框,询问您需要哪些更改&#34; blobs&#34;这几乎可以解决每个连续代码更改的问题,然后您可以为每个代码块发出y(是)n(否)等信号。

-ppatch选项适用于git中的各种命令,包括git stash save -p,可让您选择要隐藏在当前作品中的内容

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

答案 3 :(得分:41)

这种方法优于Jefromi's answer的优点可能是您不必记住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 -- A B

 # Commit those changes:
 git commit -m "Cherry-picked changes to A and B from [stuff]"

 # Delete the temporary branch:
 git branch -D to-discard

答案 4 :(得分:24)

Cherry选择是从特定的“提交”中选择更改。最简单的解决方案是选择使用某些文件的所有更改

 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 filename

答案 5 :(得分:11)

使用git merge --squash branch_name这将从其他分支获得所有更改,并为您准备提交。 现在删除所有不需要的更改并保留所需的更改。并且git不会知道合并。

答案 6 :(得分:10)

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

git reset --soft HEAD^

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

答案 7 :(得分:8)

情况:

您在自己的分支上,假设master,并且在其他任何分支上都有提交。您只需从该特定提交中选择一个文件即可。

方法:

步骤1:在所需分支上签出。

git checkout master

步骤2:确保已复制了所需的提交哈希。

git checkout commit_hash path\to\file

步骤3:现在,您可以在所需分支上更改所需文件。您只需要添加并提交即可。

git add path\to\file
git commit -m "Your commit message"

答案 8 :(得分:4)

我找到了另一种防止任何冲突合并的方式,这种方式可以让人很容易记住和理解。既然你实际上不是挑选提交,而是其中的一部分,你需要首先拆分它,然后创建一个适合你需要的提交,然后挑选它。

首先从要分割的提交中创建一个分支并将其签出:

$ 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

答案 9 :(得分:2)

将分支合并为新分支(压缩)并删除不需要的文件:

git checkout master
git checkout -b <branch>
git merge --squash <source-branch-with-many-commits>
git reset HEAD <not-needed-file-1>
git checkout -- <not-needed-file-1>
git reset HEAD <not-needed-file-2>
git checkout -- <not-needed-file-2>
git commit

答案 10 :(得分:1)

为了完整起见,最适合我的是:

paths :: Tree a -> [[a]]
paths Tip = []
paths (Bin Tip x Tip) = [[x]]
paths (Bin left x right) = map (x:) (paths left ++ paths right)

它完全符合OP的要求。它在需要时进行冲突解决,类似git show YOURHASH --no-color -- file1.txt file2.txt dir3 dir4 | git apply -3 --index - git status 的解决方法。它会merge,但不会add您的新更改。

答案 11 :(得分:0)

您可以使用:

git diff <commit>^ <commit> -- <path> | git apply

符号<commit>^指定<commit>的(第一个)父对象。因此,此diff命令选择在提交<path>中对<commit>所做的更改。

请注意,它不会提交任何内容(就像git cherry-pick一样)。因此,如果需要,您将必须这样做:

git add <path>
git commit