Git:如何仅合并修改过的文件

3
我有以下问题: 我们有一个大型产品,位于主分支中。此外,我们有其他分支,仅具有少量文件,这些文件仅适用于该分支。每个分支代表主要产品的插件。例如,当您获取主要产品时,您会收到许多文件,安装它们等等。稍后,当您决定获取插件时,您会收到一个包含几个文件的软件包,并通过上传这些文件(并替换原始文件)安装插件。
假设我在主分支中有payment.php(以及许多其他文件)。我还有paypal分支,其中仅有一个文件payment.php。现在,我在主分支的payment.php中修复了一个错误,并希望将此修复合并到paypal分支中。但是,当我运行合并时,所有文件都被添加到该分支中。因此,最终paypal分支将拥有来自主分支的所有文件。您是否知道如何解决这个问题?我希望GIT合并仅存在于此分支中的文件,因此在上面的示例中,paypal分支仍应只有一个文件(payment.php),其中包含合并的错误修复。

正如其他人所说,您可能不希望有一个缺少所有文件的分支。如果您真的想单独跟踪插件,它应该是一个单独的存储库,可能作为主项目中的子模块包含在内。如果您不想将其分开,则可以拥有自己的开发分支,但作为项目存储库的一个分支,该分支应包含整个项目,而不仅仅是一个插件。 - Cascabel
5个回答

4
这就是为什么良好地管理分支非常重要,特别是使用主题分支和向上合并。

你应该在一个主题分支上修复问题,从所有需要此修复的分支的共同祖先进行分叉,然后将其合并到主分支和paypal分支中:

x - x - x - x ------------- X (master)
|\                          |
| x - x - x ---- X (paypal) |
 \              /           /
  x (bugfix) ---------------

如果您已经修复了错误,并错误地在主分支上进行了修复而不是从适当的合并基础开始,而且主分支的历史记录尚未发布,那么您应该将其挑选或者变基到正确的位置。
# If the bugfix commit is not at the tip of master, you can rebase to get it there:
git rebase -i <commit before the bugfix> master
# rearrange the list of commits to put the bugfix at the tip, save and quit

# Now either cherry-pick or rebase the commit to the right place
# (rebase is easier if the bugfix is actually several commits)

# Cherry-pick
# make a branch and cherry-pick
git checkout -b bugfix <SHA1 of merge base>
git cherry-pick <SHA1 of bugfix>
# remove the commit from master, assuming it's still on the tip
git checkout master
git reset --hard master^

# or rebase
# make the bugfix branch (assuming it's still on the tip)
git branch bugfix master
# and remove the commit from master (assuming it's still on the tip)
git checkout master
git reset --hard master^    # or if the bugfix is composed of n commits, master~n
# rebase the bugfix branch to the right place
git rebase --onto <SHA1 of merge base> master bugfix

如果历史记录已经发布,你只能在paypal分支上挑选漏洞修复补丁,并记得下次一定要做对。
git checkout paypal
git cherry-pick <SHA1 of bugfix>

嗨,我在考虑建立PayPal分支,并不时将主分支合并到它里面。因此,当我需要实现新功能或修复错误时,我会在主分支的文件中进行操作,然后在发布之前将更改合并到PayPal分支中(以便PayPal可以拥有新的修复和功能)。我对这方面还比较新,所以如果我没有看到一些隐藏的问题,请纠正我。以前我一直在手动完成这项工作。因此,我会在主分支中实现新功能,然后手动将代码片段复制到PayPal分支中。 - Eugene
在上面的例子中,这两个分支似乎非常不同(在分支点之后有所有那些提交),而我的分支通常只有一个区别(例如 PayPal 功能)。其余的都是相同的,主要工作是确保新的代码修改始终进入两个分支。当然,有时我只针对 PayPal 分支进行修复,但这相对较少,因为此时该代码已经经过充分测试。 - Eugene
@Eugene:我真的不确定你在那些评论中想要问什么。无论如何,您始终可以从正确的分支点进行修改,然后将它们合并到需要它们的所有分支中。这些分支有多不同并不重要,只要您的补丁仍然适用... - Cascabel

1
为什么你的其他分支不包含主分支中的所有文件呢?你只是给自己增加了麻烦,费力地删除所有其他文件。尤其是如果以后需要更改已经删除的其他文件,那就更加麻烦了。

在实际应用中,需要将热修复补丁放入特定的发布分支而不是主分支。在这种情况下,您将拥有一个发布分支,它与主分支不同步,也就是说文件是不同的,因此您需要使用这个 cherry-picking 选项。 - mark.inman

1

你做错了,应该把所有文件都放在分支里。

Git的工作是跟踪分支之间不同的文件,而不是你的工作。 这正是使用版本控制系统的一点。

如果你想只分发分支之间不同的文件,这些文件可以很容易地被一个脚本提取出来。


1
嗨,感谢您的回复。我目前正在测试这个解决方案,很可能会使用它。 - Eugene

0

你可以类似这样做:http://nvie.com/git-model

(希望这个方法有效)

master 分支将继续作为主分支。你从 master 创建一个名为 bugfix 的第二个分支。你在 bugfix 分支上创建一个名为 plugin-foo 的第三个分支。

在 plugin-foo 分支中,你删除所有不需要的文件。现在,每当你对不在插件分支中的文件进行更改时,你都在主分支上进行更改。所有的 bug 修复都进入 bugfix 分支。你定期将 bugfix 分支合并到主分支和插件分支中。这会导致 bug 修复进入这两个分支。


0

将插件隔离到它们自己的git存储库中,可以使您在父项目上独立地进行演进。

然而,如果您需要直接将它们包含在您的项目中,最近的Git版本(git1.7.11,2012年6月)包括 git子树脚本(以前由 apenwarr在{{link2: GitHub上开发} },现已合并到主线git中)

这样,您可以将一个存储库(及其历史记录)合并到另一个存储库中,并保留稍后提取其历史记录的选项(与子树合并相反)。
这可以看作是git子模块的替代方法。

另一种选择是 git slave,以保持父存储库和子模块之间的紧密同步。


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