首页 > 解决方案 > 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 命令可以帮助我实现此更新?

标签: gitgithub

解决方案


记住这些项目:

  • 提交保存快照。它们不是更改,它们是每个文件的完整副本。(Git 会自动进行重复数据删除,因此许多提交重用许多文件这一事实意味着它们确实重用了该文件,即使每个都有一个完整的快照。他们都有该文件的一个快照,在所有人之间共享具有该文件的一个版本的快照。)

  • 分支名称仅标识一个特定的提交。每个提交都指向一个较早的提交或提交。1 根据定义,分支选择的提交是该分支中的最后一次提交。(这反过来意味着一些提交同时在许多甚至每个分支上。)

  • 因此,要获得更改您必须选择两个提交并比较它们。否则,您所拥有的只是一张快照。(尝试链接并比较第一对图片。时钟上的时间有变化吗?)

  • 提交本身是完全只读的。您永远无法更改任何现有提交中的任何内容。Git 所做的是将现有的提交提取到工作区。您可以在此工作区中进行任何您喜欢的更改,然后使用git addgit commit进行的提交。新的提交添加到存储库;现有的提交保持不变。


1合并提交引用了多个先前的提交,并且每个存储库中至少有一个提交(第一个提交)实际上不能引用先前的提交,所以它没有。但大多数提交大多有一个父提交,即前一次提交。这就是Git存储库中的历史:这个向后指向的提交链,从提交到父级,再到祖父级等等。这些提交中的每一个都有所有文件的完整快照。


我有一个分支 A,我想在其中应用分支 B 的更改。

让我们画出这个,早期的提交向左,后来的提交向右。我们将使用单个大写字母来代表真正的 Git 提交哈希 ID,但保留AB代表分支名称:

       I--J   <-- A
      /
...--G--H   <-- master
         \
          K--L   <-- B

当然,我不知道你的分支是什么样的,但是在这里,我们有三个分支:

  • A以提交结束J
  • B以提交结束L;和
  • master结束于 commit H

commit 的父级J是 commit I,其父级是 commit G。commit的父级是 commit LK其父级是 commit ,其父级也是 commit 。这意味着提交在所有三个分支上;提交在并且;和 提交和仅在和上,分别。KHGGHmasterBI-JK-LAB

我想将来自分支 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将改变这一点。


推荐阅读