一、GIT由来
Git是目前世界上最先进的分布式版本控制系统。
Linus创建了Linux,Linux的壮大是靠全世界热心的志愿者参与的。世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码! 时间到了2002年,Linux系统已经发展了十年,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper(专有的分布式版本BitKeeper 的权BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。
安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的 Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错),于是BitMover公司怒了,要收回Linux社区的免费使用权,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 。
Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。 他们对新的系统制订了若干目标:
- 速度很快
- 设计简单
- 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
- 完全分布式
- 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git诞生!一个月之内,Linux系统的源码已经由Git管理了!
Git迅速成为最流行的分布式版本控制系统。尤其是2008年,GitHub网站上线。它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。 自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统
二、GIT与SVN
GIT | SVN | |
概念 | Git是分布式版本控制系统,那么它就没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们两之间只需把各自的修改推送给对方,就可以互相看到对方的修改了 | SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了。 |
差异 | 1. SVN是集中式版本控制系统,Git是分布式版本控制系统; 2. SVN记录差异比较,Git是对新版本直接做快照; 3. SVN的提交会出现冲突的概率随着同一时间工作人数的增加而增加,Git鼓励多建分支使得冲突几率减小,且冲突解决机制更好 4. SVN可以通过权限控制使得部分代码的安全性,Git 则是完全clone整个仓库到本地,任何人均可以访问任何部分的代码 | |
优点 | 1、适合分布式开发,强调个体。 2、公共服务器压力和数据量都不会太大。 3、速度快、灵活。 4、任意两个开发者之间可以很容易的解决冲突。 5、离线工作 | 1、 管理方便,逻辑明确,符合一般人思维习惯。 2、 易于管理,集中式服务器更能保证安全性。 3、 代码一致性非常高。 4、 适合开发人数不多的项目开发 |
缺点 | 1、学习周期相对而言比较长。 2、不符合常规思维。 3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息 | 1、 服务器压力太大,数据库容量暴增。 2、 如果不能连接到服务器上,基本上不可以工作,看上面第二步,如果服务器不能连接上,就不能提交,还原,对比等等。 3、 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题 |
三、git原理
Git 把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 有三种状态,你的文件可能处于其中之一: 已提交(committed):表示数据已经安全的保存在本地数据库中。 已修改(modified): 表示修改了文件,但还没保存到数据库中。 已暂存(staged): 表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。 由此引入 Git 项目的三个工作区域的概念 Repository:仓库区(或本地仓库),Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部 分,从其它计算机克隆仓库时,拷贝的就是这里的数据。 Workspace:工作区工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁 盘上供你使用或修改。 Index / Stage:暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作‘索引’,不过一 般说法还是叫暂存区域。 基本的 Git 工作流程如下:
如果 Git 目录中保存着的特定版本文件,就属于已提交状态。 如果作了修改并已放入暂存区域,就属于已暂存状态。 如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。 Repository(仓库)包含的内容 - Git的目标是管理一个工程,或者说是一些文件的集合,以跟踪它们的变化。Git使用Repository来存储这些信息。一个仓库主要包含以下内容(也包括其他内容):
|
四、GIT操作命令
创建版本库,英文名 repository。 选择一个合适的地方,创建一个空目录。通过 git init 或者git init –-bare命令把这个目录变成 Git 可以管理的仓库(初始化仓库)。 初始化之后目录下面的.git目录外是工作区,.git目录里分为暂存区和Git为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫做 HEAD;图片、视频、Word文档这些二进制文件可以由版本控制系统管理,但没办法跟踪文件的变化,只能知道图片从100KB改成了120KB,但改了什么版本控制系统不知道。 | |
git init和git init –-bare区别: git init 是多一个.git 文件夹,而git所有的文件都是.git文件夹下,而git init –bare 则是将git的文件直接放在仓库根目录下。 而git init 创建的普通仓库,里面是有项目源文件的。所以git init 创建的普通仓库是有工作空间的,就是work-tree ,而git init –bare是没有工作空间的。 这里还要注意,我们一般使用git init –bare 比较好,git init 有两点不好: 1.因为使用git init 创建的仓库是可以用git操作的嘛,如果当前master正在被用户操作,那么分支如果 git push master:master 那么就会 爆炸,上传不上去。master不能同时被两个人操作,对吧。 2.分支push到远程仓库之后,我们在仓库里是没有办法看到最新的内容的,必须要 git reset --hard 在用git init 创建的仓库的时候,你git push 会遇到 ! [remote rejected] master -> master (branch is currently checked out)** 需要运行git config receive.denycurrentbranch ignore这个是允许接受远程文件。有时候push不上去,是因为文件夹没有权限,需要chomd 7777 文件 | |
把文件往 Git 版本库里面添加的时候,是分两步执行的: 1.用 git add 把文件添加进去,实际上就是把文件添加到暂存区; 注:因为我们创建 Git 版本库时候,Git 自动为我们创建了唯一一个 master 分支,所以,现在, git commit 就是往 master 分支上提交 更改 常用commit提交注释规范 | |
查看仓库当前的状态 | git status |
查看文件差异,可以看到工作区和暂存区的区别 | git diff readme.txt |
比较的是暂存区和历史区的差异 | git diff --cached |
可以查看工作区和版本库里面的区别 | git diff head – readme.txt |
可以查看所有提交的比较详细的历史纪录 | git log --pretty=oneline git log --graph --pretty=oneline |
为当前版本打标签 为历史版本打标签 指定标签说明 查看所有标签 查看某一标签 删除某一标签 | git tag 标签名 git tag 标签名 该版本ID git tag –a 标签名 –m "标签说明" [可选:版本ID] git tag git show 标签名 git tag –d 标签名 |
撤销暂存区的修改 | git reset HEAD 文件名 |
可以回退版本,把暂存区的修改退回到工作区 在 git 中,用 HEAD 表示当前版本,上一个版本就是 HEAD^ ,上上个版本就是 HEAD^^ ,往前一百个版本为 HEAD~100。
| 回到上一个版本为 git reset --hard “HEAD^” (实测不区分大小写) 假如知道版本号,回到某一个版本为 git reset --hard 126378(版本号,写前几位就行) |
记录了你之前操作的每一次命令,可以查看版本号,知道了版本号就可以随意回退版本了 | git reflog |
可以丢弃工作区的修改,这里有两种情况: | git checkout – readme.txt 没有 – ,就变成了切换到另一个分支 |
查看远程分支,这条命令并没有每一次都从远程更新仓库信息,这样子做是为了效率,我们可以手动更新一下远程分支 | git fetch origin //更新远程仓库 git branch -a //查看远程分支 |
拉取远程分支、并创建本地分支,使用该方式会在本地新建分支x,并自动切换到该本地分支x | git checkout -b 本地分支XXX origin/远程分支XXX git checkout -b test origin/test //将远程的分支 test 拉取到本地 test 分支,并且切换到本地 test 分支 |
拉取远程分支、并创建本地分支,使用该方式会在本地新建分支x,但是不会自动切换到该本地分支x,需要手动checkout | git fetch origin 远程分支XXX:本地分支XXX git fetch origin test:test //将远程的分支 test 拉取到本地 test分支,但是不会自动切换到本地的 test 分支 |
添加远程仓库 | git remote add origin git@192.168.0.1/test.git |
把本地库的所有内容推送到远程仓库上,由于远程仓库是空的,我们第一次推送的 master 分支时候,加上了 -u 参数,git 不但会把本地的 master 分支推送到远程新的 master 分支,还会把本地的 master分支和远程的 master 分支关联起来,在以后的推送或者拉取的时候可以简化命令。 | git push -u origin master |
克隆一个仓库 Git 支持多种协议,包括 https ,但是通过 ssh 支持的原生 git 协议最快。默认的 git:// 使用 ssh,但也可以使用 https 等其他协议。使用 https 除了速度慢以外,还有个最大的麻烦就是每次推送必须输入口令,只是在某些只开放 http 端口的公司内部就无法使用 ssh 协议而只能用 https | git clone git@192.168.0.1/test.git |
创建与合并分支 | git checkout -b dev git checkout 命令上加 -b 参数表示创建并且切换,相当于下面两条命令:
|
查看当前所在分支 ,该命令会列出所有分支,并且在当前的分支前面加 * | git branch |
用于合并指定分支到当前分支 | git merge dev 将 dev 分支合并到当前的 merge 分支上 git merge --abort //将刚才合并操作撤销 |
合并之后,可以放心删除 dev 分支 | git branch -d dev |
强制合并,禁用快速合并
| git merge --no-ff -m |
删除暂存区,使用--cached 表示只删除缓存区中的内容 | git rm -r --cached . |
按照上述方法定义后发现并未生效,原因是 .gitignore 只能忽略那些原来没有被 track 的文件,如果某些文件已经被纳入了版本管理中,则修改 .gitignore 是无效的 |
git add . git commit -m 'update .gitignore' |
对文件重命名 | git mv README.txt README |
Git提供了一个stash功能,可以把当前工作现场 ”隐藏起来”,等以后恢复现场后继续工作 | git stash apply恢复,恢复后,stash内容并不删除,你需要使用命令git stash drop来删除 git stash pop,恢复的同时把stash内容也删除了删除list里的储藏内容记录
|
查看远程库的信息 查看远程库的详细信息 | git remote git remote -v |
获取当前登录的用户 | git config --global user.name |
获取当前登录用户的邮箱 | git config --global user.email |
查看git的版本信息 | git --version |
设置git账户,userName为你的git账号 | git config --global user.name 'userName' |