Git push pull很头疼

时间:2016-04-21 06:18:58

标签: git cvs

我是Git爱好者。十多年来,我们公司一直使用CVS进行版本控制。我试图说服我的同事转而使用Git来克服CVS的限制。

我的一位前辈指出了CVS比Git好的情况(真的!)。让我告诉你情况。

假设John,Bill,Harry和Tom正在使用相同的存储库,但所有存储器都在不同的功能中,John和Bill一度修改了相同的Utility文件。

在这种情况下,约翰试图推动他的改变。同时,比尔已经推动了他的改变。因此,John必须首先进行更改,合并它们然后再次尝试推送。

现在,哈利推动他的改变。因此,John必须再次重做pull-merge-push活动。

再一次,汤姆推动了他的改变。约翰未能将他的改变推进3次,但从未成功,因为其他人在可能之前推动了他们的改变。

这种情况不会出现在CVS中,因为我们可以在不更新整个存储库的情况下提交对一组文件的更改。

所以我的问题是,拥有大量开发人员的公司如何使用Git?这个starvation问题的解决方法是什么?

3 个答案:

答案 0 :(得分:3)

首先,我不确定我是否理解CVS如何处理两个用户更新同一实用程序文件的情况,而不是GIT

在任何代码存储库中,标准做法是更新您的代码,然后推出您的更改,以免您不小心踩到其他人的工作或无意中覆盖其他人的工作.. < / p>

在标准的git工作流程中,会发生以下情况。 假设我使用基于branch_a分支的功能分支develop

我会做以下事情,

i。在develop分支执行:git checkout -b branch_a

ii。在branch_a上进行更改 在这一点上,我确信我需要做出的改变。但是,我正在使用的develop分支可能已被其他用户更新。

iii。所以我做了:git pull --rebase origin develop 这会针对当前develop分支更新我的本地分支。 如果某些人确实推出了与你的冲突相冲突的变化,那么你自己就会发生冲突。您可以在此时解决它们。

iv。在此步骤之后,您的分支已准备好合并开发。

v。您现在可以通过检查开发分支并执行git merge branch_a将您的分支合并到开发中。

Git与大多数旧系统的不同之处在于您在本地分支上进行本地提交的方式,而不是像往常一样提交到repo的提交方式。对我来说,Git的方法在维护大量用户的回购时更加清洁和安全。

答案 1 :(得分:2)

要添加到Som Bhattacharyya(我没有足够的代表评论):我会让约翰,比尔,哈利和汤姆密切合作。当约翰注意到他不能推动因为哈利推了一些东西时,他会打电话给那些家伙,他们会互相调整。

替代方案将是4名开发人员,每个人都在他们自己的王国中争取推动他们的变革。

为了帮助我的同事过渡到Git(主要来自SVN),我说了以下两件事:

  1. 请记住,在Git中,分支机构很便宜。廉价。分支。

  2. 请阅读the Pro Git book

  3. 在此之后,我们能够为我们提供一个非常有效的工作流程,可以完全防止您遇到的问题。

    更新:写下这个答案以及今天正在进行的一些事情使我更加意识到,对我们来说,最重要的还是沟通而不是严格遵守工作流程。我敢说这适用于每支球队吗?

答案 2 :(得分:2)

实际上,这种情况可以和 在CVS中发生,它只是(非常)罕见,因为这种冲突发生在文件级别。更具体地说,CVS具有文件原子性

在实践中,这种冲突在Git中很少见,因为(正如其他答案已经注意到的)我们使用分支来实现更好的并行开发。此外,在CVS不会发生冲突的所有情况下(因为更改都在单独的文件中),Git(或等效的Mercurial)将很容易地自行完成合并或变更,因此在您的情况下,John可能必须重试git fetch && git rebase && git push一次或两次, 1 ,但因为他可以非常简单地执行此操作(例如,使用 CTRL-P ENTER 在外壳中,它根本没有负担。最后,在在CVS中发生冲突的情况下,通常必须立即解决该冲突。使用像Git这样的DVCS,只要你想通过把它扔到一个分支中就可以推迟分辨率(Mercurial让这个决定变得更难,因为分支是持久的和全局的)。

我引用自己正在进行中的书籍......

1 事实上,git fetch && git rebase有一个方便的捷径git pull --rebase。不短,是吗? :-)你可以将git pull配置为自动 rebase,使它变为git pull && git push,但这是你不应该做的事情,直到你非常熟悉fetch-and-变基

