git - Git:如何将一个文件从分支 A 的更改应用到同一 repo 的分支 B 中的另一个文件?
问题描述
在存储库 X 中,我有一个分支 A,我想在其中应用来自分支 B 的更改。我想将来自分支 B 的文件 d(以master
作为基础)的所有更改的总和应用到另一个文件c 在分支 A 上(也有master
作为基础):
Branch A (based on master)
app/file_c (should receive the changes from app/file_d on branch B)
app/file_d
Branch B (based on master)
app/file_c
app/file_d (has the changes I'm interested in)
我尝试将分支 B 上的文件 d 移动到文件 c 的位置,然后在分支 A 上将更改挑选为分支 B 的提交,但这会覆盖整个文件并使 git 历史记录的可读性降低。
哪些 git 命令可以帮助我实现此更新?
解决方案
记住这些项目:
提交保存快照。它们不是更改,它们是每个文件的完整副本。(Git 会自动进行重复数据删除,因此许多提交重用许多文件这一事实意味着它们确实重用了该文件,即使每个都有一个完整的快照。他们都有该文件的一个快照,在所有人之间共享具有该文件的一个版本的快照。)
分支名称仅标识一个特定的提交。每个提交都指向一个较早的提交或父提交。1 根据定义,分支选择的提交是该分支中的最后一次提交。(这反过来意味着一些提交同时在许多甚至每个分支上。)
因此,要获得更改,您必须选择两个提交并比较它们。否则,您所拥有的只是一张快照。(尝试链接并比较第一对图片。时钟上的时间有变化吗?)
提交本身是完全只读的。您永远无法更改任何现有提交中的任何内容。Git 所做的是将现有的提交提取到工作区。您可以在此工作区中进行任何您喜欢的更改,然后使用
git add
和git commit
进行新的提交。新的提交添加到存储库;现有的提交保持不变。
1合并提交引用了多个先前的提交,并且每个存储库中至少有一个提交(第一个提交)实际上不能引用先前的提交,所以它没有。但大多数提交大多有一个父提交,即前一次提交。这就是Git存储库中的历史:这个向后指向的提交链,从提交到父级,再到祖父级等等。这些提交中的每一个都有所有文件的完整快照。
我有一个分支 A,我想在其中应用分支 B 的更改。
让我们画出这个,早期的提交向左,后来的提交向右。我们将使用单个大写字母来代表真正的 Git 提交哈希 ID,但保留A
和B
代表分支名称:
I--J <-- A
/
...--G--H <-- master
\
K--L <-- B
当然,我不知道你的分支是什么样的,但是在这里,我们有三个分支:
A
以提交结束J
;B
以提交结束L
;和master
结束于 commitH
。
commit 的父级J
是 commit I
,其父级是 commit G
。commit的父级是 commit L
,K
其父级是 commit ,其父级也是 commit 。这意味着提交在所有三个分支上;提交在并且;和 提交和仅在和上,分别。K
H
G
G
H
master
B
I-J
K-L
A
B
我想将来自分支 B 的文件 d (以 master 作为基础)的所有更改的总和应用到分支 A 上的不同文件 c (也以 master 作为基础)...
好吧,也许我应该把它画成:
I--J <-- A
/
...--G--H <-- master
\
K--L <-- B
您现在的目标是找到对某个文件的更改d
,如提交中所见(可能H
由名称标识)到master
提交中所见该文件的版本(L
由分支名称标识)B
。
该git diff
命令执行以下操作:
git diff master B
将向您显示提交中的所有H
文件(使用名称找到master
)到提交中的所有文件L
(使用名称找到B
)中的变化,就像在找不同的游戏中一样。您可以通过要求限制其输出,让 Git 恢复为只显示 file 中的任何不同之处d
,而忽略所有其他文件:git diff
git diff master B -- d
您可能希望将git diff
输出重定向到临时文件:
git diff master B -- d > /tmp/the_diff
请注意,此文件在其说明中包含文件名 d
以及要进行的更改。 您将需要替换此文件名,可能使用保存的git diff
输出上的任何文本编辑器,我们稍后会看到。
到分支 A 上的不同文件 c
请记住,分支名称仅标识某些特定的提交。要将该提交从Git 中取出,进入您的工作区,请使用:
git checkout A
或(自 2.23 以来在 Git 中):
git switch A
(这些特定的调用执行完全相同的操作;新git switch
命令比旧git checkout
命令更易于用户使用,因为许多git checkout
无需询问即可静默覆盖您的工作的操作已移至单独的命令,因此git switch
使用起来更安全)。
您的工作树现在有一个可修改的 file 副本c
。您现在需要修改它,使用 Git 生成的关于如何修改 commit 中的副本的d
说明,H
使其看起来像 commit 中的副本L
。为此,您将首先将说明更改为引用 filec
而不是 file d
。然后你可以运行:
git apply /tmp/the_diff
它将尝试修改(现在修改为“更改文件c
”,而不是“更改文件”)差异到您工作树中d
的副本。c
如果一切顺利,Git 将应用所有更改。如果其中一些不能正确应用,您有多种选择,例如--reject
或--3way
。
请注意,默认情况下,git apply
不会暂存要提交的更改;它留给你。使用git apply --index
将改变这一点。