美文网首页
我对git的理解

我对git的理解

作者: 玩家翁伟 | 来源:发表于2016-06-12 19:32 被阅读1473次

    面试的时候,我问过很多人,你怎么理解git?对于那些有svn使用经验的童鞋,我则往往还追问,svn跟git有什么不同。

    听到过很多不同的回答,但似乎还没有一个回答与我一致。这里,写写我对git的理解。

    (做为面试题目,我期望的不是听到一个“正确的回答”,我期望了解到的是,候选人为什么这么回答,以求对候选人有更全面的了解。)

    git commit / push / pull 等等操作,现在有玩github的工程师应该都了解;但这些仅仅是了解git的基本使用。

    还有git merge / rebase / cherry-pick等等操作;还有local / remote等的区别。

    我会觉得,了解或者说知道一个工具的使用,并不足够。更加需要理解的,是一个工具为什么被设计成为这样。

    需要理解工具背后的设计理念。

    修改 vs 版本

    git管理的是修改(changeset),而svn管理的是版本(revision)。

    在这点上,git跟hg的设计理念是一致的,Joel Spolsky为推广hg,曾经写过一篇很好的文章

    源码,经过修改,可以得到版本。当我们使用git的时候,我们需要把注意力,或者说,关注点放在修改上,而不是修改之后的版本。

    就好像装修房子,每添置一件家具都是一个修改:床、沙发、餐桌、衣柜、书架。

    假设说这五件家具都买齐后,我们可以得到一个装修完毕之后的版本。

    家具的添置,是有顺序的,假设便是床、沙发、餐桌、衣柜、书架这么顺序;那么如果我们以“版本”为单位去思考的话,便会有五个版本:

    • 床、
    • 床、沙发
    • 床、沙发、餐桌
    • 床、沙发、餐桌、衣柜
    • 床、沙发、餐桌、衣柜、书架

    而如果以修改为单位去思考的话,便会有五个修改:

    • 沙发
    • 餐桌
    • 衣柜
    • 书架

    我们往往可以方便调整修改的顺序、个数,以达到不同的修改组合-版本。

    比方说,我们要一个只有沙发跟书架的“版本”,那么开一个新的分支,引入:

    • 沙发
    • 书架

    两个修改就好了。

    而如果我们是用“版本”去思考,那么是很难(仅仅是“很难”,不是不可能)得出新的“版本组合”的。

    这便是“面向修改思考”得到的便利。

    git是源码管理工具,而git(以及hg等)认为,管理修改,要比管理版本灵活、便利、强大得多。

    很多习惯svn的思维工程师,便是在这点绕不过来,他们总是习惯性的去想“发布哪个版本?”,而不是发布“包含哪些修改的分支?”。

    要看使用的是何种思维,可以看看平时讨论的时候,是提到分支比较多,还是提到版本比较多。

    历史 vs 管理

    git是源码管理工具。源码,是需要工具来管理。

    有管理的源码,跟没管理的源码,有什么区别?处女座会说,区别很大

    软件的源码,需要有整理、规范的进行变更,它的修改历史,应该是清晰的。

    今天加个功能A、B、C,明天发布了版本1.4,后天做了bugfix x/y/z等等,整个过程都应该有规范的记录。

    所有的提交,都应该是有“分支”,分支的使用可以参考gitflow

    分支内,比方说实现某个新功能的feature 分支,内部可以有多个步骤,这个步骤先整理代码,那个步骤再实现功能,然后再添加配置等等等等。

    所有的提交,都应该是“原子提交”:包含并且仅包含某个该步骤应有的所有操作。

    这样可以使源码的演变变得非常便于管理,非常容易追溯bug,查阅某段代码是什么时候因为何故被添加。

    关键在于,工程师开发的时候,肯定不是严格照着这样规范的方式编写代码。

    我们经常是在写一段代码的时候,发现还有别的地方可以改一改,然后就顺手改了。

    代码的真实修改历史,必然是杂乱无章的。

    SVN的设计哲学是认为,代码修改历史是神圣的,源码管理工具必须永远真实的把全部修改历史都记录下来;它的任务是记录历史,杜绝一切历史被篡改的可能。

    git则认为,历史是任人打扮的姑娘;只要历史能变得漂亮,要怎么改都行!所以,git会提供各种个样的命令,方便工程师把代码变更历史变成我们想要的样子。

    gitflow里面描述的开发流程,看起来很美,但那往往不是真实发生的修改流程;但是,git会提供命令,方便我们把代码变更修改成为gitflow所描述的那样。

    然后,代码变更历史,就会有一个个feature / release / hotfix等等,非常清晰,明了,便于追溯、管理。

    漏提交了文件,提交不是原子的怎么办? git commit --amend

    修改的顺序不对怎么办? git rebase -i

    曾经有两个项目,开始的时候是独立的,git仓库也是独立的,但后来(一年多后)慢慢变成一个。

    类似于我们做代码重构,两个原先独立的类耦合度越来越高,重构时可以合并成为一个类会更简单。

    把其中一个代码仓库做为一个子目录合并到另一个仓库中,然后,使用git filter-branch,修改该子目录下的所有提交历史,让它看起来就好像从一开始就在该路径下一样。

    然后,我们得到了有两个修改起点的git仓库。

    git对源码变更历史的修改能力可以达到这样。

    有的人对源码的提交,分支的管理都处理得很随意,他们关心的仅仅是代码最终的版本是怎么样的,而不关心代码是如何变成它现在的样子;源码管理工具,在他们手上,仅仅是“源码备份工具”;copy & paste目录就好了呀,为什么还要使用git?为什么还要关心能否使用git bisect来快速定位bug?

    分布式 vs 快

    讲了这么多,我还完全没有提到git所谓的“分布式”概念,因为在我看来,git是否是分布式与否,并不是关键,“分布式”仅仅是一个实现细节,本地可以包含整个仓库,可以在本地完成所有的git操作,这样所有的git操作都可以很快。

    操作很快才是目的,而“分布式”是为了达到这个目的而采取的实现细节,如果远程操作可以比本地操作更快,那么,我认为git也完全可以是集中式的。

    按我的理解,"快"才是git的设计理念。Linus说,他刻意追求让git开新分支这个操作变得无比快(只要写入41个字节),因为只有一个操作无比的快,人们才有可能频繁的是使用它。分支操作无比快,工程师才会使用基于分支的开发。

    hg在很多地方都跟git很像,但是hg不够快。

    在windows上使用sourcetree去操作git,很慢,开个分支都要等,这怎么能忍呢?

    相关文章

      网友评论

          本文标题:我对git的理解

          本文链接:https://www.haomeiwen.com/subject/pgiedttx.html