如何在Git中从一个分支选择性地应用更改到另一个分支?

18

是否可以使用Git选择性地将一个分支的更改应用到另一个分支?

更具体地说,我在GitHub上使用公共dev分支和私有master分支进行部署。当更改适用于一个分支时,它们需要应用于另一个分支,但某些代码行需要保持不同。在我的情况下,这是一些css类和反馈。

我是新手,但我已经做过研究:

  • git merge --no-commit --no-ff可以用于后跟git mergetool,以便在发生冲突时选择我想要的内容。问题在于它仅适用于Git无法自动合并的冲突,因此在我有机会使用我的mergetool之前,我想要保留的内容会被替换。

  • git difftool --cached非常有用,因为它允许我查看差异,但是我需要从中复制我想要保留的内容,并使用文本编辑器手动替换它,因为我不能像使用mergetool那样简单地选择并保存。

  • git cherry-pick似乎将指定的提交应用于另一个提交,但我想要保留的内容可能分散在不同的提交中,并且这些提交可能不仅包含我想要保留的内容。除非我进行数百万次提交,否则我无法看到它起作用。

此外,要明确的是,我不想让一个分支成为另一个分支,这似乎是合并的情况。我希望有两个不同的分支以及它们各自的差异,并将更改从一个应用到另一个。

是否有更好的工作流程可以让我通过应用其更改并保留一些差异来保留开发和部署版本?如果可以解决问题,我不介意使用单独的存储库或不同的工具。


所以,基本上有时您可能只需要提交的一部分,这可能是来自单个文件中的某些行,也可能是来自提交中许多文件中的几个文件? - Nikhil Gupta
我需要在合并时保留几行代码的不同,例如一个分支中的白色背景和另一个分支中的黑色背景。同一文件中可能会有其他更改需要合并,因此文件排除并不能解决所有情况。 - toucanb
可能是如何使用git-merge合并选择性文件?的重复问题。 - Inigo
3个回答

21

我还了解到补丁(patch)的相关内容:

创建补丁的方法是:git diff dev > master.patch

应用补丁的方法是:patch < master.patch


2
谢谢 - 已点赞!但是请注意 - 因为我的 git配置了将一次性的虚拟目录名 a/b/ 放在我的差异中,所以对于我来说,第二个命令略有不同: patch -p1 < master.patch - Brandon Rhodes

5
利用创建git分支的便捷性,不会对工作目录中的实际内容产生影响。
1.检出源分支`dev`。 2.创建一个临时分支。它将指向与`dev`相同的提交:`checkout -b for_master`。 假设您知道(或可以轻松找到)在您想要的更改之前的最后一个提交是哪个。在这个例子中,假设该提交的哈希值为`1457B4`(“last before”)。 3.将`for_master`分支重置为该提交:`git reset 1457B4`。(不要使用`--hard`开关!) 现在,您有一个包含所有更改的工作目录,这些更改在`for_master`分支的视角下未被暂存和提交(而`dev`分支仍然指向记录所有更改的提交,因此工作仍然是安全的)。 4.使用交互式暂存(`git add -p`和/或`git add -e`),创建一个提交(如果需要,可以创建多个提交),其中包含所有且仅包含您要应用于`master`分支的更改。 记下最后提交的哈希值(或给它打上标签)。在这个例子中,我会说它的哈希是`C0DA`。 5.检出`master`。 6.挑选您刚刚做的提交:`git cherry-pick 1457B4..C0DA`。 (请注意,挑选一个范围只在git版本1.7.2之后可用。否则,您需要逐个挑选步骤4中所做的所有提交。) (另请注意,当您挑选一个范围时,范围的开始是实际上将被挑选的第一个提交之前的提交。)
这个过程有点相反于使用选定答案中提到的`git checkout -p`。它可能对创建在两个共享一些代码但也有很多差异的分支之间可以进行`cherry-pick`提交很有用(例如,在项目的两个主要版本之间),而且您不想花费大量时间在调用`git checkout -p`时忽略不相关的文件。

就我个人而言,我发现使用两个不同的工作目录(一个用于源分支,另一个用于目标分支)来管理同一个代码仓库非常方便。我会在两个命令行窗口之间切换,一个窗口使用源分支目录(工作目录),另一个窗口使用目标分支目录。但是,如果您不熟悉 git worktree 功能,那么这可能不适合您。


1
优秀的技术。帮助我将一系列明确范围的个人PR重新排列,这些PR来自于数周内涵盖多个功能的混乱提交(我真是太丢人了 - 如果要审核的话,那将是一场噩梦!)。谢谢! - Matt Wanchap

4
我认为在同一个文件中挑选提交的部分是没有办法的。我建议你需要重新组织代码,将这些部分移动到不同的文件中。
顺便说一下,如果你想从提交中取出一些文件,可以使用cherry-pick与其他命令的组合,如这里所述。

5
在你提供的链接中,执行git checkout -p branchname解决了我的问题!这使我能够交互地从其他分支中选择性地获取更改,而无需合并。樱桃拣选也可以工作,但只能得到每个提交的更改。 - toucanb
显然有一种方法 - 可能不容易。 - Att Righ

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