如果我想将仅对特定提交中更改的部分文件(包括对多个文件的更改)进行的更改合并到Git分支中,如何实现这一点?
假设名为stuff的Git提交对文件A、B、C和D进行了更改,但我只想将stuff的更改合并到文件A和B。这听起来像Git cherry-pick的工作,但cherry pick只知道如何合并整个提交,而不是文件的子集。
如果我想将仅对特定提交中更改的部分文件(包括对多个文件的更改)进行的更改合并到Git分支中,如何实现这一点?
假设名为stuff的Git提交对文件A、B、C和D进行了更改,但我只想将stuff的更改合并到文件A和B。这听起来像Git cherry-pick的工作,但cherry pick只知道如何合并整个提交,而不是文件的子集。
当前回答
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文件名
其他回答
我找到了另一种方法来防止樱桃采摘上的任何冲突合并,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
现在可以删除临时分支:
$ git branch -d temp -f
与Jefromi的答案相比,这种方法的优势可能在于您不必记住git重置的哪个行为是正确的:)
# 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
使用修补程序标志签出
完成您所描述内容的一个简单方法是通过签出补丁。修改我在顶部提供的四个变量。脚本执行以下操作:
克隆包含提交的分支(源分支)签出要将文件移动到的分支(目标分支)在所需的提交版本签出源分支,提供补丁标志和文件的相对位置作为参数。添加、提交、推送
对我来说,这一直是最简单的方法。步骤#3确实创建了一个交互式shell,但如果你想破坏目标,你可以默认整个选项。
source_branch=branch_with_file_you_want
destination_branch=file_go_here
rev=757c47d4
relative_file_path=structures/serializers/node.py
message="Patching a file from $source_branch to $destination_branch"
git clone https://github.com/yourepo/app.git -b $source_branch $source_branch
cd $source_branch
git checkout $destination_branch
git checkout $rev --patch $source_branch $relative_file_path
git add $relative_file_path
git commit -m "$message"
git push
如果您是远程GitLab,如果您需要MR,可以使用git push-o merge_request.create
您可以使用:
git diff <commit>^ <commit> -- <path> | git apply
符号<commit>^指定<commit>的(第一个)父级。因此,这个diff命令选择在commit<commit>中对<path>所做的更改。
注意,这还不会提交任何内容(正如gitcherry-pick所做的那样)。所以,如果你想这样做,你必须做到:
git add <path>
git commit
自动化程度更高:
#!/usr/bin/env bash
filter_commit_to_files() {
FILES="$1"
SHA="$2"
git show "$SHA" -- $FILES | git apply --index -
git commit -c "$SHA"
}
示例用法:
filter_commit_to_files "file1.txt file2.txt" 07271c5e
我通过复制并粘贴到外壳中来定义它。您不需要here文档。