如何从Git分支合并特定文件

我有2个git分支:

  1. branch1
  2. branch2

我想将file.pybranch2中的所有历史(多次提交)合并到branch1中的file.py,并且只合并该文件。

本质上,我只是想在branch1中处理file.py,但想利用merge命令。

最好的方法是什么?

208954 次浏览

branch2中对file.py的所有修改是否都在自己的提交中,与对其他文件的修改分开?如果是这样,你可以简单地cherry-pick更改:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

否则,merge不会在单个路径上操作…你也可以创建一个git diff补丁,将file.pybranch2git apply更改到branch1:

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch

虽然不是合并本身,但有时需要另一个分支上的另一个文件的全部内容。Jason Rudolph的博客提供了将文件从一个分支复制到另一个分支的简单方法。应用如下技巧:

$ git checkout branch1 # ensure in branch1 is checked out and active
$ git checkout branch2 file.py

现在file.pybranch1中。

为了只合并来自branch2的file.py的更改,使其他更改消失。

git checkout -B wip branch2
git read-tree branch1
git checkout branch2 file.py
git commit -m'merging only file.py history from branch2 into branch1'
git checkout branch1
git merge wip

Merge甚至不会查看任何其他文件。如果树的差异足够大,您可能需要'-f'签出。

注意,这将使branch1看起来好像branch2历史中的所有内容都已合并,这可能不是您想要的。上面第一次签出的一个更好的版本可能是

git checkout -B wip `git merge-base branch1 branch2`

在这种情况下,提交消息也应该是

git commit -m"merging only $(git rev-parse branch2):file.py into branch1"

当内容在branch2file.py中,而不再适用于branch1时,它需要选择一些更改并保留其他更改。为了完全控制,使用--patch开关进行交互式合并:

$ git checkout --patch branch2 file.py

git-add(1)手册页中的交互模式部分解释了要使用的键:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

split命令特别有用。

其他当前答案实际上都不会“合并”文件,就像您使用merge命令一样。(在最好的情况下,他们会要求你手动选择差异。)如果你真的想利用来自公共祖先的信息进行合并,你可以遵循一个基于git参考手册的“高级合并”部分中的过程。

对于这个协议,我假设你想要将文件“path/to/file.txt”从origin/master合并到HEAD - modify中。(你不必在你的存储库的顶部目录,但这是有帮助的。)

# Find the merge base SHA1 (the common ancestor) for the two commits:
git merge-base HEAD origin/master


# Get the contents of the files at each stage
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show HEAD:path/to/file.txt > ./file.ours.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt


# You can pre-edit any of the files (e.g. run a formatter on it), if you want.


# Merge the files
git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt


# Resolve merge conflicts in ./file.merged.txt
# Copy the merged version to the destination
# Clean up the intermediate files

git合并文件应该使用所有默认的合并设置来格式化等。

还要注意,如果你的“ours”是工作副本版本,你不想过于谨慎,你可以直接对文件进行操作:

git merge-base HEAD origin/master
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt
git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt

你可以stashstash pop文件:

git checkout branch1
git checkout branch2 file.py
git stash
git checkout branch1
git stash pop

我在同样的情况下,我想合并一个文件从一个分支上有许多提交它在2个分支。我尝试了上面提到的很多方法和我在网上找到的其他方法,都失败了(因为提交历史很复杂),所以我决定用我的方式(疯狂的方式)。

git merge <other-branch>
cp file-to-merge file-to-merge.example
git reset --hard HEAD (or HEAD^1 if no conflicts happen)
cp file-to-merge.example file-to-merge

我所做的有点手动,但我:

  1. 正常合并分支;恢复了revert的合并;
  2. 检出我的所有文件HEAD~1,也就是说,他们的状态在 李合并提交,< / >
  3. 重设我的提交隐藏此黑客从 李提交历史。< / >

丑吗?是的。容易记住吗?也没错。

如果您只关心解决冲突,而不关心保存提交历史记录,那么下面的方法应该是有效的。假设你想将a.py b.pyBRANCHA合并到BRANCHB。首先,确保BRANCHB中的任何更改都被提交或隐藏起来,并且没有未跟踪的文件。然后:

git checkout BRANCHB
git merge BRANCHA
# 'Accept' all changes
git add .
# Clear staging area
git reset HEAD -- .
# Stash only the files you want to keep
git stash push a.py b.py
# Remove all other changes
git add .
git reset --hard
# Now, pull the changes
git stash pop

git不会识别出a.py b.py中存在冲突,但如果确实存在冲突,则合并冲突标记会在那里。使用第三方合并工具,如VSCode,可以更轻松地解决冲突。

我发现的最不让我头疼的方法是:

git checkout <b1>
git checkout -b dummy
git merge <b2>
git checkout <b1>
git checkout dummy <path to file>
git branch -D dummy

这样做之后,b2中的path to file中的文件就是与b1完全合并后的文件。

最简单的解决方案是:

Git签出源分支的名称和我们想要添加到当前分支的特定文件的路径

git checkout sourceBranchName pathToFile

Matthew Turner的解决方案是最简单的,但是如果branch1和file有相同的名字就会给出一个错误。在这种情况下,将第二行替换为

git checkout branch2 -- file.py

如果git checkout --patch branch2 file.py将被接受,那么我应该分享我们还可以使用:

git difftool <branch> [-- <file>]

([]表示可选。)

如果为diff.tool配置,像meld这样的合并工具将允许您使用图形界面手动合并两个文件。

它的一个缺点是,如果某个文件不存在于某个分支中,则无法复制或删除该文件。在这种情况下,我们需要git checkout branch2 -- file.py

git difftool也没有保存历史。

Git签出为此提供了一个--merge选项

git checkout --merge branch2 file.py

使用此选项,将重新创建有冲突的合并。

否则,当一个新的合并发生时:

# Detach and overwrite file.py with content from branch2
git checkout --detach
git checkout branch2 file.py


# Amend changes and switch back
git commit --amend --no-edit
git checkout -


# Merge the detached branch back in
git merge --no-commit -

我发现一些答案是有用的,但令人困惑,所以避免任何困惑的未来。我只是想帮助那些有同样困惑的人。

我不会使用branch1branch2的名称,而是master(活动代码)和hotfix/abc(从master提取)和testing分支。

现在,我想将一些特定的文件从testing合并到hotfix/abc,因为不建议直接从testingstaging分支合并到master上。要做到这一点,我将做以下工作:

  1. git checkout hotfix/abc
  2. git checkout --merge testing path/to/file1.php path/to/file2.js
  3. git add .
  4. git commit -m "Fixed specific issue"
  5. git push
  6. 现在进入repo,为hotfix/abcmaster分支创建把请求。如果你不知道如何做在这里我有一个小教程。如果你想了解这些分支和git是如何工作的,我建议你看这个20分钟的视频。
  7. 现在用mastermerge来复习你的pull request。以防你看到任何冲突,是时候将master合并到hotfix/abc了。解决那里的冲突。然后再次重复步骤3-57

我还从引用教程得到了帮助。

如果有用的话,竖起大拇指。快乐编码:)