为简单起见,我将用此示例描述情况。
我在第1天为项目创建了一个git分支,其结构如下:
我立即(仍在第一天)将结构更改为以下内容:
同时(第2天),在master分支中,文件Class1.java和Class2.java被其他属性更改(从另一个分支合并到master)。
我的问题是,何时将分支合并回master(第3天)... git将保留master上其他人对Class1.java和Class2.java所做的更改,否则它将替换它们和我在分支机构中拥有的那些?
答案 0 :(得分:1)
当您运行git merge <thing>
时,Git必须找到三个提交。
这三个提交之一是您的 current 提交。 (您的索引和工作树应该匹配它,并且前端git merge
命令通常会强制执行此操作。在{dir1}情况下运行git merge
通常是不明智的,尽管git stash apply
会这样做一直以来。我建议避免使用git stash
,部分原因是因为这个原因。
这三个提交之一当然是您用<thing>
参数命名的提交:
git merge theirbranch
将提交作为其合并的第二个提交中的第二个,在其分支的顶端插入。
第三次提交是大多数魔术发生的地方。 Git自动找到第三次提交。 Git将此称为合并基础,它是从提交图派生的。在某些情况下,很容易看出它的来源。
假设您的分支及其分支具有非常简单的发散结构:
o--...--o <-- yourbranch (HEAD)
/
...--o--*
\
o--...--o <-- theirbranch
此结构的合并基础只是提交*
。
在复杂的设置中,Git仍会自行找到合并基础:合并基础是要合并的两个分支提示提交的最佳共同祖先。但是,您可以在合并之前进行调查:
git merge-base --all theirbranch
会告诉您哪些提交是合并基础。理想情况下,只有一个。当有两个或多个时,Git会遇到一个问题-Git可以解决,但是(a)很少见,(b)与本说明的其余部分有些混乱,因此暂时暂时忽略该问题。 :-)
只有一个合并基础,Git现在可以这样做:
git diff --find-renames base your-commit
来查看您所做的更改; git diff --find-renames base their-commit
看看它们发生了什么变化。也就是说,Git使用相同(公共,共享)基本提交运行git diff
两次。
鉴于上述情况,或者您重命名了一些文件,或者他们重命名了一些文件,或者很可能你们两个都重命名了一些文件。 --find-renames
选项指示git diff
发现这些重命名。 (在这种情况下,是您重命名了文件。)
重命名发现并不完美,但是在大多数情况下,它确实可以满足所需。 Git发现您中的哪些人重命名了哪些文件。这使Git可以使用重命名的文件folder1/src/Class1.java
标识合并基础文件(应为folder2/src/Class1.java
)。 Git记得也发生过重命名。
在更改 的差异中,Git在原始提交中使用未重命名的folder1/src/Class1.java
标识了原始文件folder1/src/Class1.java
。
由于这些更改来自相同的 source 文件,因此Git现在将您的更改与其更改结合在一起。它尝试将相同更改(包括重命名)应用于基本文件。因此,Git获得了基本提交版本folder1/src/Class1.java
,将您的更改及其更改(可能有冲突也可能没有冲突)组合在一起,并将结果作为folder2/src/Class1.java
放置在索引和工作树中,并使用( )重命名。
如果Git无法使用重命名的文件标识原始的基本提交文件,则所有这些组合都将失败。因此,您可以运行相同的git diff --find-renames
,也许与--name-status
一起运行,以跳过实际的差异,仅查看匹配的内容。如果正确的事情相匹配,git merge
将会做正确的事情。
如果正确的东西不匹配,则可以尝试调整Git的“重命名阈值”,将其指定为数字--find-renames=num
。该数字是Git的相似性索引的限制。当Git比较两个提交(例如合并基础和您当前的提交)时,如果合并基础具有文件d1/d2/file.ext
但您的提交没有,并且您的提交具有d3/d4/other.ext
则该基础没有,Git比较两个文件的内容。然后计算相似度指数。大致来说,这是保持不变的文件的数量; 最高达到100%相似,并且如果文件的任何部分都不匹配,则低至0%相似。默认设置是配对至少50%相似的文件。如果一个来源与五个目的地匹配,只要满足阈值,Git就会采用相似性指数最高的配对。
git merge
命令采用相同的参数,但拼写为-X find-renames=number
。
如果git merge-base --all
为您提供了多个合并基础,则Git处理问题的方式如下:
-s recursive
(默认设置):Git首先通过在它们之上或多或少运行git merge
来合并合并基础。最终的提交将成为合并基础。-s resolve
:Git以(显然)随机的方式选择一个合并基础,并使用它。其余所有内容都相同,但是请注意,如果递归合并遇到合并冲突,Git只会提交合并冲突本身。然后,这种冲突的合并结果将成为输入基础,通常会导致看起来很奇怪的冲突。
答案 1 :(得分:0)
Git会进行增量更新,只有您更改的行将被合并。如果两个或两个以上的人修改相同的行,您将遇到合并冲突,并且需要在合并更改之前对其进行修复。
https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts
答案 2 :(得分:0)
git是否会保留master上其他人对Class1.java和Class2.java所做的更改,或者将其替换为我在分支机构中拥有的更改?
是的,Git的合并操作通常会注意到您已经重命名了一些文件(将它们移到了另一个目录中-这是一个重命名操作)。在此期间,其他人在原始位置引入的更改被保留。
但是,这仅在您不重用一侧的路径folder1/src/Class*.java
且另一侧在合并发生之前也没有引入Folder2/src/Class*.java
的情况下才有效,因为那样会使Git的重命名检测失败。