当前位置: 首页 > 科技观察

Git全功能介绍

时间:2023-03-11 22:06:42 科技观察

Git的历史与现状Git是Linux作者Linus的另一部作品。2002年,他还在使用Bitkeeper作为Linux内核的版本管理,但因为是版权软件而受到质疑,随后AndrewTridgell对Bitkeeper进行了逆向工程,导致BitMover收回了Linux开发者免费使用Bitkeeper的权利。Linus一怒之下花了10天时间编写Git。名字的意思是:自负的混蛋现在Git已经成为大多数开发者的选择,由TomPreston-Werner、ChrisWanstrath和PJHyett于2007年10月推出的Github已经成为全球最大的开发者网站,我厂在上面也贡献良多.更何况一向自造轮子的微软,也有意将庞大的300GWindows源代码迁移到Git中管理。他们为Git提供了新的GVFS实现,有效提升了Git对庞大代码库的支持性能。微软将把windows源码迁移到git另外:Docker的二进制镜像管理也是基于git实现的。集中式版本管理和分布式版本管理Git和SVN是设计理念不同的版本工具。SVN集中代码管理,具有更好的稳定性和安全性,而分散式Git是从Linux操作系统的开发需求出发,是一个更适合多人协作的开源项目。它可以使用任何点作为远程将其代码与本地代码合并。随着时间的发展,衍生出更加强大的功能和一整套的操作流程,使其适用于商业软件的开发。Central和distribution的区别Git和SVN代码历史SVN的代码历史比较简单,因为是中心化的,每个人的代码都是直接提交到某个repository,所以它的ReversionID号是一个按顺序递增的数字类型,在一般而言,两个数字之间不能插入其他反转。SVNHistoryGit看起来更混乱。它的ReversionID号是一个40位的哈希值,通常可以缩写为7位。之所以会这样,是因为Git的最小单位是代码修改历史,就是Patch,而branch、Tag、Remote(一会儿会讲到这些概念)等只是branches的集合,这可以随意拆分和合并。我更愿意把branches、Tags、Remotes看成是不同的平行宇宙,因为有些机会导致分裂,导致不同的历史,或者因为一些机会,它们可能融合在一起,变得更强大。Git历史Git基本命令Git场景Git根据场景可分为以下几种场景(Scence):Workspace:当前工作空间,修改的初始状态。Staging:修改后加入缓存状态准备提交。本地仓库:本地代码仓库,只对自己的代码生效。这也是与svn的区别之一。svncommit后,直接提交到远程服务器。gitcommit后,只是提交到本地代码库。Remoterepository:远程代码库,将您本地的代码库同步到远程代码库,方便其他开发者共享成果。具体过程见图。这里简单介绍几个常用的命令。PS:图中没有提到rebase和cherry-pick命令。这两个命令也很强大。后面会提到,大家有时间可以关注一下。前面提到patchdiff,patch是Git/SVN代码版本管理的基本概念。它实际上是以行为单位的文件修改历史。添加行以+号开头,删除行以-号开头,修改行是先-再+。在Git中,可以使用gitdiff或者Linux/Mac/Conemu,也可以使用diff-Naur来生成文件比较结果,有点类似于下图。这是整个代码管理的基本概念,所有的branch、tag、remotes都是在这个基础上衍生出来的。gitdiff基本流程1.将代码克隆到本地开发环境——clone$gitclone[REPOSITORY_URL]对应svncheckout命令,用于将远程代码克隆到本地。和svn一样,REPOSITORY_URL的协议非常灵活。以前流行用ssh/scp协议,现在https/http协议越来越流行。2.更新代码-Status/Commit/Log刚才提到了Git的四种场景,前两种场景需要通过$gitstatus命令查看,代码刚刚创建,可以看到Untrackedfiles(Workspace)状态,执行add后,变成Changestobecommitted(Stage)状态,Stage中的文件被修改,会再次变成Changesnotstagedforcommit状态。commit执行后,从Stage转移到Localrepository,代码提交可以通过$gitlog查看。3.Branch和Tag前面提到,Branch和Tag都可以看作是一个定时的patch集合。分支可以相互合并。克隆仓库后,有一个名为master的主线分支。而Tag用于标记发布后的版本。这两者只是名称不同,功能(我感觉在实现上)相差不大。与SVN不同的是,SVN的Branch和Tag都复制了整个trunk的代码库。Git只是将补丁引用重新应用到当前代码中,所以Git的Branch/Tag非常轻量级且易于切换。使用Git需要尽可能的使用它的分支来提高开发效率。后面提到Gitflow时,我会介绍如何使用分支进行代码功能开发管理。3.1创建新分支的两种方式$gitcheckout-b[BRANCH_NAME]#在当前版本切换并创建新分支$gitbranch[BRANCH_NAME]#直接创建新分支3.2切换分支$gitcheckout[BRANCH_NAME]3.3二合并分支的方法$gitmerge[BRANCH_NAME]#将另一个分支的代码放在当前分支之后。$gitrebase[BRANCH_NAME]#不推荐,对比代码,将本分支的修改代码rebase到另一个分支。通常情况下,不推荐使用,因为下游分支rebase后,会从上游分支合并丢失分支合并的commit,但是对于一些有历史恐惧症的人来说,它是保持代码提交历史的神器干净,将http://git.code.oa.com/xxx的分支'xxx'合并到yyy提交看起来也很讨厌。对于已经push到远程仓库的commit,不推荐rebase,因为一旦rebase了,别人pull的时候就会有很多冲突,基本没法修复。通常,建议使用merge更安全。PS:rebase还有一个强大的功能就是配合--interactive参数修改之前的patch,自己查,但是修改之后push--force,难免被别人拉回造成冲突,但是这个trick是修改Github网站上Pullrequest(后面会提到)的必备技巧。3.4删除分支$gitbranch-d[BRANCH_NAME]#已经合并到master$gitbranch-D[BRANCH_NAME]#这个分支还没有合并到master,强行删除PS:即使你删除了一个分支等,可以用gitreflogs找回哦3.5Unmodifygitstash#取消所有修改,很厉害可以恢复,自己查看gitreset--soft[REV]#保留修改的内容,从Localrepository撤消,也可以用来回滚历史gitreset--hard[REV]#丢弃修改的内容,从本地仓库撤消,也可以用来回滚历史push本地代码到远程仓库来push代码和别人合作,命令行很简单$gitpush[REMOTE][BRANCH]remote默认为origin,不填就推给它,branch默认为当前分支,其实就是它可以省略,如果添加,指定的分支将被推送到远程。如果要推送本地特性分支,建议在推送后加上--set-upstream参数。郑重警告:永远不要在主线的master分支上执行--force获取远程分支更新$gitpull#更新代码到工作区$gitfetch#更新代码到本地仓库,可能需要再次合并到工作区通过合并。远程仓库Clone后,默认会有一个远程仓库作为origin,但是如果要添加其他远程仓库,需要使用如下命令:$gitremoteadd[REMOTE_NAME][URL]#添加原始仓库$gitfetch[REMOTE_NAME]#获取远程仓库更新$gitbranch-a#查看包括远程仓库在内的所有分支$gitpush[REMOTE_NAME][BRANCH_NAME]#推送到远程仓库GithubPullRequest&GitlabMergeRequestGithub基于GitRemote方便大家参与开源项目,衍生出一套机制。目前常规开源项目的参与流程是先注册一个Github账号,然后将自己感兴趣的开源项目fork一份到自己的namespace中,然后拆分分支进行修改。然后提交到自己的Github仓库,然后发起PullRequest让项目维护者合并你的代码(Pullrequest名副其实)。在此过程中,项目维护者将审查和评论您的代码。你必须按照维护者的要求进行修改(这里会经常用到rebase),修改通过,维护者同意后,他会将代码合并到项目中。具体过程大家自己走一走就可以了解了。Gitlab的MergeRequest的原理完全一样。PS:样图从PPT第22页开始。Git流程Git流程应该是本文的重点。它基于Git分支实现了一套简单的功能模块化开发流程。主要思想是把分支分成上下游几个层次,然后通过一套命令行工具来维护。master分支——与线上版本一致,线上出现问题时可以轻松修复。develop分支——功能开发的基线分支,功能开发完成后合并到其中。所有功能开发完成后,测试上线,然后合并回master。feature/*特性开发分支——从develop中分离出来,需要随时将develop的更新合并回来,与上游分支保持一致。功能开发完成后,可以合并到develop中。通过与上游分支保持一致,可以避免误删别人的代码。所有的代码冲突都必须在下游分支修复,测试完成后才能合并到上游分支。hotfix/*hotfixbranch-主要用于在线bug修复,但修复后要同时合并到master和develop分支。Gitflow和gitflow提供了一组命令行工具来更容易地做这些代码合并的事情。$gitflowinit#初始化gitflow分支模型$gitflowfeaturestart[NAME]#启动一个功能分支$gitflowfeaturefinish[NAME]#将功能分支合并到develop$gitflowhotfixstart[NAME]#启动一个hotfixFixbranch$gitflowhotfixfinish[NAME]#将patch合并到develop和master$gitflowrelease[NAME]#发布一个新版本,打上标签感觉Gitflow有个长,我会详细解释下次。如果你对其他内容感兴趣,可以继续阅读其他相关内容,很有意思:gitsvn-Git可以使用svn作为代码后端,使用Giit来管理SVN中代码的版本。gitreflogs-参考记录,不用怕在git中不小心删除了一个commit,只要commit了,就可以通过reflogs找到,用reset或者cherrypick恢复。gitcherrypick-挑选一颗樱桃(提交),单独从另一个分支挑选一个补丁。gitbarerepository-搭建一个Gitservergitsubmodule-submodule,一个大项目可以通过submodule进行拆分,随时可以进行submodule的版本更新和回溯。githooks-Hooks,当git对仓库有一定的行为时,可以通过hooks触发一些行为,比如Github上的一些第三方持续集成服务,就是在这个基础上实现的。gitsignature-signature,commit时通过gpg对patch进行签名,证明patch确实是自己提交的,可以参考Github的文档。SourceTree-SourceTree是一个跨平台的Git图形界面,简单方便。我目前主要用它来做基础的Patch阅读,比命令行舒服多了。