假设名为“stuff”的Git提交对文件A、B、C和D进行了更改,但我只想将“stuff”对文件A和B的更改合并。这听起来像是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
如果大部分的修改都是你不想要的,那么你可以重置所有内容,然后再添加你需要的内容,而不是检查单个路径(中间步骤):
# 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 checkout .
之外,我建议还要使用 git clean -f
命令,以删除由挑选的提交引入的任何新但不需要的文件。 - rlatgit add -p
命令,它可以让你交互式地决定要将哪些更改添加到每个文件的索引中。 - matthaeusgit reset -p HEAD
来选择性地取消暂存。这相当于 add -p
,但很少有人知道它的存在。 - Patrick Schlüter其他方法对我没用,因为提交有很多变更和与许多其他文件的冲突。我的做法很简单:
git show SHA -- file1.txt file2.txt | git apply -
实际上它不会为你添加
文件或提交,因此您可能需要跟进它
git add file1.txt file2.txt
git commit -c SHA
或者,如果您想跳过添加操作,可以使用--cached
参数来执行git apply
git show SHA -- file1.txt file2.txt | git apply --cached -
你也可以对整个目录执行相同的操作
git show SHA -- dir1 dir2 | git apply -
show SHA -- file | apply
不就和Mark Longair的回答中的checkout SHA -- file
基本上是一样的吗? - Tobias Kienzlercheckout SHA -- file
将会精确地检出 SHA 版本,而 show SHA -- file | apply
只会应用 SHA 中的更改(就像 cherry-pick 一样)。这很重要,因为(a)源分支中有多个提交更改了给定文件,或者(b)当前目标分支中有一个提交更改了该文件。 - Michael Andersongit revert
会撤销整个提交)。在这种情况下,只需使用命令git show -R SHA -- file1.txt file2.txt | git apply -
。 - Michael Andersongit diff SHA -- file1.txt file2.txt | git apply -
means apply all the differences between the current version of the file and the version at SHA to the current version. In essence it is the same as git checkout SHA -- file1.txt file2.txt
. See my earlier comment for why that is different to what the git show
version.” 的意思是:这句话的意思与之前说的不同。“git diff SHA -- file1.txt file2.txt | git apply -”的意思是将文件当前版本和SHA版本间的所有差异应用到当前版本,本质上与“git checkout SHA -- file1.txt file2.txt”相同。详见我之前发表的评论,了解为什么与“git show”版本不同。 - Michael Andersongit apply -3 -
而不是仅使用 git apply -
,这样如果发生冲突,你可以使用标准的冲突解决技巧,包括使用 git mergetool
。 - qwertzguy通常我会使用-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
接着会弹出一个对话框,询问您要在哪些“代码块”中进行更改,这基本上是每个连续代码更改的一部分,然后您可以为每个代码块发出信号 y
(是)n
(否)等。
-p
或patch
选项适用于git中的各种命令,包括git stash save -p
,它允许您选择要从当前工作区中存储的内容。
我有时会在完成大量工作并希望将其分离出来并提交到更具主题性的提交中时使用此技术,使用git add -p
并选择每个提交所需的内容 :)
git-add -p
命令,但我不知道 git-checkout
命令也有一个 -p
选项。这个选项是否解决了非 -p
答案中提到的合并问题? - Tobias Kienzler-p
选项可以允许手动编辑这样一个冲突的部分,而cherry-pick
也可能会产生。下次需要时我会测试一下,这绝对是一个有趣的方法。 - Tobias Kienzlergit reset -p HEAD
还允许使用 -p
选项,当您只想从索引中删除一些补丁时,这个选项非常方便。 - Patrick Schlüter情况:
您在分支上,假设为master
,并且您有一个提交在任何其他分支上。 您必须从该特定提交中选择一个文件。
方法:
步骤1:切换到所需的分支。
git checkout master
步骤2:确保您已复制所需的提交哈希值。
git checkout commit_hash path\to\file
步骤三:现在你已经在你想要的分支上有了所需文件的更改。你只需要将它们添加并提交。
git add path\to\file
git commit -m "Your commit message"
也许这种方法比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 -- 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
git checkout to-discard -- A B
会覆盖当前的 A 和 B,还是与当前的 A 和 B 合并? - Yves挑选特定"提交(commit)"中的更改被称为"cherry-pick"。最简单的解决方案是选择特定文件的所有更改,可以使用
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 checkout e0032947bd37f44044962ae2f7229d339944f83c example.txt
- Rishi Kulshreshthagit show YOURHASH --no-color -- file1.txt file2.txt dir3 dir4 | git apply -3 --index -
merge
一样。它会执行git add
,但不会执行git commit
,所以请检查你的git status
。3
是什么意思吗(... git apply -3 --index ...
)? - Dan Nissenbaum-3
代表使用“三方合并回退”功能。在实践中,这意味着Git可以插入常见的冲突标记,或者绕过已经被应用的更改。默认的git apply
行为对我来说太严格了,它会拒绝应用任何细微差别上的整个补丁。 - kubanczykgit checkout <branch|hash> -- path/to/file1 path/to/filen
我只想挑选所有东西,然后这样做:
git reset --soft HEAD^
然后我会还原我不想要的更改,再进行新的提交。
使用 git merge --squash branch_name
命令,它将获取另一个分支上的所有更改,并为您准备一个提交。现在删除所有不需要的更改,只保留您想要的更改即可。这样 Git 将不知道有任何合并操作发生过。
git gui
可用,那我会像Cascabel一样操作。如果不行的话,Tyrone Wilson的方法对于精细选择变更是不错的选择。 - undefined