Git学习笔记 – 概念篇

http://hedatou.com/archives/git_learning_journal_concept.html

什么是Git?

Git是由Linus Torvalds开发的一套版本管理系统。传统的CVS、SVN属于集中式版本管理系统,依赖于一个中心服务器,而Git是一个分布式版本管理系统,每个使用者都有一套完整的修订历史记录,每台机器都是一个独立的节点,不依赖于其他节点就可以进行离线提交、离线查看文件修改记录。而且Git提供了一套完善的分支/合并系统,速度快、不依赖网络,开发中使用起来非常方便。

为什么使用Git?

枯燥的理论不好理解,我就说一些工作中出现的实际使用场景,再和SVN对比一下。

1.完善的离线机制

最近在做的这个项目中,就发生了这样的状况,公司的SVN因为网络问题挂掉了,团队中无法共享代码,只能在QQ上把代码传来传去,我连想查看一下文件的修改历史记录都不能,因为这些信息都保存在服务器上。做完一个功能的修改,我想对比一下我这次都修改了哪些文件、哪些内容,也不可以,因为对比功能也依赖于服务器。

使用Git就可以避免这个问题,每个人都保存着这个项目自创建开始至今的完整记录,所以查看修改历史、对比修改内容,这都不是问题。而且Git也可以使用点对点的版本管理,当中心服务器不可用时,可以直接和同事的Git点对点通信,共享代码、合并分支。比如,你可以对同事说:“我已经把BUG #4037修改好了,在我本地的bug4037分支上,地址是:git://192.168.0.10/project.git”,然后局域网内的同事可以直接把我的bug4037分支pull到他的本地,做一些修改,再重新push到我这里。其实Git还是鼓励有一个中心服务器来作为整体协调的媒介,不过当中心服务器临时不可用时,依然不会影响开发进程。SVN就不行了,中心服务器一挂,几乎就是啥都干不了了。

2.本地修改、离线提交

使用SVN时,团队内肯定都有这样的约定,只有可运行的代码才能上传SVN,不然别人下载代码回来发现跑不起来就不好了。但是这样就造成了提交代码的粒度太大,比如说我要修改一个功能,横跨多个模块,而且耗时非常长,可能需要两天时间,为了降低风险,我需要每修改一个独立模块就保存、提交一次,但仅仅这一个模块的修改,不能独立的使整个项目跑起来。这个情景SVN就没有办法了,细粒度和可用上传是矛盾的。

SVN的层级只有两级:客户端工作区和服务端归档区。使用Git就可以解决这个问题,因为Git有三级:本地工作区、本地归档区和远程归档区(还有个暂存区先不谈,其实是四级)。本地可以多次提交,只提交到本地归档区,不影响中心服务器。而当所有任务全部完成,把本地归档区和远程归档区同步时,可以把本地的多次修订记录一起同步到服务器归档。这样既保证了提交单元的细粒度,又保证了服务器版本的一致性。

3.分支/合并

工作中经常发生这样的情况,正在埋头写一个模块功能,突然测试报了一个紧急BUG,必须放下手里的工作优先修改。如果是小问题,只涉及一两个文件还好,但如果你正在做的工作和BUG修改都涉及到十几、二十个文件,就该乱套了。更甚者如果两者在某些文件上交叉,则更是乱上加乱。

处理这个问题应该用分支来处理,每个独立的修改主题应该在不同的分支上来进行,新特性就在新特性分支上,BUG修改就在BUG修改分支上,彼此互不影响,都完成了再合并。其实SVN也有分支/合并,不过相对来说重量级点,一个分支就是一个新的目录,更适合一整个团队切入进来。而Git的分支就轻量多了,随手就开一个分支,做一些修改再合并回去,Git所有分支都在同一个文件夹内。Git实现的非常像一个文件系统,对同一个文件夹,根据版本号回滚或前进到某一时刻。另外Git还有一个非常可爱的命令:git stash,可以把手头的工作储藏到一个临时区,恢复到上一个版本,之后可以用git stash apply再还原回来。

4.冗余目录(.svn、.git)

这个就不是什么大问题了,不过对于完美主义者来说,SVN管理下的项目中,每个文件夹、子文件夹下都有个.svn文件夹,真的挺烦的……

Git也有元数据文件夹,但只在根目录下有一个,这要好很多了,部署代码时用不着递归下去挨个子文件夹删了。

5.开源项目中贡献代码

建立在SVN上的开源项目,可以是由发起人和若干提交者来共同维护代码,这些人都拥有读写权限,而匿名用户当然只有读权限没有写权限。如果匿名用户发现了代码中的BUG,或是有一些好点子,想贡献一些代码,那个流程是非常麻烦的,比如说email一下diff、patch什么的,还要看项目人员有没有采纳,没有一个系统内建的机制来方便陌生人贡献代码。

GitHub是一个基于Git的代码托管服务,它有一套完善的Fork+Pull Request机制。比如说我想为jQuery贡献代码,就可以在jQuery的主页上点击Fork按钮,这样我的仓库里就有了一份jQuery的分支,而我是它的主人,自然有完全的读写权限,我可以做一些BUG修改和新特性开发。然后我可以在我的主页点击Pull Request,向原作者发起一次请求。原作者看到这条请求后,就有了我的项目Git访问地址,他可以把我的修改Pull到他的项目中,合并到主分支中,这样就完成了一次代码贡献。

