如果我想合并到Git分支中,而仅对某些提交中的某些文件所做的更改(包括对多个文件的更改)进行更改,那么如何实现呢?
假设git的承诺称为stuff
具有对文件的改变A
,B
,C
,和D
,但我想只合并stuff
的对文件的更改A
和B
。这听起来像是一项工作,git cherry-pick
但cherry-pick
只知道如何合并整个提交,而不是文件的子集。
如果我想合并到Git分支中,而仅对某些提交中的某些文件所做的更改(包括对多个文件的更改)进行更改,那么如何实现呢?
假设git的承诺称为stuff
具有对文件的改变A
,B
,C
,和D
,但我想只合并stuff
的对文件的更改A
和B
。这听起来像是一项工作,git cherry-pick
但cherry-pick
只知道如何合并整个提交,而不是文件的子集。
Answers:
我可以使用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 add -p
它可以交互地决定要向每个文件
git reset -p HEAD
。它相当于,add -p
但是很少有人知道它的存在。
其他方法对我不起作用,因为提交有很多更改,并且与许多其他文件存在冲突。我想出的只是
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 -
您还可以对整个目录执行相同的操作
git show SHA -- dir1 dir2 | git apply -
checkout SHA -- file
将签正好在SHA版本,而show SHA -- file | apply
将只适用于SHA(就像摘樱桃一样)的变化。重要的是:(a)在源分支中有多个提交更改了给定文件,或者(b)在当前目标分支中有一个更改更改了文件。
git revert
撤消整个提交)。在这种情况下,请使用git show -R SHA -- file1.txt file2.txt | git apply -
git diff SHA -- file1.txt file2.txt | git apply -
意味着将文件的当前版本和SHA上的版本之间的所有差异应用于当前版本。本质上,它与git checkout SHA -- file1.txt file2.txt
。请参阅我先前的评论,以了解为何与git show
版本不同。
git apply -3 -
而不是just git apply -
,如果发生冲突,则可以使用标准的冲突解决技术,包括使用git mergetool
。
我通常将-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”中进行哪些更改,这几乎可以解决连续代码更改的每个块,然后您可以为每个代码块发出y
(是)n
(否)等信号。
该-p
或patch
选项可用于各种Git中包括的命令git stash save -p
,它允许你选择你想从你目前的工作来隐藏什么
当我做了很多工作时,有时我会使用这种技术,想将其分离出来,并使用git add -p
每次提交选择我想要的内容来提交更多基于主题的提交:)
-p
将允许对这样一个冲突的部分进行手动编辑,cherry-pick
无论如何也可能会产生结果。下次需要时,我将进行测试,这绝对是一种有趣的方法
git reset -p HEAD
还允许-p
仅在从索引中删除一些补丁时可以方便地使用。
也许这种方法优于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
cherry-pick
和直接使用git checkout stuff -- A B
?并与git commit -C stuff
提交信息将保持不变,以及
stuff
没有被修改你的当前分支或共同祖先之间的任何地方HEAD
,并stuff
和尖端stuff
。如果有,则cherry-pick
创建正确的结果(本质上是合并的结果),而您的方法将丢弃当前分支中的更改,并保留所有更改,从公共祖先一直到stuff
-不仅限于此单次提交。
stuff
樱桃选择的结果将离开,A
并且B
其内容与提交中的内容不同stuff
。但是,如果只是一样的话,那么您是对的-您可以按照自己的意愿去做。
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文件名
情况:
假设您在您的分支上,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"
使用git merge --squash branch_name
它将从另一个分支获取所有更改,并为您准备一个提交。现在,删除所有不需要的更改,然后保留所需的更改。git不会知道有合并。
我发现了另一种方法,可以防止在进行樱桃选择时发生任何冲突合并,而IMO则很容易记住和理解。由于实际上您不是在挑选承诺,而是一部分承诺,因此您需要先将其拆分,然后创建一个满足您需求的承诺并挑选承诺。
首先从要拆分的提交中创建一个分支,并检出它:
$ git checkout COMMIT-TO-SPLIT-SHA -b temp
然后还原先前的提交:
$ git reset HEAD~1
然后添加您想要选择的文件/更改:
$ git add FILE
并提交:
$ git commit -m "pick me"
注意提交哈希,我们称其为PICK-SHA,然后回到您的主分支,例如master强制结帐:
$ git checkout -f master
然后选择提交:
$ git cherry-pick PICK-SHA
现在您可以删除temp分支:
$ git branch -d temp -f
git checkout .
我还建议git clean -f
您删除经过精心挑选的提交所引入的所有新文件,但这些文件是不需要的。