方案: 2个开发人员在同一个项目上工作,每个开发人员构建一个新功能。项目的某些文件由两个开发人员使用,因此由他们更改。 当第一个开发人员进入生产系统时,一切都很好。但是当第二个开发推进时,会发生什么?
问题: git是否会更改受影响文件中的增量,以便没有开发人员必须通过它来手动查找和修复更改?或者git只跟踪版本并用第二个覆盖第一次推送?或者发生甚至不同的事情? 谢谢:))
答案 0 :(得分:3)
当第二个开发人员试图推送他的文件时,git会说他的存储库副本不是最新的,所以它会迫使他拉/获取存储库。然后,如果git能够自动修复共享文件(例如,因为第一个开发人员已经在第1-10行工作而第二个工作在第50-100行),那么它将会这样做。否则,它将通知第二个开发人员发生冲突,并且他将不得不手动修复该文件。
(我假设他们正在同一个分支上工作。如果他们不是,那么当合并分支时会出现合并问题,但会发生的情况基本相同。)
答案 1 :(得分:3)
你从误解开始:Git不会将提交保留为增量。 1 任何给定的提交都会存储一个完整的目录树,其中包含所有文件。给定提交SHA-1 ID,要查看名称为top/mid/bottom.ext
的文件的内容,您:
top
的子树。这包括该子树的SHA-1 ID。mid
的子树(它给出了另一个SHA-1)bottom.ext
的blob(文件),它为您提供最后一个SHA-1 这与许多其他版本控制系统不同,后者将更改存储为增量,并且必须重建"较新的"文件(第一个版本直接存储,差异向前移动)或任何"较旧的"文件(最后一个版本直接存储,差异向后移动)。
除此之外,每个提交都有一个树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
其中B
,C
,D
和E
表示提交节点(由那些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;命名中央服务器。)
现在由她决定如何合并F
和G
。两个简单而自动化的替代方案是:
G
变为F
G
和F
合并到M
要将G
重新定位到F
,她只需要运行git rebase
(假设通常的跟踪分支设置)。这将差异G
对E
(为了获得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
新提交可能会被推回到服务器,因为M
有F
作为祖先,所以这会在服务器上保留提交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所做的更改作为自己的回购,并且合并是更改。