合并两个分支,拆分目录

时间:2015-11-02 23:37:25

标签: git git-merge

在我们的一个git存储库中,我们有两个分支,每个分支都在某些目录上工作,以至于它们大不相同 1 。我们现在想要合并两个分支,保留两个版本。

我已经玩过重命名一个目录,以便它们不会在磁盘上重叠,但是当我合并分支时,git知道它们最初都来自同一个源,并且有助于"移动& #34;文件从一个到另一个,伴随着合并冲突。

我还尝试使用git merge -s ours branchname然后使用git checkout branchname -- directory/,但这看起来会破坏他们的历史记录#34;分支,使它看起来像突然出现的文件。理想情况下,我希望保留对预合并分支中的文件进行修改的能力,合并能够找到文件的正确版本。

有没有办法告诉git合并两个分支,但保留某些文件/目录为"分开",尽管共享起源?或者换句话说,有没有办法吐出文件的历史记录,以便git知道它在一个分支中移动但在另一个分支中没有移动?

1 这些是文档/测试目录,因此关于代码重复的标准问题很少到不存在。

1 个答案:

答案 0 :(得分:1)

这里有坏消息和好消息。

Git并不关心(在某种程度上,在包文件的工作方式中存在秘密关注点,并且我还要提及的是关于提交中的路径名)。它只关心内容:文件中的位,以及放置这些内容的名称。除了父ID之外,每个提交完全独立于之前或(最终)之后的任何提交。因此,“文件”根本没有任何历史记录。

显然,文件有历史记录,因为如果你区分两次提交(这是git show在显示提交时所做的那样),你会看到一个来自“之前版本的补丁” foo“to”foo的新版本“,你可以做”git blame foo“这样的事情来看历史。

Git通过使用内容每次要求一个来构建历史记录来协调这两个对立面。如果您运行git showgit log -p,以查看更改的内容,git会根据内容重新构建历史记录。

在查找已移动/重命名的文件方面,git使用一个或多个技巧,具体取决于您如何指导它。您可以告诉git diff(包括获取差异的大多数命令,包括合并操作)根本不检查。这是最快的方法。

你可以告诉它使用一个快速(但仍然是O(n 2 ))算法,该算法只查看仅在diff比较的两个提交之一中的路径名。这是合并的默认方法(您可以通过配置diff.renameLimit将其配置为diff的默认方法,或者您可以使用-M选项为其提供。)

或者,您可以通过--find-copies(又名-C)或--find-copies-harder告诉它使用缓慢甚至非常慢的方法。

默认的大多数快速方法确实使用路径名,而非常慢的方法不使用路径名。尽管如此,两者仍然依赖于内容。特别是,在复制或重命名检测方面,如果文件“至少50%相似”,或者您使用-M和/或{{-C选择的任何其他相似性比率,则文件被视为“相同” 1}} diff的参数。

这既是好消息,也是坏消息。基本上,每次你得到git来比较两个提交 - 包括任何未来的合并,回顾这些为他们的merge-bases-git将找到一些重命名,而不是找到一些其他重命名和/或副本,取决于你给它的标志和内容的相似性。您可以在合并期间(-X rename-threshold而不是-M)对检测值大惊小怪,但这里的控件非常粗糙。

(请注意,git blamegit log --follow在尝试发现重命名时也会执行此类基于名称和内容的匹配。git log --follow的算法仅在向后移动时才有效及时,从当前路径到之前的路径,因此当与--reverse结合使用时会失败。)