推入git与多个开发人员文件冲突

时间:2013-11-15 14:09:47

标签: git version-control dvcs branching-and-merging

方案: 2个开发人员在同一个项目上工作,每个开发人员构建一个新功能。项目的某些文件由两个开发人员使用,因此由他们更改。 当第一个开发人员进入生产系统时,一切都很好。但是当第二个开发推进时,会发生什么?

问题: git是否会更改受影响文件中的增量,以便没有开发人员必须通过它来手动查找和修复更改?或者git只跟踪版本并用第二个覆盖第一次推送?或者发生甚至不同的事情? 谢谢:))

3 个答案:

答案 0 :(得分:3)

当第二个开发人员试图推送他的文件时,git会说他的存储库副本不是最新的,所以它会迫使他拉/获取存储库。然后,如果git能够自动修复共享文件(例如,因为第一个开发人员已经在第1-10行工作而第二个工作在第50-100行),那么它将会这样做。否则,它将通知第二个开发人员发生冲突,并且他将不得不手动修复该文件。

(我假设他们正在同一个分支上工作。如果他们不是,那么当合并分支时会出现合并问题,但会发生的情况基本相同。)

答案 1 :(得分:3)

你从误解开始:Git不会将提交保留为增量。 1 任何给定的提交都会存储一个完整的目录树,其中包含所有文件。给定提交SHA-1 ID,要查看名称为top/mid/bottom.ext的文件的内容,您:

  1. 提取树以进行提交(通过提取具有此树的SHA-1 ID的提交)并找到名为top的子树。这包括该子树的SHA-1 ID。
  2. 提取该树并找到名为mid的子树(它给出了另一个SHA-1)
  3. 提取该树并找到名为bottom.ext的blob(文件),它为您提供最后一个SHA-1
  4. 使用SHA-1提取blob。这是文件的全部内容。
  5. 这与许多其他版本控制系统不同,后者将更改存储为增量,并且必须重建"较新的"文件(第一个版本直接存储,差异向前移动)或任何"较旧的"文件(最后一个版本直接存储,差异向后移动)。

    除此之外,每个提交都有一个树SHA-1 ID,一组"父提交"。对每个提交者的父母进行传递闭包会产生有向无环图(或可能是多个DAG)。这个图中的边缘是人们喜欢的#34;分支" (虽然git动态地计算它们;一个"分支名称"只是在图中标记一个节点。)

    所有这一切,当您执行git push时,您联系远程仓库并了解哪些分支名称对应于哪些提交ID,并建议将某些特定分支名称移动到不同的commit-ID。你也发送任何"失踪" SHA-1 ID和重建树,文件,标签和/或提交所需的数据。远程仓库考虑您的请求("请从提交ID 1234567更改develop,提交ID ba98765")并接受或拒绝它,通常是基于是否向分支添加新提交,不删除任何旧的。

    如果开发人员1先推送,并向分支develop添加一些新的提交,那么到目前为止一切顺利。然后,当开发人员2推送时,她添加到develop的提交是新的,但是他们指示远程仓库删除开发人员1的提交。当每个人都开始时他们有这样的东西(从中央服务器克隆):

    ...<--B<--C<--D<--E       <-- develop
    

    其中BCDE表示提交节点(由那些SHA-1 ID标识,这对人类来说太难以使用,所以我们使用名称develop来跟踪E的SHA-1 ID。

    当开发人员1添加提交时,这将成为(在他自己的回购中):

    ...<--B<--C<--D<--E<--F   <-- develop
    

    如果他将此推送到中央服务器,那么添加F就可以了,它是一个新的提交,即#34;下游&#34;。因此,服务器会添加F并更改develop以获得该ID。

    同时开发人员2添加了一个提交,但她得到了这个:

    ...<--B<--C<--D<--E<--G   <-- develop
    

    她的SHA-1 ID不匹配(因为SHA-1 ID是全局唯一的:它们是提交的加密哈希,包括其所有树和文件)。当她去推送时,中央服务器会看到她建议添加G,但为此,请删除F。 (请记住,提交ID包含父ID,因此G 必须指向E。它无法更改:在提交中的任何位置更改一位或其内容更改SHA-1 ID。)

    如果正常(不是&#34;强制&#34;)推送,服务器将拒绝此操作。

    然后,开发人员2必须git fetch(或等效)才能获取提交F,并将其提供给她:

    ...<--B<--C<--D<--E<--G   <-- develop
                       \
                        `-F   <-- origin/develop
    

    origin是&#34;远程&#34;命名中央服务器。)

    现在由她决定如何合并FG。两个简单而自动化的替代方案是:

    • G变为F
    • 进行&#34;合并提交&#34;将GF合并到M

    要将G重新定位到F,她只需要运行git rebase(假设通常的跟踪分支设置)。这将差异GE(为了获得delta-git不存储增量!),然后尝试将增量应用于F。如果自动delta-apply有效,则会获得G的修改后的副本 - 将其称为G'

    ...<--B<--C<--D<--E<--G
                       \
                        F     <-- origin/develop
                         \
                          G'  <-- develop
    

    旧的G不再有标签,因此它被放弃并最终被垃圾收集。 2 新的G'F的直接后代{1}}现在可以推送了。

    她的另一个选择是合并,通过标准的三向合并创建一个新的提交M

    ...-B--C--D--E--G--M      <-- develop
                  \   /
                    F         <-- origin/develop
    

    新提交可能会被推回到服务器,因为MF作为祖先,所以这会在服务器上保留提交F

    强制推送选项(而不是重新绑定或合并)仍然是一个选项,但通常不是一个好选项,因为它会从分支上的提交链中删除提交F,其提示标记为{{ 1}}。

    是否要改变或合并的问题是优先考虑的问题。合并添加了额外的提交节点,使得查看发生的事情变得更加困难,但更难的主要原因是它描述了真正发生的事情。重新定位使它看起来更简单 - 它看起来像&#34;开发人员2等待开发人员1完成他的工作,然后基于他的编写她的。但事实并非如此,而且通常情况下,提交时间戳会显示出来。


    1 Git 在内部进行增量压缩,但方式却截然不同。理论上,例如,git可以在提交中压缩文件的内容,反之亦然(反之亦然)。这种增量压缩保持了git调用&#34; pack文件的大小&#34;小。树可以针对其他树进行压缩,因此如果在大目录中添加或远程单个文件,则相应的子树可能会应用增量压缩。为了性能和方便,git对象保持&#34; de-deltified&#34;作为&#34;松散的物体&#34;并且&#34;重新包装&#34;自动进入新包装。松散的对象是deflate-compressed,压缩也用在包中。

    2 垃圾收集也会进行上述重新包装。大多数提交都会保留一段时间(默认为90天),通过git&#34; reflog&#34;机制,它允许您(1)按日期查找分支提交ID和(2)恢复意外删除的提交,直到reflog条目到期

答案 2 :(得分:0)

Git不会覆盖任何内容,在这种情况下,Git会要求您手动合并。

如果两个开发人员已经在不同的分支上工作,那么开发人员2应该能够将开发人员1所做的更改作为自己的回购,并且合并是更改。