Git有什么缺点吗?

1.Windows

Git是举着开源大旗的Linus Torvalds开发的,只有Linux、Mac OS版本,Windows版本没有开发计划,现在没有以后估计也不会有……不过有个项目msysGit,是志愿者基于MinGW搭建的Windows系统下的Git,Windows环境下也可以用Git了

2.权限管理

同样因为Git是举着开源大旗的Linus Torvalds开发的,用Git管理的工程任何人只要知道URL就可以获取源代码,拒绝封闭是开源运动的原教旨嘛~公司开发带有版权的私有代码,在内网还无所谓,外网就不方便用Git来管理了……

3.团队中推广

大家都习惯了CVS、SVN这种集中式版本管理,要转变开发方式为基于分支/合并的模式,一级提交变为两级提交,推广起来应该不是很容易的。不过这是项目管理者需要操心的,对于程序员个体来说,这不是问题,而且Git中有个git-svn,相当于可以在本地使用Git,享受一切由Git带来的本地修订管理的好处,然后提交到团队中的SVN中心服务器,这个特性非常实用。

Git基础

1.初始化工程:git clone url ,相当于SVN的checkout,第一次参与项目都要用到。git init,把当前目录初始化为Git仓库,通常是管理员来进行这个操作。

2.获取最新修改:git pull ,相当于SVN的update。不过有一点区别,SVN只有远程和本地两个层级,update就直接合并代码了,而Git有四级:remote repo、local repo、cached area和working area,pull操作只是把remote repo中的最新修改抓取到local repo,但没有合并代码,只不过origin/master分支指针指向到了最新修订版本,而本地master分支指针指向的版本没有变,仍然和pull前一样。

3.纳入管理:git add file ,新建文件、初始化工程时都要用到这个,可以把文件从working area纳入到cached area中,working area就是我们平时所用的、没有任何版本管理的文件系统,cached area就是暂存区,表示已经纳入到Git的管理中了,但还没有提交,cached area会有一个SHA-1 id。git add还有多个含义,比较容易混淆,另外在解决冲突时用来标记resolved也是用它,这些暂且不提。working area可以分为两个概念:untracked和unstaged,分别是未纳入Git管理的和已纳入Git管理但未纳入到暂存区的文件,同样需要git add添加到cached area中。

4.提交:git commit ,会把cached area中的文件赋予一个commit id,放到local repo中去。local repo中都是已经提交的变更,各个分支以树形结构存储索引信息。每次commit必须有注释,否则不让提交~ :)   可以加-a选项,则可以省去git add把文件放入暂存区的步骤,直接提交到local repo中。

5.查询变化:git diff ,会标出修改了哪些行,还可以对比特定的版本号、文件、目录。

6.查看摘要:git status ,查看有哪些文件未纳入管理,未暂存的文件有哪些变更,已暂存的文件有哪些变更,当前正在哪个分支工作。

7.还原:git chechout file ,相当于SVN的revert,使用仓库版本替换此文件。

8.查看历史:git log ,列出提交历史的id、作者、日期、注释。有了commit id,就可以用git show id来查看相应提交的详细修改内容。commit id都是40字节的SHA-1,谁也不可能记住一长串的id,Git比较智能,你只要输入前几位(至少4位)即可,只要能确保唯一就行。git checkout id ,切换到指定版本。

9.分支:git branch name ,创建一个分支,git checkout name ,切换到指定分支。

10.合并:git merge branch ,把指定分支合并到当前分支。根据当前代码修订状态,合并可以分为两种:Fast Forward合并和Three Way合并,前者是单一父节点,故不会有冲突的问题,后者是双父节点合并,当两者修改同一行代码时会有冲突,Git会报告,没有冲突会自动合并,并自动产生一个新的提交用来表示当前状态。

分支/合并是Git的核心概念,后面会专门谈这个话题。

11.提交到中心服务器:git push ,如果本地Git工程是通过git clone url 命令下载回来的,则远程地址默认已经设置好,直接执行git push就把本地库推送到中心服务器,在这之前应该首先git pull把最新版本拉取到本地,并完成合并,否则push时会报冲突,拒绝推送。

分支/合并

先来说,什么是分支?分支就是一个指向某个commit id的指针。打个比方来说,Git就是一个时光机器,而commit id就好像某个时间点,分支就好像某几个关键时间点的时间隧道驿站。我们可以乘坐Git这部时光机器把整个项目目录还原到任意一个时间点,多个平行分支就好像是平行宇宙,在各自的时空发生不同的事情,彼此互不影响,而且两个平行宇宙(A和B)还可以合并,合并之后生成了一个新的时空(C),在C中回忆历史会发现A和B中曾经发生的故事在C中也都曾发生过。如果一个人在A宇宙和B宇宙做了一件互相矛盾的事情,那在合并时就会发生冲突,就必须由上帝介入来干涉一下,手动处理掉这个冲突。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值