如何只挑选一个文件的更改,而非整个提交的更改?

135

我需要将一个分支引入的更改应用到另一个分支上。我可以使用cherry-pick来完成。但是,在我的情况下,我只想应用与一个文件相关的更改,而不需要挑选整个提交。 如何做到这一点?


7
可能是 如何 git-cherry-pick 只选取特定文件的更改? 的重复问题。 - Potherca
10个回答

172

根据您想要实现的目标,您有不同的选项:

如果您希望文件内容与目标分支上的内容相同,则可以使用 git checkout <branch> -- <filename>。但这不会“挑选”单个提交中发生的更改,而是仅采用该文件的结果状态。因此,如果您在提交中添加了一行,但先前的提交进行了更多更改,并且您只想添加该行而没有其他更改,则检出不是您想要的。

否则,如果您想要将提交中引入的补丁应用于单个文件,则有多种选项。您可以运行 git cherry-pick -n,即不进行提交,编辑提交(例如使用 git reset --. 重置所有文件并仅使用 git add <filename> 添加要更改的文件)。或者,您可以为该文件创建差异并然后应用差异:

git diff <branch>^..<branch> -- <filename> | git apply

30

创建一个 补丁文件 并应用它。

git diff branchname -- filename > patchfile
git apply patchfile

编辑:

既然您需要使用一个提交中的更改,那么可以像这样创建补丁:

git show sha1 -- filename > patchfile

1
-1 使用文件名的 git checkout 是这个问题的正确解决方法。这两个选项都是不必要复杂的。 - Rein Henrichs
9
针对这个特定的情况,是的。但一般来说,如果您想从提交到特定文件的更改中挑选更改,则 checkout 将无法解决问题,因为它可能涉及其他不需要的先前更改,并且可能不包含在当前分支中进行的更改。 - Sailesh
正如@Alexander Oh所指出的那样(https://dev59.com/dGQo5IYBdhLWcg3wbe1K#42623347),`sha1`是提交中文件的blob id。 git ls-tree -r在这方面很有帮助。但结果将是实际的文件内容而不是补丁。 - white_gecko
不使用临时文件:git diff 分支名 -- 文件名 | git apply - - Eric M.

13

Git 已经准备就绪 :)

只需使用 git checkout <sha> <path-to-file> 即可。


12
这不是挑选其中一部分,而是完整检查文件。目标是从提交记录中进行特定更改。通常这两者是相同的,但有时却不是。 - AndrewF

13

另一个有用的操作是本地获取补丁,然后使用:

git checkout {<name_of_branch>, commit's SHA} <path to the file> 

那并不是挑刺。


2
警告:正如@poke在他的答案中所说,这种方法不会复制修改内容,而是复制整个文件的状态。因此,如果你想要将一个提交的修改添加到文件中,那么通过像这样检出文件,你最终会覆盖任何更新的修改,这是不好的。 - Alexander Bird

7
git checkout the_branch_with_the_change the/path/to/the/file/you/want.extension

这将起作用,如果你想将另一个分支中的单个文件复制到当前工作分支。

1
请注意,文件中所做的更改如果不在另一个分支的版本中,则会丢失。 - Patrick Schlüter
同意这个。如果您只需要文件的副本并且想要在当前分支上更改它,则这很有用。 - Ismail Iqbal
1
可以使用通配符(path / *)并指定多个路径/文件。 - Todd

6

使用-n选项来避免提交。

git cherry-pick -n <target>

现在通过选择所需的文件来提交更改。

git commit -- file1 file2

5
您可以尝试这样做:
git show COMMIT_ID -- path/to/specific-file | git apply

例如:

git show 3feaf20 -- app/views/home/index.html | git apply

当只涉及单个文件时,这是一种优雅的解决方案! - bric3

2

我通常会使用 git ls-tree 命令。

只需执行:

git ls-tree -r <commit-id> |grep 'your filename'
# there will be output that shows a SHA1 of your file
git show ${SHA1 of your file} > 'your filename'

这将打印出与您的grep匹配的所有文件名,并在提交中提供文件的SHA1密钥。

Git show还可以用于分支外的文件。 使用>从shell中将输出导管到文件中,即可获得所需的结果。


1
“git ls-tree -r” 是 @Sailesh 的回答中缺失的部分(https://dev59.com/dGQo5IYBdhLWcg3wbe1K#16068419),谢谢。 - white_gecko

1
这就是你要找的内容:
git checkout target-branch sha1 path/to/file

sha1是可选的


12
不,"pick changes in commit" 不等于 "pick whole file"。 - Abyx

-12
git reset HEAD~1

将文件移动到预提交阶段

git stash

从内存中删除

现在你的分支非常干净(恢复到之前的提交)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接