集中与分布式

许多较旧的VCS是集中式或CVCSes。 Git和Mercurial是DVCSes:分布式版本控制系统。

这两种系统之间的主要区别在于集中式VCS具有指定的主存储库。可能存在主设备的多个副本,或甚至具有某种同步协议的多个主设备(例如,ClearCase MultiSite),但是只有一个主设备。他们的设计假设这种单船,因此可以依赖它。

使用分布式VCS,没有指定的主存储库。用户通常拥有每个存储库的完整私有副本。这些私有副本之间的通信,至少在原则上是对等操作:两个存储库都不是更精通,以及冲突 - Alice和Bob都对相同文件的相同区域进行了更改的情况 - 可以和做发生并需要某种解决方案。

始终可以集中使用分布式VCS:您只需将一个特定存储库指定为主版本,并协调对其的更新。但是,集中式系统  通常提供锁定源文件或目录,限制访问(读取和/或写入,特定文件,目录和/或分支)等功能,等等。对于典型的DVCS来说,提供这些功能更困难(虽然在技术上不可能),而Git和Mercurial根本没有,至少没有附加功能。使用提供锁定的CVCS,用户可以锁定文件(通常只有一个特定的版本ID),以防止其他用户进行相互冲突的更改。这在概念上更容易,但当然它可以禁止并行工作。

存储库和工作树

VCS区分存储库(文件控制良好和版本化)和工作树(文件通常没有版本化)。工作树通常用于编辑文件,编译文件以及以其他方式使用文件。 [段落的其余部分,它充实了一些早期的定义]

使用集中式VCS,主存储库可以保留在集中式服务器上。然后,我们可以在不首先复制整个存储库的情况下签出用户机器(例如,笔记本电脑)上的工作树, 所以笔记本电脑的存储空间可能小于服务器的存储空间。通常我们也只能提取一个小子集:如果存储库包含数百个包,库或其他子系统,我们可以只检出一个子系统,甚至只检查一个文件。这很方便 一个是快速简单的改变。另一方面,它要求在结账和签入/提交操作期间将工作树连接(联网)到集中式服务器,如果本地工作空间断开连接,则可能无法使用其他修订。

由于分布式VCS通常会复制整个存储库, 5 整个历史记录通常始终可用。这里的主要权衡是初始副本(克隆操作)的设置时间较长,以及克隆所需的其他非易失性存储。这些DVCS很难使同步操作高效,因此一旦进行了初始克隆,获取新版本的速度相对较快。 (例如,我已经看到初始克隆在慢速网络上花费了四个小时或更长时间,但是它们的重新同步通常只需要几秒钟。)

5 Git和Mercurial现在都支持浅克隆单分支克隆,它们可以省略某些存储库。 [剪掉其余的脚注,这基本上是以后即将发布的信息的预告片,或者可能是它的链接,最终......]

原子性:最小的修订单位是什么?

较旧的VCS使用签出/签入模型一次只使用一个文件。它们的原子性单位是文件。即使您一次签出(或更多)文件,VCS也会执行每个操作 每个文件的基础,就像你一次只做一个。考虑表1.1中显示的四个可构建迭代。让我们假设在每次迭代时,一组新的可编译文件都被一起签入 - 但是我们的VCS只能处理文件,一次一个文件。每个文件都以版本1开头,但在迭代3,文件kanga.c有两个版本,而文件roo.c有三个。 6 最后一个可构建的迭代引入了新文件{ {1}},现在是版本1.为了构建任何给定的迭代,您需要哪些版本的文件?您需要跳过哪些文件版本组合?当然,答案在我们的表格中,但VCS不会自行跟踪。

