如果我想将仅对特定提交中更改的部分文件(包括对多个文件的更改)进行的更改合并到Git分支中,如何实现这一点?

假设名为stuff的Git提交对文件A、B、C和D进行了更改,但我只想将stuff的更改合并到文件A和B。这听起来像Git cherry-pick的工作,但cherry pick只知道如何合并整个提交,而不是文件的子集。


当前回答

与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

其他回答

其他方法对我不起作用,因为提交时对很多其他文件进行了大量更改和冲突。我想到的只是

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

它实际上并没有为您添加文件或进行提交,因此您可能需要使用

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

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

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

您也可以对整个目录执行相同的操作

git show SHA -- dir1 dir2 | git apply -

我找到了另一种方法来防止樱桃采摘上的任何冲突合并,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

您可以使用:

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

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

注意,这还不会提交任何内容(正如gitcherry-pick所做的那样)。所以,如果你想这样做,你必须做到:

git add <path>
git commit

情况:

你在你的分支上,比如说,你在任何其他分支上都有你的承诺。您只能从该特定提交中选择一个文件。

方法:

步骤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 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