ChatGPT解决这个技术问题 Extra ChatGPT

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

我有 2 个 git 分支 branch1 和 branch2,我想将 branch2 中的 file.py 合并到 branch1 中的 file.py 中,并且只有那个文件。

本质上,我只想处理 branch1 中的 file.py,但想利用 merge 命令。做这个的最好方式是什么?


D
Dave Jarvis

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 命令特别有用。


我们如何在使用补丁的同时使用合并工具?而不是关键的东西
@Gabriel 我什至使用了带有补丁文件和 tarball 的 Git,因为创建存储库 (git init <dir>) 并最终将其丢弃 (rm -r <dir>) 非常容易。
应用补丁时如何工作的链接也很有用,讨论 +- 起始行,以及您应该如何执行更改选择。
有没有办法以非交互方式做到这一点?
这不是合并,不保留历史记录
D
Dave Jarvis

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

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

现在 file.py 现在位于 branch1 中。


很简单,但这实际上不是合并。它只是用分支 2 中的任何内容覆盖 file.py
如果将文件从分支 1 合并回分支 2 会怎样?你会发生冲突!
这会保留提交历史吗?
@Beez 不,请参阅 RM 的回答
R
R.M.

其他当前答案都不会真正“合并”文件,就像您使用合并命令一样。 (充其量他们会要求您手动选择差异。)如果您真的想利用来自共同祖先的信息进行合并,您可以按照 git 参考手册的 "Advanced Merging" section 中的程序进行操作.

对于此协议,我假设您希望将文件 'path/to/file.txt' 从 origin/master 合并到 HEAD - 根据需要进行修改。 (您不必位于存储库的顶级目录中,但这会有所帮助。)

# 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 merge-file 应使用所有默认合并设置进行格式设置等。

另请注意,如果您的“我们的”是工作副本版本,并且您不想过于谨慎,则可以直接对文件进行操作:

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

这确实是实际上合并更改的唯一选项。我在 bash 循环中使用它对几个文件执行此操作:for file in {file1,file2,etc}; do git show $(git merge-base HEAD dev-mysql-to-pdo):$file > common.tmp; git show HEAD:$file > current.tmp; git show dev-mysql-to-pdo:$file > other.tmp; git merge-file -p current.tmp common.tmp other.tmp > $file; rm current.tmp other.tmp common.tmp; done
佚名

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

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

否则,merge 不会对单个路径进行操作...您不妨创建一个 git diff 补丁,其中包含从 branch2git applybranch1file.py 更改:

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

M
Martin G

您可以stashstash pop 文件:

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

这将使用 branch2/file.py 的内容覆盖 branch1/file.py,而不是应该引发合并冲突以解决的合并。
不“合并”文件,只是替换它......最后三个语句几乎没有改变结果......
M
Makogan

我发现让我最不头痛的解决方案:

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

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


J
Jackkobec

最简单的解决方案是:

git checkout 源分支的名称和我们要添加到当前分支的特定文件的路径

git checkout sourceBranchName pathToFile

b
bananaspy

Git checkout 为此提供了一个 --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 -

j
jthill

要仅合并来自 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

合并甚至永远不会查看任何其他文件。如果树足够不同,您可能需要“-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"

C
Claire. D

Matthew Turner 的解决方案是最简单的,但如果 branch1 和文件具有相同的名称,则会出错。在这种情况下,将第二行替换为

git checkout branch2 -- file.py


M
Mohamed Laradji

如果您只关心冲突解决而不关心保留提交历史记录,则以下方法应该有效。假设您要将 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,将能够更轻松地解决冲突。


T
Trac Nguyen

我处于同样的情况,我想从一个分支合并一个文件,该分支在 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

L
Lucas Lima

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

正常合并分支;使用 revert 恢复合并;将我所有的文件检出到 HEAD~1,也就是它们在合并提交中的状态;重新设置我的提交以从提交历史中隐藏这个骇客。

丑陋的?是的。容易记住?也是的。


t
techniao

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

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

[] 表示可选。)

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

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

git difftool 也不保留历史记录。