6 目前,我们只会为每个文件修订编号,而不必担心修改后的树木。

[表1.1和1.2要求StackOverflow中没有标记;这里我使用纯文本]

表1.1:四个可构建的迭代,以文件原子性记录,导致七次签到。实际上每行签到的文件都标有星号。

wallaby.c

较新的系统,包括Git和Mercurial,可以处理更大的文件集。它们的原子性单位是 commit 。提交更改会立即输入所有文件。如果出现任何问题, no 文件将获得新版本;如果整个提交成功,所有文件将获得一个新的修订,如表1.2所示。提取最新的commit-row 4 - 获取所有三个文件的最新版本。备份一个版本可以获得之前的check-in iteration files -------------------------------------------------------- 1 kanga.c:1* 2 1 kanga.c:1 roo.c:1* 3 kanga.c:2* roo.c:1 4 2 kanga.c:2 roo.c:2* 5 3 kanga.c:2 roo.c:3* 6 kanga.c:3* roo.c:3 7 4 kanga.c:3 roo.c:3 wallaby.c:1* kanga.c - 这会更改roo.c的内容,同时保持kanga.c的内容相同 - 并删除roo.c完全,全部自动。

表1.2:相同的四个可构建迭代,但具有提交原子性。

wallaby.c

通常,在文件原子系统中,您可以将一组文件修订名称或标记组合在一起,并按标记提取。标签往往有 一个明显的成本 - 即使他们没有占用大量的空间或时间, 7 他们提出了一种修正的混乱,实际上他们只用于更主要的检查站。基于提交的系统消除了对这些标签的需求(尽管我们将看到,标签仍然有用)。

7 例如,CVS中的标签是按文件级别维护的,因此标记整个树的操作非常慢。

[更多的冲突,删除有关压缩,文件标识,分支和版本编号的整个部分,关于分支和修订的可分离性的一些哲学问题等)

并发模型

无论是集中式还是分布式,任何允许多个用户彼此独立工作的VCS都必须提供一些方法来处理潜在的冲突。如前所述,一种方法是锁定:在更改文件之前,用户必须获得一个锁,然后在提交更改时释放锁。这种简单的方法具有前面提到的禁止并行工作的明显问题。有可能使锁更精细 - Alice可能会锁定文件的上半部分,而下半部分可供Bob锁定和更改 - 但这会产生扩展问题。此外,用户和/或管理员必须有办法打破锁定,因为用户将锁定文件但失败或忘记解锁它们(例如,在决定不提交之后)。

如果VCS提供 merge 模型,则两个或更多人可以在相同的文件上工作,并在CVCS中的定义的集合点,在签入/提交时,例如 - 他们有机会调和他们的变化。在组合分支时也需要合并,并且在现代DVCS中,通常将相同的方法用于这两者。 请注意,在DVCS中,会合点(以及任何合并)可以在签入后发生。 Bob可以在自己办理登机手续之前拿起Alice的工作,但由于系统是分布式的,Bob不必等待Alice(反之亦然)。

[下一节是对所选VCS的评论。我不会在这里复制它,但是会注意到我在表中给CVS一个条目,它表明它是SCCS和RCS的一步:它具有合并并发性,但仍然使用文件原子性而不是分发。 Subversion位于下一组,提供提交原子性和合并并发,但仍使用集中式存储库。与此同时,Git和Mercurial都使用提交原子性,合并并发性,并使用完全分布式模型。

有理由坚持使用集中式VCS,但今天仍在使用CVS的人应该在几年前切换到SVN。承诺原子性是如此的飞跃,至少,如果我可以避免它,我至少会永远不会回头。 SVN有一个奇怪的分支模型,但它确实有效,并且有cvs2&lt; thing&gt;转换器可以帮助你。]